diff --git a/.vpython3 b/.vpython3
index 34c97a0..d13f2d1 100644
--- a/.vpython3
+++ b/.vpython3
@@ -236,7 +236,7 @@
 >
 wheel: <
   name: "infra/python/wheels/cffi/${vpython_platform}"
-  version: "version:1.14.5"
+  version: "version:1.14.5.chromium.4"
 >
 wheel: <
   name: "infra/python/wheels/pycparser-py2_py3"
diff --git a/DEPS b/DEPS
index e78a5b10..e51199f 100644
--- a/DEPS
+++ b/DEPS
@@ -234,23 +234,23 @@
   # 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': '62392f624f39b798b39587fb07380544868c0b31',
+  'skia_revision': '647bd84de7cc6eafcaebe1053de3b85a3ee36193',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'd560628484c98a76654b101b69dcdad319c64bdb',
+  'v8_revision': 'a299e86f9feb9075105d7a7da4c40bd6f47c8faa',
   # 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': '9e4ade6898fbb19dc8fb2a089450304ee0d14b25',
+  'angle_revision': '135362c9ce1773edaf961ff43cdfe34f7d31da49',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'f5cf2d08ff9c05779fbd48de0e6b7088965f2955',
+  'swiftshader_revision': '6e23c082b73a952d36c0cdb2f33f597166674f6d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '15c1e6ae5cf2cd2ca02b0a530fdb85e106ab4781',
+  'pdfium_revision': '31883270b7eea64726d4e233c83333bc88c72c27',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -277,11 +277,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': 'a5f1a96618b45426f64877d5bd77721df29c92c9',
+  'nacl_revision': '5ea7f18df797eb055c2b0efcb0637a82ca0eba84',
   # 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': '9079c5d91aa87bcae223fc933b9c0ebf346b7d64',
+  'freetype_revision': '81912a1385e8fc7694eda820221e15745cdcada4',
   # 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 catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '153af62da5446071d6f21925f79aedbc0a08fffd',
+  'catapult_revision': '8a112e2bdf2b5839f07c820e255d78c835b0fd62',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -309,7 +309,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': '603acd4972dca83da2b04ff84633503d3cff7533',
+  'devtools_frontend_revision': 'e26874754697c23e24fc15433a0b853413f2b321',
   # 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.
@@ -349,7 +349,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'fd066a33451a79a91829d915cb07d1dfaf579aaf',
+  'dawn_revision': '3d9e331ef83a8813cd50acbd831d0df96f827118',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -365,7 +365,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling wuffs
   # and whatever else without interference from each other.
-  'wuffs_revision': 'c9d2ed7983381ab659a56e0b8bc0d077e421f697',
+  'wuffs_revision': 'a0e2454f0c21369f9775cad3bcaf1e3bb1db70b6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libgifcodec
   # and whatever else without interference from each other.
@@ -393,7 +393,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libcxxabi_revision':    'a63bbc1389aaabc536f7076853661eab3e08d362',
+  'libcxxabi_revision':    'e504863f9e2d6e6f32c4c6f06545bf9626308145',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -627,7 +627,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '6ae6c2edacaceb6ae459de19415488d6a12db16a',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '108f768308391bb70b7222bd9faeb4399fd231ab',
       'condition': 'checkout_ios',
   },
 
@@ -708,7 +708,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/linux-amd64',
-          'version': 'vRDCgkbDxqraWrSljn0QG8n6WJcTuo_Vj4xWdUK8trEC',
+          'version': 'gJBAEYiywu0o-EEwn7UpwifzCyC4Rii5lIAO9w3vM5IC',
         },
       ],
       'dep_type': 'cipd',
@@ -719,7 +719,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/mac-amd64',
-          'version': 'jwA0c9pdXhf8AtWfs_ynaR9GAHvbM4DR_y9ugZ0qZ6IC',
+          'version': 'Y30Ib8gHQhcNop8Fl4wQC5J7l6NFymKZNLE6ztsf1PgC',
         },
       ],
       'dep_type': 'cipd',
@@ -730,7 +730,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/windows-amd64',
-          'version': 'SXLNYpoHgJoHGvReZzxxTWAAmC7J5p35lpT9UHefnb4C',
+          'version': 'raTuwcc-vtXLaNKG7DXvx10nm9P-TUlL6TkY9cV7YOwC',
         },
       ],
       'dep_type': 'cipd',
@@ -791,7 +791,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'ZLK16MyL6-u2bhLeLaelNDvoSpFO9qRUiGse469qKRAC',
+          'version': 'wgGrIASbzI25xEdOD1slUhYwmBa_FcdH498LBPPTwBgC',
       },
     ],
     'condition': 'checkout_android',
@@ -1010,7 +1010,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' + '@' + '77674d73d308373d51ce330ced5d08b55277d6b3',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '0de06d4d0383c77ddd675f01feb596ce9f7deb83',
       'condition': 'checkout_chromeos',
   },
 
@@ -1413,7 +1413,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '514e743cbfd9ae549cb95d9c43a0a3bc1b188883',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '03cb3fd2f9c1b7475bf3838ecdf014b786b791f3',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1634,7 +1634,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '5e8ac4959f931fcffb7d0d97b82b22ba0db6258e',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'a83f874d03327b833bf63debac0c47bf2ffa0b4b',
+    Var('webrtc_git') + '/src.git' + '@' + '984cf9b837f906f5872fe601c9712b0444d5ce6d',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1692,7 +1692,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1d05f12556588cc4162b383b7aa13865a9aa5596',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c499636a8f9bec11f42f2ce89b57c1a4d80ef409',
     'condition': 'checkout_src_internal',
   },
 
@@ -1711,7 +1711,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'VogUG4o3LP73Kd5tzgSvCBSPfCa9zRGd_FPuEG5byXkC',
+        'version': 'UcFjbZ80vDokyymGZVPZJi8WrXD5t_jfrGlSzCSWTRgC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1722,7 +1722,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': '4TqvAmaYlmxkgV5ZX7TcWkuuPBbeaqj-3u0-XvCOaVkC',
+        'version': 'Fu_Vv-127TddfIRXmqgJqD5xmGIh3v7o5TQHSN4ekIkC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1733,7 +1733,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 's_hGUrmWuKUL-_iHgiKwFxWYEqWWoP8MERwx20JB-cYC',
+        'version': 'pRBSas8lzL9DIXylB30R5CUMNZE99H8-V8UumNkwML4C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/WATCHLISTS b/WATCHLISTS
index 3719f42..cf544d9 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -716,7 +716,7 @@
       'filepath': 'chromeos/',
     },
     'chromeos_attestation': {
-      'filepath': 'chromeos/attestation/|'\
+      'filepath': 'ash/components/attestation/|'\
                   'chrome/browser/ash/attestation/|'\
                   'chrome/browser/extensions/api/enterprise_platform_keys_private/',
     },
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index 30e7d03..f0365a6e 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -132,7 +132,6 @@
   migrate_context_storage_data("Session Storage");
 
   // These were missed in the initial migration
-  migrate_context_storage_data("Application Cache");
   migrate_context_storage_data("File System");
   migrate_context_storage_data("IndexedDB");
   migrate_context_storage_data("Local Storage");
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java b/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java
index af72cbe..50c5f03 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java
@@ -438,12 +438,12 @@
 
     @Override
     public synchronized void setAppCacheEnabled(boolean flag) {
-        mAwSettings.setAppCacheEnabled(flag);
+        // Intentional no-op.
     }
 
     @Override
     public synchronized void setAppCachePath(String appCachePath) {
-        mAwSettings.setAppCachePath(appCachePath);
+        // Intentional no-op.
     }
 
     @Override
diff --git a/android_webview/java/src/org/chromium/android_webview/AwQuotaManagerBridge.java b/android_webview/java/src/org/chromium/android_webview/AwQuotaManagerBridge.java
index 6b2de7a..7e285a9 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwQuotaManagerBridge.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwQuotaManagerBridge.java
@@ -59,12 +59,11 @@
     }
 
     /*
-     * There are five HTML5 offline storage APIs.
+     * There are four HTML5 offline storage APIs.
      * 1) Web Storage (ie the localStorage and sessionStorage variables)
      * 2) Web SQL database
-     * 3) Application cache
-     * 4) Indexed Database
-     * 5) Filesystem API
+     * 3) Indexed Database
+     * 4) Filesystem API
      */
 
     /**
diff --git a/android_webview/java/src/org/chromium/android_webview/AwSettings.java b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
index 484d72d..e59c129 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwSettings.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
@@ -1433,20 +1433,6 @@
     }
 
     /**
-     * See {@link android.webkit.WebSettings#setAppCacheEnabled}.
-     */
-    public void setAppCacheEnabled(boolean flag) {
-        // Deprecated no-op.
-    }
-
-    /**
-     * See {@link android.webkit.WebSettings#setAppCachePath}.
-     */
-    public void setAppCachePath(String path) {
-        // Deprecated no-op.
-    }
-
-    /**
      * See {@link android.webkit.WebSettings#setDomStorageEnabled}.
      */
     public void setDomStorageEnabled(boolean flag) {
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index 1d9e1e1..2147d58 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -220,5 +220,7 @@
             Flag.baseFeature(BlinkFeatures.RTC_DISALLOW_PLAN_B_OUTSIDE_DEPRECATION_TRIAL,
                     "Makes constructing an RTCPeerConnection with {sdpSemantics:'plan-b'} throw "
                             + "an exception."),
+            Flag.baseFeature(BlinkFeatures.PREFETCH_ANDROID_FONTS,
+                    "Enables prefetching Android fonts on renderer startup."),
     };
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
index 0a15d4f..55a788c 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
@@ -284,7 +284,6 @@
     @MediumTest
     @Feature({"AndroidWebView"})
     @Test
-    @DisabledTest(message = "Flaky - https://crbug.com/1105220")
     public void testPowerSaveBlockerIsTransferredToFullscreen() throws Throwable {
         Assert.assertFalse(DOMUtils.isFullscreen(getWebContentsOnUiThread()));
         loadTestPage(VIDEO_INSIDE_DIV_TEST_URL);
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwQuotaManagerBridgeTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwQuotaManagerBridgeTest.java
index c4ddac4d..f4c83b63 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwQuotaManagerBridgeTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwQuotaManagerBridgeTest.java
@@ -5,7 +5,6 @@
 package org.chromium.android_webview.test;
 
 import android.support.test.InstrumentationRegistry;
-import android.util.Pair;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -22,9 +21,6 @@
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.net.test.util.TestWebServer;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Tests for the AwQuotaManagerBridge.
  */
@@ -50,8 +46,6 @@
         AwSettings settings = mActivityTestRule.getAwSettingsOnUiThread(mAwContents);
         settings.setJavaScriptEnabled(true);
         settings.setDomStorageEnabled(true);
-        settings.setAppCacheEnabled(true);
-        settings.setAppCachePath("whatever");  // Enables AppCache.
     }
 
     @After
@@ -117,37 +111,15 @@
         return callbackHelper.getValue();
     }
 
-    private void useAppCache() throws Exception {
-        final String cachedFilePath = "/foo.js";
-        final String cachedFileContents = "1 + 1;";
-        mWebServer.setResponse(cachedFilePath, cachedFileContents, null);
-
-        final String manifestPath = "/foo.manifest";
-        final String manifestContents = "CACHE MANIFEST\nCACHE:\n" + cachedFilePath;
-        List<Pair<String, String>> manifestHeaders = new ArrayList<Pair<String, String>>();
-        manifestHeaders.add(Pair.create("Content-Disposition", "text/cache-manifest"));
-        mWebServer.setResponse(manifestPath, manifestContents, manifestHeaders);
-
-        final String pagePath = "/appcache.html";
-        final String pageContents = "<html manifest=\"" + manifestPath + "\">"
-                + "<head><script src=\"" + cachedFilePath + "\"></script></head></html>";
-        String url = mWebServer.setResponse(pagePath, pageContents, null);
-
-        mActivityTestRule.loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), url);
-        mActivityTestRule.executeJavaScriptAndWaitForResult(
-                mAwContents, mContentsClient, "window.applicationCache.update();");
-    }
-
     /*
     @LargeTest
     @Feature({"AndroidWebView", "WebStore"})
     */
     @Test
     @DisabledTest(message = "crbug.com/609977")
-    public void testDeleteAllWithAppCache() throws Exception {
+    public void testDeleteAll() throws Exception {
         final long initialUsage = getUsageForOrigin(mOrigin);
 
-        useAppCache();
         AwActivityTestRule.pollInstrumentationThread(
                 () -> getUsageForOrigin(mOrigin) > initialUsage);
 
@@ -161,10 +133,9 @@
     */
     @Test
     @DisabledTest(message = "crbug.com/609977")
-    public void testDeleteOriginWithAppCache() throws Exception {
+    public void testDeleteOrigin() throws Exception {
         final long initialUsage = getUsageForOrigin(mOrigin);
 
-        useAppCache();
         AwActivityTestRule.pollInstrumentationThread(
                 () -> getUsageForOrigin(mOrigin) > initialUsage);
 
@@ -179,7 +150,6 @@
     @Test
     @DisabledTest(message = "crbug.com/609977")
     public void testGetResultsMatch() throws Exception {
-        useAppCache();
         AwQuotaManagerBridge bridge =
                 mActivityTestRule.getAwBrowserContext().getQuotaManagerBridge();
         AwActivityTestRule.pollInstrumentationThread(
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
index 4c1f61e..30d3e12e 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
@@ -416,6 +416,10 @@
             super(containerView, contentViewClient, true);
         }
 
+        // A string which can be encoded by UTF-8 charset but not by Latin-1 charset. Translates to
+        // "Hello world."
+        private static final String NON_LATIN_TEXT = "你好世界";
+
         @Override
         protected String getAlteredValue() {
             return "Latin-1";
@@ -439,11 +443,21 @@
         @Override
         protected void doEnsureSettingHasValue(String value) throws Throwable {
             loadDataSync(getData());
-            Assert.assertEquals(value, getTitleOnUiThread());
+
+            if ("UTF-8".equals(value)) {
+                Assert.assertEquals("Title should be decoded correctly when charset is UTF-8",
+                        NON_LATIN_TEXT, getTitleOnUiThread());
+            } else {
+                // The content seems to decode as "你好世界", but it's sufficient to just
+                // enforce the text decodes incorrectly.
+                Assert.assertNotEquals(
+                        "Title should be garbled (decoded incorrectly) when charset is Latin-1",
+                        NON_LATIN_TEXT, getTitleOnUiThread());
+            }
         }
 
         private String getData() {
-            return "<html><body onload='document.title=document.defaultCharset'></body></html>";
+            return "<html><body onload='document.title=\"" + NON_LATIN_TEXT + "\"'></body></html>";
         }
     }
 
@@ -1740,12 +1754,9 @@
                     views.getContainer1(), views.getClient1(), new ImagePageGenerator(1, true)));
     }
 
-    /*
-     * @SmallTest
-     * @Feature({"AndroidWebView", "Preferences"})
-     */
     @Test
-    @DisabledTest(message = "Disabled due to document.defaultCharset removal. crbug.com/587484")
+    @SmallTest
+    @Feature({"AndroidWebView", "Preferences"})
     public void testDefaultTextEncodingWithTwoViews() throws Throwable {
         ViewPair views = createViews();
         runPerViewSettingsTest(
diff --git a/android_webview/renderer/README.md b/android_webview/renderer/README.md
index f46c307..69e4bed 100644
--- a/android_webview/renderer/README.md
+++ b/android_webview/renderer/README.md
@@ -58,6 +58,34 @@
 overridden this callback. Therefore, unlike in Chrome, renderer crashes are
 often non-recoverable.
 
+### Toggling multiprocess for debugging
+
+On Android Oreo and above, you can toggle WebView multiprocess mode via adb:
+
+```shell
+# To disable:
+$ adb shell cmd webviewupdate disable-multiprocess
+
+# To re-enable:
+$ adb shell cmd webviewupdate enable-multiprocess
+```
+
+Then you can check the multiprocess state by running:
+
+```shell
+$ adb shell dumpsys webviewupdate | grep 'Multiprocess'
+  Multiprocess enabled: false
+```
+
+*** note
+**Warning:** this setting is persistent! Remember to re-enable multiprocess mode
+after you're done testing.
+
+Changing this setting will immediately kill all WebView-based apps running on
+the device (similar to what happens when you install a WebView update or change
+the system's WebView provider).
+***
+
 ## Multiple renderers
 
 WebView does not support multiple renderer processes, but this may be supported
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 3c31c8c..7b8461b 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -995,6 +995,8 @@
     "system/bluetooth/bluetooth_device_list_item_battery_view.h",
     "system/bluetooth/bluetooth_device_list_item_view.cc",
     "system/bluetooth/bluetooth_device_list_item_view.h",
+    "system/bluetooth/bluetooth_device_status_ui_handler.cc",
+    "system/bluetooth/bluetooth_device_status_ui_handler.h",
     "system/bluetooth/bluetooth_disabled_detailed_view.cc",
     "system/bluetooth/bluetooth_disabled_detailed_view.h",
     "system/bluetooth/bluetooth_feature_pod_controller.cc",
@@ -1037,6 +1039,8 @@
     "system/dark_mode/dark_mode_feature_pod_controller.cc",
     "system/dark_mode/dark_mode_feature_pod_controller.h",
     "system/enterprise/enterprise_domain_observer.h",
+    "system/geolocation/geolocation_controller.cc",
+    "system/geolocation/geolocation_controller.h",
     "system/gesture_education/gesture_education_notification_controller.cc",
     "system/gesture_education/gesture_education_notification_controller.h",
     "system/holding_space/downloads_section.cc",
@@ -1083,6 +1087,8 @@
     "system/holding_space/recent_files_bubble.h",
     "system/holding_space/screen_captures_section.cc",
     "system/holding_space/screen_captures_section.h",
+    "system/hps/hps_configuration.cc",
+    "system/hps/hps_configuration.h",
     "system/ime/ime_feature_pod_controller.cc",
     "system/ime/ime_feature_pod_controller.h",
     "system/ime/ime_observer.h",
@@ -1980,6 +1986,7 @@
     "//ash/assistant/util",
     "//ash/components/audio",
     "//ash/components/fwupd",
+    "//ash/components/geolocation",
     "//ash/components/pcie_peripheral",
     "//ash/components/phonehub",
     "//ash/components/settings",
@@ -2022,6 +2029,7 @@
     "//chromeos/dbus/hermes:hermes_clients",
     "//chromeos/dbus/hermes:hermes_fakes",
     "//chromeos/dbus/hps",
+    "//chromeos/dbus/hps:hps_proto",
     "//chromeos/dbus/init",
     "//chromeos/dbus/power",
     "//chromeos/dbus/power:power_manager_proto",
@@ -2136,7 +2144,6 @@
     # Ash should not depend upon cryptohome_client or components that depend
     # on it. TODO(stevenjb): Assert on //chromeos/dbus/cryptohome_client once it
     # is extracted from //chromeos/dbus. https://crbug.com/647367.
-    "//chromeos/attestation",
     "//chromeos/cryptohome",
     "//chromeos/login/auth",
     "//chromeos/tpm",
@@ -2435,6 +2442,7 @@
     "system/bluetooth/bluetooth_device_list_controller_unittest.cc",
     "system/bluetooth/bluetooth_device_list_item_battery_view_unittest.cc",
     "system/bluetooth/bluetooth_device_list_item_view_unittest.cc",
+    "system/bluetooth/bluetooth_device_status_ui_handler_unittest.cc",
     "system/bluetooth/bluetooth_disabled_detailed_view_unittest.cc",
     "system/bluetooth/bluetooth_feature_pod_controller_unittest.cc",
     "system/bluetooth/bluetooth_notification_controller_unittest.cc",
@@ -2446,8 +2454,10 @@
     "system/bluetooth/tray_bluetooth_helper_legacy_unittest.cc",
     "system/bluetooth/unified_bluetooth_detailed_view_controller_unittest.cc",
     "system/caps_lock_notification_controller_unittest.cc",
+    "system/geolocation/geolocation_controller_unittest.cc",
     "system/gesture_education/gesture_education_notification_controller_unittest.cc",
     "system/holding_space/holding_space_tray_unittest.cc",
+    "system/hps/hps_configuration_unittest.cc",
     "system/ime/ime_feature_pod_controller_unittest.cc",
     "system/ime_menu/ime_menu_tray_unittest.cc",
     "system/locale/locale_feature_pod_controller_unittest.cc",
@@ -2481,7 +2491,6 @@
     "system/network/sms_observer_unittest.cc",
     "system/network/vpn_list_unittest.cc",
     "system/network/wifi_toggle_notification_controller_unittest.cc",
-    "system/night_light/night_light_controller_unittest.cc",
     "system/overview/overview_button_tray_unittest.cc",
     "system/palette/mock_palette_tool_delegate.cc",
     "system/palette/mock_palette_tool_delegate.h",
@@ -2699,6 +2708,7 @@
     "//chromeos/dbus/hermes:hermes_clients",
     "//chromeos/dbus/hermes:hermes_fakes",
     "//chromeos/dbus/hps",
+    "//chromeos/dbus/hps:hps_proto",
     "//chromeos/dbus/power",
     "//chromeos/dbus/power:power_manager_proto",
     "//chromeos/dbus/services:test_support",
@@ -3041,6 +3051,7 @@
     "//ash/app_menu",
     "//ash/assistant/model:model",
     "//ash/assistant/ui:ui",
+    "//ash/components/attestation:test_support",
     "//ash/components/audio",
     "//ash/constants",
     "//ash/keyboard/ui",
diff --git a/ash/app_list/views/continue_section_view.cc b/ash/app_list/views/continue_section_view.cc
index c2464ef..cf276f4 100644
--- a/ash/app_list/views/continue_section_view.cc
+++ b/ash/app_list/views/continue_section_view.cc
@@ -16,9 +16,11 @@
 #include "ash/app_list/views/continue_task_view.h"
 #include "ash/bubble/bubble_utils.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
+#include "ash/strings/grit/ash_strings.h"
 #include "base/check.h"
 #include "base/strings/string_util.h"
 #include "extensions/common/constants.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/label.h"
@@ -67,10 +69,9 @@
   layout->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::kStretch);
 
-  // TODO(https://crbug.com/1204551): Localized strings.
-  // TODO(https://crbug.com/1204551): Styling.
   if (!tablet_mode) {
-    auto* continue_label = AddChildView(CreateContinueLabel(u"Continue"));
+    auto* continue_label = AddChildView(CreateContinueLabel(
+        l10n_util::GetStringUTF16(IDS_ASH_LAUNCHER_CONTINUE_SECTION_LABEL)));
     continue_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     continue_label->SetBorder(
         views::CreateEmptyBorder(gfx::Insets(0, kHeaderHorizontalPadding)));
diff --git a/ash/app_list/views/search_result_view.cc b/ash/app_list/views/search_result_view.cc
index 4811c606..ed222e7 100644
--- a/ash/app_list/views/search_result_view.cc
+++ b/ash/app_list/views/search_result_view.cc
@@ -35,12 +35,14 @@
 #include "ui/gfx/geometry/skia_conversions.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/views/accessibility/accessibility_paint_checks.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/menu/menu_runner.h"
-#include "ui/views/controls/styled_label.h"
 #include "ui/views/image_model_utils.h"
+#include "ui/views/layout/flex_layout.h"
+#include "ui/views/layout/flex_layout_view.h"
 #include "ui/views/style/typography.h"
 
 namespace ash {
@@ -144,26 +146,71 @@
   set_context_menu_controller(this);
   SetNotifyEnterExitOnChild(true);
 
-  title_label_ = AddChildView(std::make_unique<views::StyledLabel>());
-  title_label_->SetDisplayedOnBackgroundColor(SK_ColorTRANSPARENT);
+  text_container_ = AddChildView(std::make_unique<views::FlexLayoutView>());
+  text_container_->GetViewAccessibility().OverrideIsIgnored(true);
+  text_container_->SetCrossAxisAlignment(views::LayoutAlignment::kStretch);
+
+  switch (view_type_) {
+    case SearchResultViewType::kDefault:
+      text_container_->SetOrientation(views::LayoutOrientation::kHorizontal);
+      break;
+    case SearchResultViewType::kClassic:
+    case SearchResultViewType::kInlineAnswer:
+      text_container_->SetOrientation(views::LayoutOrientation::kVertical);
+      break;
+  }
+
+  auto setup_flex_specifications = [](views::View* view) {
+    view->SetProperty(
+        views::kFlexBehaviorKey,
+        views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero,
+                                 views::MaximumFlexSizeRule::kScaleToMaximum));
+  };
+
+  title_label_ =
+      text_container_->AddChildView(std::make_unique<views::Label>());
+  title_label_->SetBackgroundColor(SK_ColorTRANSPARENT);
   title_label_->SetVisible(false);
+  title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  setup_flex_specifications(title_label_);
 
-  details_label_ = AddChildView(std::make_unique<views::StyledLabel>());
-  details_label_->SetDisplayedOnBackgroundColor(SK_ColorTRANSPARENT);
-  details_label_->SetVisible(false);
-
-  separator_label_ = AddChildView(std::make_unique<views::Label>(
-      l10n_util::GetStringUTF16(IDS_ASH_SEARCH_RESULT_SEPARATOR),
-      CONTEXT_SEARCH_RESULT_VIEW, STYLE_PRODUCTIVITY_LAUNCHER));
+  separator_label_ =
+      text_container_->AddChildView(std::make_unique<views::Label>(
+          l10n_util::GetStringUTF16(IDS_ASH_SEARCH_RESULT_SEPARATOR)));
   separator_label_->SetBackgroundColor(SK_ColorTRANSPARENT);
   separator_label_->SetVisible(false);
   separator_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  setup_flex_specifications(separator_label_);
+
+  details_label_ =
+      text_container_->AddChildView(std::make_unique<views::Label>());
+  details_label_->SetBackgroundColor(SK_ColorTRANSPARENT);
+  details_label_->SetVisible(false);
+  details_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  setup_flex_specifications(details_label_);
+
+  title_label_->SetTextContext(CONTEXT_SEARCH_RESULT_VIEW);
+  separator_label_->SetTextContext(CONTEXT_SEARCH_RESULT_VIEW);
+  details_label_->SetTextContext(CONTEXT_SEARCH_RESULT_VIEW);
+  switch (view_type_) {
+    case SearchResultViewType::kClassic:
+      title_label_->SetTextStyle(STYLE_CLASSIC_LAUNCHER);
+      separator_label_->SetTextStyle(STYLE_CLASSIC_LAUNCHER);
+      details_label_->SetTextStyle(STYLE_CLASSIC_LAUNCHER);
+      break;
+    case SearchResultViewType::kDefault:
+    case SearchResultViewType::kInlineAnswer:
+      title_label_->SetTextStyle(STYLE_PRODUCTIVITY_LAUNCHER);
+      separator_label_->SetTextStyle(STYLE_PRODUCTIVITY_LAUNCHER);
+      details_label_->SetTextStyle(STYLE_PRODUCTIVITY_LAUNCHER);
+  }
 }
 
 SearchResultView::~SearchResultView() = default;
 
 void SearchResultView::OnResultChanged() {
   OnMetadataChanged();
+  // Update tile, separator, and details text visibility.
   UpdateTitleText();
   UpdateDetailsText();
   UpdateAccessibleName();
@@ -201,25 +248,40 @@
 void SearchResultView::UpdateTitleText() {
   if (!result() || result()->title().empty()) {
     title_label_->SetText(std::u16string());
+    text_container_->SetVisible(false);
+    title_label_->SetVisible(false);
   } else {
     title_label_->SetText(result()->title());
     StyleTitleLabel();
+    text_container_->SetVisible(true);
+    title_label_->SetVisible(true);
   }
 }
 
 void SearchResultView::UpdateDetailsText() {
   if (!result() || result()->details().empty()) {
     details_label_->SetText(std::u16string());
+    details_label_->SetVisible(false);
+    separator_label_->SetVisible(false);
   } else {
     details_label_->SetText(result()->details());
     StyleDetailsLabel();
+    details_label_->SetVisible(true);
+    switch (view_type_) {
+      case SearchResultViewType::kDefault:
+        separator_label_->SetVisible(true);
+        break;
+      case SearchResultViewType::kClassic:
+      case SearchResultViewType::kInlineAnswer:
+
+        separator_label_->SetVisible(false);
+    }
   }
 }
 
-void SearchResultView::StyleLabel(views::StyledLabel* label,
+void SearchResultView::StyleLabel(views::Label* label,
+                                  bool is_title_label,
                                   const SearchResult::Tags& tags) {
-  label->ClearStyleRanges();
-
   // Apply font weight styles.
   bool is_url = false;
   for (const auto& tag : tags) {
@@ -227,45 +289,28 @@
     bool has_match_tag = (tag.styles & SearchResult::Tag::MATCH);
     is_url = has_url_tag || is_url;
     if (has_match_tag) {
-      views::StyledLabel::RangeStyleInfo selected_text_bold;
-      selected_text_bold.text_style = ash::AshTextStyle::STYLE_EMPHASIZED;
-      selected_text_bold.disable_line_wrapping = true;
-      selected_text_bold.override_color =
-          is_url ? AshColorProvider::Get()->GetContentLayerColor(
-                       AshColorProvider::ContentLayerType::kTextColorURL)
-                 : AppListColorProvider::Get()->GetSearchBoxSecondaryTextColor(
-                       kDeprecatedSearchBoxTextDefaultColor);
-      label->AddStyleRange(tag.range, selected_text_bold);
+      label->SetTextStyleRange(AshTextStyle::STYLE_EMPHASIZED, tag.range);
     }
   }
-
   // Apply font color styles.
-  views::StyledLabel::RangeStyleInfo base_style;
-  switch (view_type_) {
-    case SearchResultViewType::kClassic:
-      label->SetTextContext(CONTEXT_SEARCH_RESULT_VIEW);
-      label->SetDefaultTextStyle(STYLE_CLASSIC_LAUNCHER);
-      break;
-    case SearchResultViewType::kInlineAnswer:
-    case SearchResultViewType::kDefault:
-      label->SetTextContext(CONTEXT_SEARCH_RESULT_VIEW);
-      label->SetDefaultTextStyle(STYLE_PRODUCTIVITY_LAUNCHER);
-  }
-  base_style.override_color =
-      is_url ? AshColorProvider::Get()->GetContentLayerColor(
-                   AshColorProvider::ContentLayerType::kTextColorURL)
-             : AppListColorProvider::Get()->GetSearchBoxSecondaryTextColor(
-                   kDeprecatedSearchBoxTextDefaultColor);
-  base_style.disable_line_wrapping = true;
-  label->AddStyleRange(gfx::Range(0, label->GetText().size()), base_style);
+  label->SetEnabledColor(
+      is_url
+          ? AshColorProvider::Get()->GetContentLayerColor(
+                AshColorProvider::ContentLayerType::kTextColorURL)
+          : is_title_label
+                ? AppListColorProvider::Get()->GetSearchBoxTextColor(
+                      kDeprecatedSearchBoxTextDefaultColor)
+                : AppListColorProvider::Get()->GetSearchBoxSecondaryTextColor(
+                      kDeprecatedSearchBoxTextDefaultColor));
 }
 
 void SearchResultView::StyleTitleLabel() {
-  StyleLabel(title_label_, result()->title_tags());
+  StyleLabel(title_label_, true /*is_title_label*/, result()->title_tags());
 }
 
 void SearchResultView::StyleDetailsLabel() {
-  StyleLabel(details_label_, result()->details_tags());
+  StyleLabel(details_label_, false /*is_title_label*/,
+             result()->details_tags());
 }
 
 void SearchResultView::OnQueryRemovalAccepted(bool accepted) {
@@ -344,31 +389,9 @@
     switch (view_type_) {
       case SearchResultViewType::kDefault: {
         gfx::Size label_size(text_bounds.width(), PrimaryTextHeight());
-        gfx::Rect title_rect(text_bounds);
-        title_rect.ClampToCenteredSize(label_size);
-        title_label_->SetBoundsRect(title_rect);
-        title_label_->SetVisible(true);
-
-        // Create Separator label.
-        int title_width = title_label_->CalculatePreferredSize().width();
-        gfx::Rect separator_rect(text_bounds);
-        separator_rect.ClampToCenteredSize(label_size);
-        separator_rect.set_x(title_rect.x() + title_width);
-        separator_rect.set_width(separator_rect.width() - title_width);
-        separator_label_->SetBoundsRect(separator_rect);
-        separator_label_->SetVisible(true);
-
-        // Create details label shifted to the right.
-
-        // TODO(yulunwu) Reimplement with a layout manager.
-        int title_separator_width =
-            title_width + separator_label_->CalculatePreferredSize().width();
-        gfx::Rect details_rect(text_bounds);
-        details_rect.ClampToCenteredSize(label_size);
-        details_rect.set_x(details_rect.x() + title_separator_width);
-        details_rect.set_width(details_rect.width() - title_separator_width);
-        details_label_->SetBoundsRect(details_rect);
-        details_label_->SetVisible(true);
+        gfx::Rect centered_text_bounds(text_bounds);
+        centered_text_bounds.ClampToCenteredSize(label_size);
+        text_container_->SetBoundsRect(centered_text_bounds);
         break;
       }
       case SearchResultViewType::kClassic:
@@ -376,27 +399,17 @@
         gfx::Size title_size(text_bounds.width(), PrimaryTextHeight());
         gfx::Size details_size(text_bounds.width(), SecondaryTextHeight());
         int total_height = title_size.height() + details_size.height();
-        int y = text_bounds.y() + (text_bounds.height() - total_height) / 2;
-
-        title_label_->SetBoundsRect(
-            gfx::Rect(gfx::Point(text_bounds.x(), y), title_size));
-        title_label_->SetVisible(true);
-
-        y += title_size.height();
-        details_label_->SetBoundsRect(
-            gfx::Rect(gfx::Point(text_bounds.x(), y), details_size));
-        details_label_->SetVisible(true);
-        separator_label_->SetVisible(false);
+        gfx::Size label_size(text_bounds.width(), total_height);
+        gfx::Rect centered_text_bounds(text_bounds);
+        centered_text_bounds.ClampToCenteredSize(label_size);
+        text_container_->SetBoundsRect(centered_text_bounds);
       }
     }
   } else if (!title_label_->GetText().empty()) {
-    gfx::Size title_size(text_bounds.width(), PrimaryTextHeight());
-    gfx::Rect centered_title_rect(text_bounds);
-    centered_title_rect.ClampToCenteredSize(title_size);
-    title_label_->SetBoundsRect(centered_title_rect);
-    title_label_->SetVisible(true);
-    details_label_->SetVisible(false);
-    separator_label_->SetVisible(false);
+    gfx::Size text_size(text_bounds.width(), PrimaryTextHeight());
+    gfx::Rect centered_text_bounds(text_bounds);
+    centered_text_bounds.ClampToCenteredSize(text_size);
+    text_container_->SetBoundsRect(centered_text_bounds);
   }
 }
 
diff --git a/ash/app_list/views/search_result_view.h b/ash/app_list/views/search_result_view.h
index cd18df5d..0524af5 100644
--- a/ash/app_list/views/search_result_view.h
+++ b/ash/app_list/views/search_result_view.h
@@ -21,8 +21,8 @@
 #include "ui/views/context_menu_controller.h"
 
 namespace views {
+class FlexLayoutView;
 class ImageView;
-class StyledLabel;
 class Label;
 }  // namespace views
 
@@ -83,7 +83,9 @@
   void UpdateTitleText();
   void UpdateDetailsText();
 
-  void StyleLabel(views::StyledLabel* label, const SearchResult::Tags& tags);
+  void StyleLabel(views::Label* label,
+                  bool is_title_label,
+                  const SearchResult::Tags& tags);
   void StyleTitleLabel();
   void StyleDetailsLabel();
 
@@ -144,9 +146,11 @@
 
   MaskedImageView* icon_ = nullptr;              // Owned by views hierarchy.
   views::ImageView* badge_icon_ = nullptr;       // Owned by views hierarchy.
-  views::StyledLabel* title_label_ = nullptr;    // Owned by view hierarchy.
-  views::StyledLabel* details_label_ = nullptr;  // Owned by view hierarchy.
-  views::Label* separator_label_ = nullptr;      // Owned by view hierarchy.
+  views::FlexLayoutView* text_container_ =
+      nullptr;                               // Owned by views hierarchy.
+  views::Label* title_label_ = nullptr;      // Owned by views hierarchy.
+  views::Label* details_label_ = nullptr;    // Owned by views hierarchy.
+  views::Label* separator_label_ = nullptr;  // Owned by views hierarchy.
 
   std::unique_ptr<AppListMenuModelAdapter> context_menu_;
 
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 87918f2..cdd4c3be 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -546,13 +546,16 @@
       <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_NO_DEVICE_CONNECTED" desc="The sub-header label for no devices connected in the Bluetooth device list.">
         No device connected
       </message>
+      <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED_OR_CONNECTED_TOAST" desc="The text used in the toast shown when a new Bluetooth device is newly paired or connected.">
+      <ph name="DEVICE_NAME">$1<ex>Pixel Buds</ex></ph> connected
+      </message>
 
       <message name="IDS_ASH_STATUS_TRAY_UPDATE" desc="The label used in the tray popup to notify that the user should restart to get system updates.">
         Restart to update
       </message>
 
-      <message name="IDS_ASH_STATUS_TRAY_RESTART_AND_POWERWASH_TO_UPDATE" desc="The label used in the tray popup to notify that the user should restart and powerwash the device to get system updates.">
-        Restart and powerwash to update
+      <message name="IDS_ASH_STATUS_TRAY_RESET_TO_UPDATE" desc="The label used in the tray popup to notify that the user should restart and powerwash the device to get system updates.">
+        Reset to update
       </message>
 
       <message name="IDS_ASH_STATUS_TRAY_UPDATE_OVER_CELLULAR_AVAILABLE" desc="The label used in the tray popup to notify that update is available but current connection is cellular.">
@@ -563,7 +566,10 @@
         Update available
       </message>
       <message name="IDS_ROLLBACK_NOTIFICATION_TITLE" desc="The title of the notification to notify that the user should restart to roll back the device.">
-        Device will be rolled back
+        Device needs to go back to previous version
+      </message>
+      <message name="IDS_ROLLBACK_OVERDUE_NOTIFICATION_TITLE" desc="The title of the notification to notify that the user should restart to roll back the device and the admin recommended to restart.">
+        Device change to previous version is overdue
       </message>
 
       <!-- Upgrade notifications -->
@@ -589,7 +595,32 @@
           other {Update device within # seconds}}
       </message>
       <message name="IDS_RELAUNCH_REQUIRED_BODY" desc="The body text of a dialog that tells users the device must be restarted. MANAGER can be a domain or an email address.">
-        <ph name="MANAGER">$1<ex>google.com</ex></ph> requires you to update this <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph> before the deadline.
+        <ph name="MANAGER">$1<ex>google.com</ex></ph> requires you to update your <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph> before the deadline
+      </message>
+
+      <message name="IDS_ROLLBACK_REQUIRED_TITLE_DAYS" desc="The title of a dialog that tells users the device must be restarted to roll back to an earlier version within days. The device will be wiped on restart.">
+        {0, plural,
+          =1 {Change device to previous version within a day}
+          other {Change device to previous version within # days}}
+      </message>
+      <message name="IDS_ROLLBACK_REQUIRED_TITLE_HOURS" desc="The title of a dialog that tells users the device must be restarted to roll back to an earlier version within hours. The device will be wiped on restart.">
+        {0, plural,
+          =1 {Change device to previous version within an hour}
+          other {Change device to previous version within # hours}}
+      </message>
+      <message name="IDS_ROLLBACK_REQUIRED_TITLE_MINUTES" desc="The title of a dialog that tells users the device must be restarted to roll back to an earlier version within minutes. The device will be wiped on restart.">
+        {0, plural,
+          =1 {Change device to previous version within 1 minute}
+          other {Change device to previous version within # minutes}}
+      </message>
+      <message name="IDS_ROLLBACK_REQUIRED_TITLE_SECONDS" desc="The title of a dialog that tells users the device must be restarted to roll back to an earlier version within seconds. The device will be wiped on restart.">
+        {0, plural,
+          =0 {Change device to previous version within now}
+          =1 {Change device to previous version within 1 second}
+          other {Change device to previous version within # seconds}}
+      </message>
+      <message name="IDS_ROLLBACK_REQUIRED_BODY" desc="The body text of a dialog that tells users the device must be restarted to roll back to an earlier version within a deadline given in the title of the message. The device will be wiped on restart. MANAGER can be a domain or an email address.">
+        <ph name="MANAGER">$1<ex>google.com</ex></ph> requires you to roll back your <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph>. Your device will reset and all data will be deleted.
       </message>
 
       <message name="IDS_RELAUNCH_RECOMMENDED_TITLE" desc="The title of a dialog that tells users that a device restart is recommended for an update.">
@@ -599,10 +630,10 @@
         Update overdue
       </message>
       <message name="IDS_RELAUNCH_RECOMMENDED_BODY" desc="The body text of a dialog that tells users the device must be restarted. MANAGER can be a domain or an email address.">
-        <ph name="MANAGER">$1<ex>google.com</ex></ph> recommends that you update this <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph>.
+        <ph name="MANAGER">$1<ex>google.com</ex></ph> recommends that you update your <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph>
       </message>
       <message name="IDS_RELAUNCH_RECOMMENDED_OVERDUE_BODY" desc="The body text of a dialog that tells users the device must be restarted right now. MANAGER can be a domain or an email address.">
-        <ph name="MANAGER">$1<ex>google.com</ex></ph> requires you to update this <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph> immediately.
+        <ph name="MANAGER">$1<ex>google.com</ex></ph> requires you to update your <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph> immediately
       </message>
 
       <message name="IDS_GESTURE_NOTIFICATION_TITLE" desc="The title of the notification to show off new gestures.">
@@ -630,13 +661,16 @@
         Restart to update
       </message>
       <message name="IDS_ROLLBACK_NOTIFICATION_RESTART_BUTTON" meaning="button label" desc="The label used as the button to restart system to rollback. Displayed as the action button of the notification for system rollback.">
-        Restart and reset
+        Reset
       </message>
       <message name="IDS_UPDATE_NOTIFICATION_MESSAGE_POWERWASH" desc="The notification message used in the system notification update when user need to powerwash the device in order to update the system.">
-        This update requires powerwashing your device. Learn more about the latest <ph name="SYSTEM_APP_NAME">$1<ex>Chromium OS</ex></ph> update.
+        This update requires powerwashing your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. All data will be deleted. Learn more about the latest <ph name="SYSTEM_APP_NAME">$2<ex>Chromium OS</ex></ph> update.
       </message>
-      <message name="IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK" desc="The notification message used in the system notification update when the device is rolled back and data will be deleted.">
-        Your administrator is rolling back your device. All data will be deleted when the device is restarted.
+      <message name="IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK" desc="The notification message used in the system notification update when the device is rolled back and data will be deleted. MANAGER can be a domain or an email address.">
+        <ph name="MANAGER">$1<ex>google.com</ex></ph> is rolling back your <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph>. Your device will reset and all data will be deleted.
+      </message>
+      <message name="IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK_OVERDUE" desc="The notification message used in the system notification update when the device is overdue for rollback that will put the device on a previous version and delete data. MANAGER can be a domain or an email address.">
+        <ph name="MANAGER">$1<ex>google.com</ex></ph> requires you to roll back your <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph>. Your device will reset and all data will be deleted.
       </message>
       <message name="IDS_UPDATE_NOTIFICATION_MESSAGE_SLOW_BOOT" desc="The additional body of the notification to notify the user that the next reboot is slow.">
         <ph name="UPDATE_TEXT">$1<ex>Learn more about the latest Chromium OS update</ex></ph>. This Chromebook needs to restart to apply an update. This can take up to 1 minute.
@@ -4305,7 +4339,10 @@
         Too many fingerprint attempts
       </message>
 
-      <!-- Continue Section strings -->
+      <!-- Launcher: Continue Section -->
+      <message name="IDS_ASH_LAUNCHER_CONTINUE_SECTION_LABEL" desc="Label for the continue section of the launcher, which shows recent files and apps that the user can continue using.">
+        Continue
+      </message>
       <message name="IDS_ASH_LAUNCHER_CONTINUE_SECTION_CONTEXT_MENU_OPEN" desc="Context menu option title to open a suggestion for a task in the launcher. Tasks display in the continue section located above the app list.">
         Open
       </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_LAUNCHER_CONTINUE_SECTION_LABEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_LAUNCHER_CONTINUE_SECTION_LABEL.png.sha1
new file mode 100644
index 0000000..7ae0ffda
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_LAUNCHER_CONTINUE_SECTION_LABEL.png.sha1
@@ -0,0 +1 @@
+da6739cce85d374f5d83c0ff25cc552487ee4e8b
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED_OR_CONNECTED_TOAST.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED_OR_CONNECTED_TOAST.png.sha1
new file mode 100644
index 0000000..099f0d74
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED_OR_CONNECTED_TOAST.png.sha1
@@ -0,0 +1 @@
+87bd6f70ba8e07d89e749e2eaaf56404d8256364
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_RESET_TO_UPDATE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_RESET_TO_UPDATE.png.sha1
new file mode 100644
index 0000000..5803a70
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_RESET_TO_UPDATE.png.sha1
@@ -0,0 +1 @@
+5bbda6831cc51621b6f1a7ee2396e80534142acc
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_RELAUNCH_RECOMMENDED_BODY.png.sha1 b/ash/ash_strings_grd/IDS_RELAUNCH_RECOMMENDED_BODY.png.sha1
index 2af33f45..2f69fcb 100644
--- a/ash/ash_strings_grd/IDS_RELAUNCH_RECOMMENDED_BODY.png.sha1
+++ b/ash/ash_strings_grd/IDS_RELAUNCH_RECOMMENDED_BODY.png.sha1
@@ -1 +1 @@
-19b1999ddf8d24c17222245c87079f65aedd57b1
\ No newline at end of file
+92765d7290a890fd68ca29a0400c3abaf2c44717
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_RELAUNCH_RECOMMENDED_OVERDUE_BODY.png.sha1 b/ash/ash_strings_grd/IDS_RELAUNCH_RECOMMENDED_OVERDUE_BODY.png.sha1
index e8ad0c7a..6bf9840 100644
--- a/ash/ash_strings_grd/IDS_RELAUNCH_RECOMMENDED_OVERDUE_BODY.png.sha1
+++ b/ash/ash_strings_grd/IDS_RELAUNCH_RECOMMENDED_OVERDUE_BODY.png.sha1
@@ -1 +1 @@
-8bbf09ff39bdb507669579d145c0cad6d8dcb1d0
\ No newline at end of file
+3b03ec5656219dd80d23a24a97b3f84e3cea4e85
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_RELAUNCH_REQUIRED_BODY.png.sha1 b/ash/ash_strings_grd/IDS_RELAUNCH_REQUIRED_BODY.png.sha1
index e343d813..b81c0156 100644
--- a/ash/ash_strings_grd/IDS_RELAUNCH_REQUIRED_BODY.png.sha1
+++ b/ash/ash_strings_grd/IDS_RELAUNCH_REQUIRED_BODY.png.sha1
@@ -1 +1 @@
-2c4bf103c2bf5cf38c106731cbebf75dca983eb6
\ No newline at end of file
+1973a7fe2d47a0b484be8c4e87d2168b59319fc3
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ROLLBACK_NOTIFICATION_RESTART_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_ROLLBACK_NOTIFICATION_RESTART_BUTTON.png.sha1
new file mode 100644
index 0000000..df865960a
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ROLLBACK_NOTIFICATION_RESTART_BUTTON.png.sha1
@@ -0,0 +1 @@
+d0b23ad0e5fb5690e4d3d762d81353544f9f3a04
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ROLLBACK_NOTIFICATION_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ROLLBACK_NOTIFICATION_TITLE.png.sha1
new file mode 100644
index 0000000..df865960a
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ROLLBACK_NOTIFICATION_TITLE.png.sha1
@@ -0,0 +1 @@
+d0b23ad0e5fb5690e4d3d762d81353544f9f3a04
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ROLLBACK_OVERDUE_NOTIFICATION_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ROLLBACK_OVERDUE_NOTIFICATION_TITLE.png.sha1
new file mode 100644
index 0000000..dd5c084
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ROLLBACK_OVERDUE_NOTIFICATION_TITLE.png.sha1
@@ -0,0 +1 @@
+3cdf279d3bca062cf67f37609bd4366187e79aad
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_BODY.png.sha1 b/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_BODY.png.sha1
new file mode 100644
index 0000000..919b9905
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_BODY.png.sha1
@@ -0,0 +1 @@
+4a7cfbbb582cf6bc93098d1d5ead43a722993a0f
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_TITLE_DAYS.png.sha1 b/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_TITLE_DAYS.png.sha1
new file mode 100644
index 0000000..919b9905
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_TITLE_DAYS.png.sha1
@@ -0,0 +1 @@
+4a7cfbbb582cf6bc93098d1d5ead43a722993a0f
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_TITLE_HOURS.png.sha1 b/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_TITLE_HOURS.png.sha1
new file mode 100644
index 0000000..88dd748
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_TITLE_HOURS.png.sha1
@@ -0,0 +1 @@
+c86457d0279e44eb5301ba8b1997be25fc4fca93
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_TITLE_MINUTES.png.sha1 b/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_TITLE_MINUTES.png.sha1
new file mode 100644
index 0000000..5e7d275
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_TITLE_MINUTES.png.sha1
@@ -0,0 +1 @@
+7ba81c760aad0b77a62e92ec0fecef9955318535
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_TITLE_SECONDS.png.sha1 b/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_TITLE_SECONDS.png.sha1
new file mode 100644
index 0000000..a1c48a1
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ROLLBACK_REQUIRED_TITLE_SECONDS.png.sha1
@@ -0,0 +1 @@
+30704379921115092223b1c60814a007d594fc7f
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_UPDATE_NOTIFICATION_MESSAGE_POWERWASH.png.sha1 b/ash/ash_strings_grd/IDS_UPDATE_NOTIFICATION_MESSAGE_POWERWASH.png.sha1
new file mode 100644
index 0000000..5803a70
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_UPDATE_NOTIFICATION_MESSAGE_POWERWASH.png.sha1
@@ -0,0 +1 @@
+5bbda6831cc51621b6f1a7ee2396e80534142acc
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK.png.sha1 b/ash/ash_strings_grd/IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK.png.sha1
new file mode 100644
index 0000000..df865960a
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK.png.sha1
@@ -0,0 +1 @@
+d0b23ad0e5fb5690e4d3d762d81353544f9f3a04
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK_OVERDUE.png.sha1 b/ash/ash_strings_grd/IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK_OVERDUE.png.sha1
new file mode 100644
index 0000000..dd5c084
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK_OVERDUE.png.sha1
@@ -0,0 +1 @@
+3cdf279d3bca062cf67f37609bd4366187e79aad
\ No newline at end of file
diff --git a/ash/components/BUILD.gn b/ash/components/BUILD.gn
index 2fd838f..53cb7c8 100644
--- a/ash/components/BUILD.gn
+++ b/ash/components/BUILD.gn
@@ -11,6 +11,7 @@
 source_set("unit_tests") {
   testonly = true
   deps = [
+    "//ash/components/attestation:unit_tests",
     "//ash/components/audio:unit_tests",
     "//ash/components/device_activity:unit_tests",
     "//ash/components/drivefs:unit_tests",
diff --git a/ash/components/arc/BUILD.gn b/ash/components/arc/BUILD.gn
index 358562e..309136d 100644
--- a/ash/components/arc/BUILD.gn
+++ b/ash/components/arc/BUILD.gn
@@ -316,8 +316,6 @@
     "test/fake_file_system_instance.h",
     "test/fake_iio_sensor_instance.cc",
     "test/fake_iio_sensor_instance.h",
-    "test/fake_intent_helper_instance.cc",
-    "test/fake_intent_helper_instance.h",
     "test/fake_lock_screen_instance.cc",
     "test/fake_lock_screen_instance.h",
     "test/fake_memory_instance.cc",
@@ -407,13 +405,6 @@
     "enterprise/snapshot_session_controller_unittest.cc",
     "ime/arc_ime_service_unittest.cc",
     "ime/key_event_result_receiver_unittest.cc",
-
-    # TODO(b/129295708): Move intent_helper unit tests back to //components/arc.
-    "intent_helper/activity_icon_loader_unittest.cc",
-    "intent_helper/arc_intent_helper_bridge_unittest.cc",
-    "intent_helper/custom_tab_unittest.cc",
-    "intent_helper/intent_filter_unittest.cc",
-    "intent_helper/link_handler_model_unittest.cc",
     "lock_screen/arc_lock_screen_bridge_unittest.cc",
     "media_session/arc_media_session_bridge_unittest.cc",
     "memory/arc_memory_bridge_unittest.cc",
@@ -488,7 +479,6 @@
     "//ui/events:dom_keycode_converter",
     "//ui/events:test_support",
     "//ui/ozone",
-    "//ui/views",
     "//ui/views:test_support",
     "//url:url",
   ]
diff --git a/ash/components/arc/net/DEPS b/ash/components/arc/net/DEPS
index 04c0d47..6aa7cc8 100644
--- a/ash/components/arc/net/DEPS
+++ b/ash/components/arc/net/DEPS
@@ -3,6 +3,7 @@
   "+chromeos/network",
   "+components/onc",
   "+components/user_manager",
+  "+dbus",
   "+third_party/cros_system_api/dbus/service_constants.h",
   "+third_party/cros_system_api/dbus/shill",
 ]
diff --git a/ash/components/arc/net/arc_net_host_impl.cc b/ash/components/arc/net/arc_net_host_impl.cc
index 42c580f..cf579e7 100644
--- a/ash/components/arc/net/arc_net_host_impl.cc
+++ b/ash/components/arc/net/arc_net_host_impl.cc
@@ -16,6 +16,8 @@
 #include "base/memory/singleton.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "chromeos/dbus/shill/shill_manager_client.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "chromeos/network/device_state.h"
 #include "chromeos/network/managed_network_configuration_handler.h"
@@ -30,6 +32,7 @@
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
+#include "dbus/object_path.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
 
 namespace {
@@ -49,6 +52,15 @@
   return chromeos::NetworkHandler::Get()->network_connection_handler();
 }
 
+chromeos::NetworkProfileHandler* GetNetworkProfileHandler() {
+  return chromeos::NetworkHandler::Get()->network_profile_handler();
+}
+
+const chromeos::NetworkProfile* GetNetworkProfile() {
+  return GetNetworkProfileHandler()->GetProfileForUserhash(
+      chromeos::LoginState::Get()->primary_user_hash());
+}
+
 std::vector<const chromeos::NetworkState*> GetActiveNetworks() {
   std::vector<const chromeos::NetworkState*> active_networks;
   GetStateHandler()->GetActiveNetworkListByType(
@@ -65,6 +77,58 @@
          user_manager::UserManager::Get()->GetOwnerAccountId();
 }
 
+std::string TranslateEapMethod(arc::mojom::EapMethod method) {
+  switch (method) {
+    case arc::mojom::EapMethod::kLeap:
+      return shill::kEapMethodLEAP;
+    case arc::mojom::EapMethod::kPeap:
+      return shill::kEapMethodPEAP;
+    case arc::mojom::EapMethod::kTls:
+      return shill::kEapMethodTLS;
+    case arc::mojom::EapMethod::kTtls:
+      return shill::kEapMethodTTLS;
+    case arc::mojom::EapMethod::kNone:
+      return "";
+  }
+  NET_LOG(ERROR) << "Unknown EAP method";
+  return "";
+}
+
+std::string TranslateEapPhase2Method(arc::mojom::EapPhase2Method method) {
+  switch (method) {
+    case arc::mojom::EapPhase2Method::kPap:
+      return shill::kEapPhase2AuthTTLSPAP;
+    case arc::mojom::EapPhase2Method::kMschap:
+      return shill::kEapPhase2AuthTTLSMSCHAP;
+    case arc::mojom::EapPhase2Method::kMschapv2:
+      return shill::kEapPhase2AuthTTLSMSCHAPV2;
+    case arc::mojom::EapPhase2Method::kNone:
+      return "";
+  }
+  NET_LOG(ERROR) << "Unknown EAP phase 2 method";
+  return "";
+}
+
+std::string TranslateKeyManagement(arc::mojom::KeyManagement management) {
+  switch (management) {
+    case arc::mojom::KeyManagement::kIeee8021X:
+      return shill::kKeyManagementIEEE8021X;
+    case arc::mojom::KeyManagement::kFtEap:
+    case arc::mojom::KeyManagement::kFtPsk:
+    case arc::mojom::KeyManagement::kFtSae:
+    case arc::mojom::KeyManagement::kWpaEap:
+    case arc::mojom::KeyManagement::kWpaEapSha256:
+    case arc::mojom::KeyManagement::kWpaPsk:
+    case arc::mojom::KeyManagement::kSae:
+    case arc::mojom::KeyManagement::kNone:
+      // Currently these key managements are not handled.
+      NET_LOG(ERROR) << "Key management is not supported";
+      return "";
+  }
+  NET_LOG(ERROR) << "Unknown key management";
+  return "";
+}
+
 arc::mojom::SecurityType TranslateWiFiSecurity(const std::string& type) {
   if (type == shill::kSecurityNone)
     return arc::mojom::SecurityType::NONE;
@@ -350,6 +414,12 @@
   LOG(ERROR) << "ArcVpnErrorCallback: " << operation << ": " << error_name;
 }
 
+void AddPasspointCredentialsFailureCallback(const std::string& error_name,
+                                            const std::string& error_message) {
+  LOG(ERROR) << "Failed to add passpoint credentials, error:" << error_name
+             << ", message: " << error_message;
+}
+
 }  // namespace
 
 namespace arc {
@@ -710,11 +780,19 @@
       chromeos::ConnectCallbackMode::ON_COMPLETED);
 }
 
-std::unique_ptr<base::Value> ArcNetHostImpl::TranslateStringListToValue(
+base::Value ArcNetHostImpl::TranslateStringListToValue(
     const std::vector<std::string>& string_list) {
-  auto result = std::make_unique<base::Value>(base::Value::Type::LIST);
+  base::Value result(base::Value::Type::LIST);
   for (const auto& item : string_list)
-    result->Append(item);
+    result.Append(item);
+  return result;
+}
+
+base::Value ArcNetHostImpl::TranslateLongListToStringValue(
+    const std::vector<uint64_t>& long_list) {
+  base::Value result(base::Value::Type::LIST);
+  for (const auto& item : long_list)
+    result.Append(base::NumberToString(item));
   return result;
 }
 
@@ -744,17 +822,13 @@
   ip_dict->SetKey(onc::ipconfig::kGateway, base::Value(cfg.ipv4_gateway));
 
   ip_dict->SetKey(onc::ipconfig::kNameServers,
-                  base::Value::FromUniquePtrValue(
-                      TranslateStringListToValue(cfg.nameservers)));
-  ip_dict->SetKey(
-      onc::ipconfig::kSearchDomains,
-      base::Value::FromUniquePtrValue(TranslateStringListToValue(cfg.domains)));
+                  TranslateStringListToValue(cfg.nameservers));
+  ip_dict->SetKey(onc::ipconfig::kSearchDomains,
+                  TranslateStringListToValue(cfg.domains));
   ip_dict->SetKey(onc::ipconfig::kIncludedRoutes,
-                  base::Value::FromUniquePtrValue(
-                      TranslateStringListToValue(cfg.split_include)));
+                  TranslateStringListToValue(cfg.split_include));
   ip_dict->SetKey(onc::ipconfig::kExcludedRoutes,
-                  base::Value::FromUniquePtrValue(
-                      TranslateStringListToValue(cfg.split_exclude)));
+                  TranslateStringListToValue(cfg.split_exclude));
 
   top_dict->SetKey(onc::network_config::kStaticIPConfig,
                    base::Value::FromUniquePtrValue(std::move(ip_dict)));
@@ -819,9 +893,94 @@
       base::BindOnce(&ArcVpnErrorCallback, "disconnecting ARC VPN"));
 }
 
+base::Value ArcNetHostImpl::TranslateEapCredentialsToDict(
+    const mojom::EapCredentials& cred) {
+  base::Value dict(base::Value::Type::DICTIONARY);
+
+  dict.SetStringKey(shill::kEapMethodProperty, TranslateEapMethod(cred.method));
+  dict.SetStringKey(shill::kEapPhase2AuthProperty,
+                    TranslateEapPhase2Method(cred.phase2_method));
+  if (cred.anonymous_identity.has_value()) {
+    dict.SetStringKey(shill::kEapAnonymousIdentityProperty,
+                      cred.anonymous_identity.value());
+  }
+  if (cred.identity.has_value()) {
+    dict.SetStringKey(shill::kEapIdentityProperty, cred.identity.value());
+  }
+  if (cred.password.has_value()) {
+    dict.SetStringKey(shill::kEapPasswordProperty, cred.password.value());
+  }
+  dict.SetStringKey(shill::kEapKeyMgmtProperty,
+                    TranslateKeyManagement(cred.key_management));
+  // TODO(195262431): Provision and fill in certificates.
+  if (cred.subject_match.has_value()) {
+    dict.SetStringKey(shill::kEapSubjectMatchProperty,
+                      cred.subject_match.value());
+  }
+  if (cred.subject_alternative_name_match_list.has_value()) {
+    dict.SetKey(shill::kEapSubjectAlternativeNameMatchProperty,
+                TranslateStringListToValue(
+                    cred.subject_alternative_name_match_list.value()));
+  }
+  if (cred.domain_suffix_match_list.has_value()) {
+    dict.SetKey(
+        shill::kEapDomainSuffixMatchProperty,
+        TranslateStringListToValue(cred.domain_suffix_match_list.value()));
+  }
+  if (cred.tls_version_max.has_value()) {
+    dict.SetStringKey(shill::kEapTLSVersionMaxProperty,
+                      cred.tls_version_max.value());
+  }
+  dict.SetBoolKey(shill::kEapUseSystemCasProperty, cred.use_system_cas);
+  dict.SetBoolKey(shill::kEapUseProactiveKeyCachingProperty,
+                  cred.use_proactive_key_caching);
+  dict.SetBoolKey(shill::kEapUseLoginPasswordProperty, cred.use_login_password);
+
+  return dict;
+}
+
+base::Value ArcNetHostImpl::TranslatePasspointCredentialsToDict(
+    const mojom::PasspointCredentials& cred) {
+  // Fill in EAP credentials fields.
+  if (!cred.eap) {
+    LOG(ERROR) << "Failed to get EAP credentials for passpoint credentials";
+  }
+  auto dict = TranslateEapCredentialsToDict(*cred.eap);
+
+  // Fill in Passpoint credentials fields.
+  dict.SetKey(shill::kPasspointCredentialsDomainsProperty,
+              TranslateStringListToValue(cred.domains));
+  dict.SetStringKey(shill::kPasspointCredentialsRealmProperty, cred.realm);
+  dict.SetKey(shill::kPasspointCredentialsHomeOIsProperty,
+              TranslateLongListToStringValue(cred.home_ois));
+  dict.SetKey(shill::kPasspointCredentialsRequiredHomeOIsProperty,
+              TranslateLongListToStringValue(cred.required_home_ois));
+  dict.SetKey(shill::kPasspointCredentialsRoamingConsortiaProperty,
+              TranslateLongListToStringValue(cred.roaming_consortium_ois));
+  dict.SetBoolKey(shill::kPasspointCredentialsMeteredOverrideProperty,
+                  cred.metered);
+  dict.SetStringKey(shill::kPasspointCredentialsAndroidPackageNameProperty,
+                    cred.package_name);
+
+  return dict;
+}
+
 void ArcNetHostImpl::AddPasspointCredentials(
     mojom::PasspointCredentialsPtr credentials) {
-  // TODO(b/195262431) Call shill Manager AddPasspointCredentials method.
+  // TODO(195262431): Support EAP-TLS.
+  if (credentials->eap->method != mojom::EapMethod::kTtls)
+    return;
+
+  const auto properties = TranslatePasspointCredentialsToDict(*credentials);
+  const auto* profile = GetNetworkProfile();
+  if (!profile || profile->path.empty()) {
+    LOG(ERROR) << "Unable to get network profile path";
+    return;
+  }
+
+  ash::ShillManagerClient::Get()->AddPasspointCredentials(
+      dbus::ObjectPath(profile->path), properties, base::DoNothing(),
+      base::BindOnce(&AddPasspointCredentialsFailureCallback));
   return;
 }
 
diff --git a/ash/components/arc/net/arc_net_host_impl.h b/ash/components/arc/net/arc_net_host_impl.h
index c69b3fdc..df599bc3 100644
--- a/ash/components/arc/net/arc_net_host_impl.h
+++ b/ash/components/arc/net/arc_net_host_impl.h
@@ -17,6 +17,7 @@
 #include "base/threading/thread_checker.h"
 #include "base/values.h"
 #include "chromeos/network/network_connection_observer.h"
+#include "chromeos/network/network_profile_handler.h"
 #include "chromeos/network/network_state_handler_observer.h"
 #include "components/arc/mojom/net.mojom.h"
 #include "components/arc/session/connection_observer.h"
@@ -94,7 +95,12 @@
   std::unique_ptr<base::DictionaryValue> TranslateVpnConfigurationToOnc(
       const mojom::AndroidVpnConfiguration& cfg);
 
-  // Overriden from chromeos::NetworkStateHandlerObserver.
+  base::Value TranslateEapCredentialsToDict(const mojom::EapCredentials& cred);
+
+  base::Value TranslatePasspointCredentialsToDict(
+      const mojom::PasspointCredentials& cred);
+
+  // Overridden from chromeos::NetworkStateHandlerObserver.
   void ScanCompleted(const chromeos::DeviceState* /*unused*/) override;
   void OnShuttingDown() override;
   void NetworkConnectionStateChanged(
@@ -103,7 +109,7 @@
   void DeviceListChanged() override;
   void NetworkPropertiesUpdated(const chromeos::NetworkState* network) override;
 
-  // Overriden from chromeos::NetworkConnectionObserver.
+  // Overridden from chromeos::NetworkConnectionObserver.
   void DisconnectRequested(const std::string& service_path) override;
 
   // Overridden from ConnectionObserver<mojom::NetInstance>:
@@ -134,9 +140,17 @@
   // Convert a vector of strings, |string_list|, to a base::Value
   // that can be added to an ONC dictionary.  This is used for fields
   // like NameServers, SearchDomains, etc.
-  std::unique_ptr<base::Value> TranslateStringListToValue(
+  base::Value TranslateStringListToValue(
       const std::vector<std::string>& string_list);
 
+  // Convert a vector of uint64_t, |long_list|, to a base::Value of type list
+  // that can be passed to shill. This is because 64-bit integer values are not
+  // supported for base::Value.
+  // The translated values will be a list of decimal string and not a single
+  // string.
+  base::Value TranslateLongListToStringValue(
+      const std::vector<uint64_t>& long_list);
+
   // Ask Shill to connect to the Android VPN with name |service_path|.
   // |service_path| and |guid| are stored locally for future reference.
   // This is used as the callback from a CreateConfiguration() or
diff --git a/chromeos/attestation/BUILD.gn b/ash/components/attestation/BUILD.gn
similarity index 92%
rename from chromeos/attestation/BUILD.gn
rename to ash/components/attestation/BUILD.gn
index 54747ab..11c3b71 100644
--- a/chromeos/attestation/BUILD.gn
+++ b/ash/components/attestation/BUILD.gn
@@ -2,12 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/chromeos/ui_mode.gni")
 import("//testing/test.gni")
 
-assert(is_chromeos, "Non-Chrome-OS builds must not depend on //chromeos")
+assert(is_chromeos_ash, "Non-Chrome-OS builds must not depend on //ash")
 
 component("attestation") {
-  defines = [ "IS_CHROMEOS_ATTESTATION_IMPL" ]
+  defines = [ "IS_ASH_ATTESTATION_IMPL" ]
   deps = [
     "//base",
     "//chromeos/cryptohome",
diff --git a/chromeos/attestation/DEPS b/ash/components/attestation/DEPS
similarity index 100%
rename from chromeos/attestation/DEPS
rename to ash/components/attestation/DEPS
diff --git a/chromeos/attestation/DIR_METADATA b/ash/components/attestation/DIR_METADATA
similarity index 100%
rename from chromeos/attestation/DIR_METADATA
rename to ash/components/attestation/DIR_METADATA
diff --git a/chromeos/attestation/OWNERS b/ash/components/attestation/OWNERS
similarity index 100%
rename from chromeos/attestation/OWNERS
rename to ash/components/attestation/OWNERS
diff --git a/chromeos/attestation/attestation_flow.cc b/ash/components/attestation/attestation_flow.cc
similarity index 98%
rename from chromeos/attestation/attestation_flow.cc
rename to ash/components/attestation/attestation_flow.cc
index 1df0a18..4068436 100644
--- a/chromeos/attestation/attestation_flow.cc
+++ b/ash/components/attestation/attestation_flow.cc
@@ -2,25 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/attestation/attestation_flow.h"
+#include "ash/components/attestation/attestation_flow.h"
 
 #include <algorithm>
 #include <utility>
 
+#include "ash/components/attestation/attestation_flow_utils.h"
 #include "base/bind.h"
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/timer/timer.h"
-#include "chromeos/attestation/attestation_flow_utils.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/attestation/attestation_client.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
 #include "components/account_id/account_id.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 namespace {
@@ -375,4 +375,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/attestation_flow.h b/ash/components/attestation/attestation_flow.h
similarity index 95%
rename from chromeos/attestation/attestation_flow.h
rename to ash/components/attestation/attestation_flow.h
index 41fab16..fd8878a 100644
--- a/chromeos/attestation/attestation_flow.h
+++ b/ash/components/attestation/attestation_flow.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_ATTESTATION_ATTESTATION_FLOW_H_
-#define CHROMEOS_ATTESTATION_ATTESTATION_FLOW_H_
+#ifndef ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_H_
+#define ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_H_
 
 #include <memory>
 #include <string>
@@ -13,6 +13,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+// TODO(https://crbug.com/1164001): forward declare after it moved to ash.
+#include "chromeos/dbus/attestation/attestation_client.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
 #include "chromeos/dbus/constants/attestation_constants.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
@@ -20,14 +22,11 @@
 
 class AccountId;
 
-namespace chromeos {
-
-class AttestationClient;
-
+namespace ash {
 namespace attestation {
 
 // Interface for access to the Privacy CA server.
-class COMPONENT_EXPORT(CHROMEOS_ATTESTATION) ServerProxy {
+class COMPONENT_EXPORT(ASH_ATTESTATION) ServerProxy {
  public:
   using DataCallback =
       base::OnceCallback<void(bool success, const std::string& data)>;
@@ -59,7 +58,7 @@
 //    flow.GetCertificate(ENTERPRISE_USER_CERTIFICATE, false, callback);
 //
 // This class is not thread safe.
-class COMPONENT_EXPORT(CHROMEOS_ATTESTATION) AttestationFlow {
+class COMPONENT_EXPORT(ASH_ATTESTATION) AttestationFlow {
  public:
   using CertificateCallback =
       base::OnceCallback<void(AttestationStatus status,
@@ -290,15 +289,6 @@
 };
 
 }  // namespace attestation
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove when //chromeos/attestation
-// moved to ash
-namespace ash {
-namespace attestation {
-using ::chromeos::attestation::AttestationFlow;
-using ::chromeos::attestation::ServerProxy;
-}  // namespace attestation
 }  // namespace ash
 
-#endif  // CHROMEOS_ATTESTATION_ATTESTATION_FLOW_H_
+#endif  // ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_H_
diff --git a/chromeos/attestation/attestation_flow_adaptive.cc b/ash/components/attestation/attestation_flow_adaptive.cc
similarity index 97%
rename from chromeos/attestation/attestation_flow_adaptive.cc
rename to ash/components/attestation/attestation_flow_adaptive.cc
index 4f446cd..040eeb9 100644
--- a/chromeos/attestation/attestation_flow_adaptive.cc
+++ b/ash/components/attestation/attestation_flow_adaptive.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/attestation/attestation_flow_adaptive.h"
+#include "ash/components/attestation/attestation_flow_adaptive.h"
 
 #include <memory>
 #include <utility>
@@ -10,7 +10,7 @@
 #include "base/logging.h"
 #include "chromeos/dbus/constants/attestation_constants.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 struct AttestationFlowAdaptive::GetCertificateParams {
@@ -149,4 +149,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/attestation_flow_adaptive.h b/ash/components/attestation/attestation_flow_adaptive.h
similarity index 83%
rename from chromeos/attestation/attestation_flow_adaptive.h
rename to ash/components/attestation/attestation_flow_adaptive.h
index 260e9ef..2ea08d8 100644
--- a/chromeos/attestation/attestation_flow_adaptive.h
+++ b/ash/components/attestation/attestation_flow_adaptive.h
@@ -2,30 +2,29 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_ATTESTATION_ATTESTATION_FLOW_ADAPTIVE_H_
-#define CHROMEOS_ATTESTATION_ATTESTATION_FLOW_ADAPTIVE_H_
+#ifndef ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_ADAPTIVE_H_
+#define ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_ADAPTIVE_H_
 
 #include <memory>
 #include <string>
 
+#include "ash/components/attestation/attestation_flow.h"
+#include "ash/components/attestation/attestation_flow_factory.h"
+#include "ash/components/attestation/attestation_flow_status_reporter.h"
+#include "ash/components/attestation/attestation_flow_type_decider.h"
 #include "base/component_export.h"
 #include "base/memory/weak_ptr.h"
-#include "chromeos/attestation/attestation_flow.h"
-#include "chromeos/attestation/attestation_flow_factory.h"
-#include "chromeos/attestation/attestation_flow_status_reporter.h"
-#include "chromeos/attestation/attestation_flow_type_decider.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
 #include "chromeos/dbus/constants/attestation_constants.h"
 #include "components/account_id/account_id.h"
 
-namespace chromeos {
-
+namespace ash {
 namespace attestation {
 
 // An attestation flow that adaptively chooses the preferred attestation flow
 // object to perform the attestation flow, and falls back to the legacy
 // attestation if the default (platform-side integrated) attestation flow fails.
-class COMPONENT_EXPORT(CHROMEOS_ATTESTATION) AttestationFlowAdaptive
+class COMPONENT_EXPORT(ASH_ATTESTATION) AttestationFlowAdaptive
     : public AttestationFlow {
  public:
   explicit AttestationFlowAdaptive(std::unique_ptr<ServerProxy> server_proxy);
@@ -108,15 +107,6 @@
 };
 
 }  // namespace attestation
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove when //chromeos/attestation
-// moved to ash
-namespace ash {
-namespace attestation {
-using ::chromeos::attestation::AttestationFlowAdaptive;
-using ::chromeos::attestation::ServerProxy;
-}  // namespace attestation
 }  // namespace ash
 
-#endif  // CHROMEOS_ATTESTATION_ATTESTATION_FLOW_ADAPTIVE_H_
+#endif  // ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_ADAPTIVE_H_
diff --git a/chromeos/attestation/attestation_flow_adaptive_unittest.cc b/ash/components/attestation/attestation_flow_adaptive_unittest.cc
similarity index 98%
rename from chromeos/attestation/attestation_flow_adaptive_unittest.cc
rename to ash/components/attestation/attestation_flow_adaptive_unittest.cc
index 1214f27c..ade30c8 100644
--- a/chromeos/attestation/attestation_flow_adaptive_unittest.cc
+++ b/ash/components/attestation/attestation_flow_adaptive_unittest.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/attestation/attestation_flow_adaptive.h"
+#include "ash/components/attestation/attestation_flow_adaptive.h"
 
 #include <utility>
 
+#include "ash/components/attestation/mock_attestation_flow.h"
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chromeos/attestation/mock_attestation_flow.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -20,7 +20,7 @@
 using testing::StrictMock;
 using testing::WithArg;
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 namespace {
@@ -302,4 +302,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/attestation_flow_factory.cc b/ash/components/attestation/attestation_flow_factory.cc
similarity index 82%
rename from chromeos/attestation/attestation_flow_factory.cc
rename to ash/components/attestation/attestation_flow_factory.cc
index db5c656..7833ae0 100644
--- a/chromeos/attestation/attestation_flow_factory.cc
+++ b/ash/components/attestation/attestation_flow_factory.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/attestation/attestation_flow_factory.h"
+#include "ash/components/attestation/attestation_flow_factory.h"
 
 #include <memory>
 #include <utility>
 
-#include "chromeos/attestation/attestation_flow.h"
-#include "chromeos/attestation/attestation_flow_integrated.h"
+#include "ash/components/attestation/attestation_flow.h"
+#include "ash/components/attestation/attestation_flow_integrated.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 AttestationFlowFactory::AttestationFlowFactory() = default;
@@ -42,4 +42,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/attestation_flow_factory.h b/ash/components/attestation/attestation_flow_factory.h
similarity index 84%
rename from chromeos/attestation/attestation_flow_factory.h
rename to ash/components/attestation/attestation_flow_factory.h
index f4b8030..1ba9ae24 100644
--- a/chromeos/attestation/attestation_flow_factory.h
+++ b/ash/components/attestation/attestation_flow_factory.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_ATTESTATION_ATTESTATION_FLOW_FACTORY_H_
-#define CHROMEOS_ATTESTATION_ATTESTATION_FLOW_FACTORY_H_
+#ifndef ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_FACTORY_H_
+#define ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_FACTORY_H_
 
 #include <memory>
 
 #include "base/component_export.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 class AttestationFlow;
@@ -18,7 +18,7 @@
 
 // A factory that creates a default attestation flow we should try first and a
 // fallback solution if necessary.
-class COMPONENT_EXPORT(CHROMEOS_ATTESTATION) AttestationFlowFactory {
+class COMPONENT_EXPORT(ASH_ATTESTATION) AttestationFlowFactory {
  public:
   AttestationFlowFactory();
   virtual ~AttestationFlowFactory();
@@ -48,6 +48,6 @@
 };
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROMEOS_ATTESTATION_ATTESTATION_FLOW_FACTORY_H_
+#endif  // ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_FACTORY_H_
diff --git a/chromeos/attestation/attestation_flow_integrated.cc b/ash/components/attestation/attestation_flow_integrated.cc
similarity index 97%
rename from chromeos/attestation/attestation_flow_integrated.cc
rename to ash/components/attestation/attestation_flow_integrated.cc
index 11d8bea..0604e31 100644
--- a/chromeos/attestation/attestation_flow_integrated.cc
+++ b/ash/components/attestation/attestation_flow_integrated.cc
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/attestation/attestation_flow_integrated.h"
+#include "ash/components/attestation/attestation_flow_integrated.h"
 
 #include <algorithm>
 #include <utility>
 
+#include "ash/components/attestation/attestation_flow_utils.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/logging.h"
@@ -14,7 +15,6 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/timer/timer.h"
-#include "chromeos/attestation/attestation_flow_utils.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/attestation/attestation_client.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
@@ -22,7 +22,7 @@
 #include "components/account_id/account_id.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 namespace {
@@ -215,4 +215,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/attestation_flow_integrated.h b/ash/components/attestation/attestation_flow_integrated.h
similarity index 92%
rename from chromeos/attestation/attestation_flow_integrated.h
rename to ash/components/attestation/attestation_flow_integrated.h
index 22c42af..84e134e 100644
--- a/chromeos/attestation/attestation_flow_integrated.h
+++ b/ash/components/attestation/attestation_flow_integrated.h
@@ -2,18 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_ATTESTATION_ATTESTATION_FLOW_INTEGRATED_H_
-#define CHROMEOS_ATTESTATION_ATTESTATION_FLOW_INTEGRATED_H_
+#ifndef ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_INTEGRATED_H_
+#define ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_INTEGRATED_H_
 
 #include <memory>
 #include <string>
 
+#include "ash/components/attestation/attestation_flow.h"
 #include "base/callback_forward.h"
 #include "base/component_export.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
-#include "chromeos/attestation/attestation_flow.h"
+// TODO(https://crbug.com/1164001): forward declare after it moved to ash.
+#include "chromeos/dbus/attestation/attestation_client.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
 #include "chromeos/dbus/constants/attestation_constants.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
@@ -21,10 +23,7 @@
 
 class AccountId;
 
-namespace chromeos {
-
-class AttestationClient;
-
+namespace ash {
 namespace attestation {
 
 // Implements the message flow for Chrome OS attestation tasks by checking the
@@ -34,7 +33,7 @@
 // removed.
 //
 // Note: This class is not thread safe.
-class COMPONENT_EXPORT(CHROMEOS_ATTESTATION) AttestationFlowIntegrated
+class COMPONENT_EXPORT(ASH_ATTESTATION) AttestationFlowIntegrated
     : public AttestationFlow {
  public:
   AttestationFlowIntegrated();
@@ -150,6 +149,6 @@
 };
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROMEOS_ATTESTATION_ATTESTATION_FLOW_INTEGRATED_H_
+#endif  // ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_INTEGRATED_H_
diff --git a/chromeos/attestation/attestation_flow_integrated_unittest.cc b/ash/components/attestation/attestation_flow_integrated_unittest.cc
similarity index 98%
rename from chromeos/attestation/attestation_flow_integrated_unittest.cc
rename to ash/components/attestation/attestation_flow_integrated_unittest.cc
index ef26451..181a9981 100644
--- a/chromeos/attestation/attestation_flow_integrated_unittest.cc
+++ b/ash/components/attestation/attestation_flow_integrated_unittest.cc
@@ -2,12 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/attestation/attestation_flow_integrated.h"
+#include "ash/components/attestation/attestation_flow_integrated.h"
 
 #include <memory>
 #include <string>
 #include <utility>
 
+#include "ash/components/attestation/attestation_flow_factory.h"
+#include "ash/components/attestation/attestation_flow_utils.h"
+#include "ash/components/attestation/mock_attestation_flow.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/logging.h"
@@ -16,9 +19,6 @@
 #include "base/test/mock_callback.h"
 #include "base/test/task_environment.h"
 #include "base/timer/timer.h"
-#include "chromeos/attestation/attestation_flow_factory.h"
-#include "chromeos/attestation/attestation_flow_utils.h"
-#include "chromeos/attestation/mock_attestation_flow.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/attestation/attestation_client.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
@@ -29,7 +29,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 namespace {
@@ -500,4 +500,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/attestation_flow_status_reporter.cc b/ash/components/attestation/attestation_flow_status_reporter.cc
similarity index 94%
rename from chromeos/attestation/attestation_flow_status_reporter.cc
rename to ash/components/attestation/attestation_flow_status_reporter.cc
index d5db8ec4..e16c0ad 100644
--- a/chromeos/attestation/attestation_flow_status_reporter.cc
+++ b/ash/components/attestation/attestation_flow_status_reporter.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 "chromeos/attestation/attestation_flow_status_reporter.h"
+#include "ash/components/attestation/attestation_flow_status_reporter.h"
 
 #include "base/metrics/histogram_functions.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 namespace {
@@ -65,4 +65,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/attestation_flow_status_reporter.h b/ash/components/attestation/attestation_flow_status_reporter.h
similarity index 84%
rename from chromeos/attestation/attestation_flow_status_reporter.h
rename to ash/components/attestation/attestation_flow_status_reporter.h
index 82551b41..429982e 100644
--- a/chromeos/attestation/attestation_flow_status_reporter.h
+++ b/ash/components/attestation/attestation_flow_status_reporter.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 CHROMEOS_ATTESTATION_ATTESTATION_FLOW_STATUS_REPORTER_H_
-#define CHROMEOS_ATTESTATION_ATTESTATION_FLOW_STATUS_REPORTER_H_
+#ifndef ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_STATUS_REPORTER_H_
+#define ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_STATUS_REPORTER_H_
 
 #include "base/component_export.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 // This class is used to record various attributes and execution results of an
 // adaptive attestation flow instance.
-class COMPONENT_EXPORT(CHROMEOS_ATTESTATION) AttestationFlowStatusReporter {
+class COMPONENT_EXPORT(ASH_ATTESTATION) AttestationFlowStatusReporter {
  public:
   AttestationFlowStatusReporter();
   ~AttestationFlowStatusReporter();
@@ -49,6 +49,6 @@
 };
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROMEOS_ATTESTATION_ATTESTATION_FLOW_STATUS_REPORTER_H_
+#endif  // ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_STATUS_REPORTER_H_
diff --git a/chromeos/attestation/attestation_flow_status_reporter_unittest.cc b/ash/components/attestation/attestation_flow_status_reporter_unittest.cc
similarity index 93%
rename from chromeos/attestation/attestation_flow_status_reporter_unittest.cc
rename to ash/components/attestation/attestation_flow_status_reporter_unittest.cc
index 630d398b..5864aa5 100644
--- a/chromeos/attestation/attestation_flow_status_reporter_unittest.cc
+++ b/ash/components/attestation/attestation_flow_status_reporter_unittest.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/attestation/attestation_flow_status_reporter.h"
+#include "ash/components/attestation/attestation_flow_status_reporter.h"
 
 #include "base/test/metrics/histogram_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 namespace {
@@ -58,4 +58,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/attestation_flow_type_decider.cc b/ash/components/attestation/attestation_flow_type_decider.cc
similarity index 84%
rename from chromeos/attestation/attestation_flow_type_decider.cc
rename to ash/components/attestation/attestation_flow_type_decider.cc
index 4210d8f8..8ff8608 100644
--- a/chromeos/attestation/attestation_flow_type_decider.cc
+++ b/ash/components/attestation/attestation_flow_type_decider.cc
@@ -2,17 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/attestation/attestation_flow_type_decider.h"
+#include "ash/components/attestation/attestation_flow_type_decider.h"
 
 #include <utility>
 
+#include "ash/components/attestation/attestation_flow.h"
+#include "ash/components/attestation/attestation_flow_status_reporter.h"
 #include "base/bind.h"
-#include "chromeos/attestation/attestation_flow.h"
-#include "chromeos/attestation/attestation_flow_status_reporter.h"
 
 #include "base/logging.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 AttestationFlowTypeDecider::AttestationFlowTypeDecider() = default;
@@ -41,4 +41,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/attestation_flow_type_decider.h b/ash/components/attestation/attestation_flow_type_decider.h
similarity index 80%
rename from chromeos/attestation/attestation_flow_type_decider.h
rename to ash/components/attestation/attestation_flow_type_decider.h
index 5308c0fd..5fdd6ba1 100644
--- a/chromeos/attestation/attestation_flow_type_decider.h
+++ b/ash/components/attestation/attestation_flow_type_decider.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_ATTESTATION_ATTESTATION_FLOW_TYPE_DECIDER_H_
-#define CHROMEOS_ATTESTATION_ATTESTATION_FLOW_TYPE_DECIDER_H_
+#ifndef ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_TYPE_DECIDER_H_
+#define ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_TYPE_DECIDER_H_
 
 #include "base/callback_forward.h"
 #include "base/component_export.h"
 #include "base/memory/weak_ptr.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 class AttestationFlowStatusReporter;
@@ -17,7 +17,7 @@
 
 // An object that decides if the default (platform-side integrated) flow is a
 // valid option.
-class COMPONENT_EXPORT(CHROMEOS_ATTESTATION) AttestationFlowTypeDecider {
+class COMPONENT_EXPORT(ASH_ATTESTATION) AttestationFlowTypeDecider {
  public:
   using AttestationFlowTypeCheckCallback =
       base::OnceCallback<void(bool is_integrated_flow_valid)>;
@@ -40,6 +40,6 @@
 };
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROMEOS_ATTESTATION_ATTESTATION_FLOW_TYPE_DECIDER_H_
+#endif  // ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_TYPE_DECIDER_H_
diff --git a/chromeos/attestation/attestation_flow_type_decider_unittest.cc b/ash/components/attestation/attestation_flow_type_decider_unittest.cc
similarity index 93%
rename from chromeos/attestation/attestation_flow_type_decider_unittest.cc
rename to ash/components/attestation/attestation_flow_type_decider_unittest.cc
index 68a49b5..6869d7b 100644
--- a/chromeos/attestation/attestation_flow_type_decider_unittest.cc
+++ b/ash/components/attestation/attestation_flow_type_decider_unittest.cc
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/attestation/attestation_flow_type_decider.h"
+#include "ash/components/attestation/attestation_flow_type_decider.h"
 
 #include <memory>
 #include <utility>
 
+#include "ash/components/attestation/attestation_flow_status_reporter.h"
+#include "ash/components/attestation/mock_attestation_flow.h"
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/run_loop.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chromeos/attestation/attestation_flow_status_reporter.h"
-#include "chromeos/attestation/mock_attestation_flow.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -22,7 +22,7 @@
 using testing::Invoke;
 using testing::StrictMock;
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 class AttestationFlowTypeDeciderTest : public testing::Test {
@@ -101,4 +101,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/attestation_flow_unittest.cc b/ash/components/attestation/attestation_flow_unittest.cc
similarity index 98%
rename from chromeos/attestation/attestation_flow_unittest.cc
rename to ash/components/attestation/attestation_flow_unittest.cc
index 041d236..b1482e9 100644
--- a/chromeos/attestation/attestation_flow_unittest.cc
+++ b/ash/components/attestation/attestation_flow_unittest.cc
@@ -5,6 +5,10 @@
 #include <memory>
 #include <utility>
 
+#include "ash/components/attestation/attestation_flow_factory.h"
+#include "ash/components/attestation/attestation_flow_integrated.h"
+#include "ash/components/attestation/attestation_flow_utils.h"
+#include "ash/components/attestation/mock_attestation_flow.h"
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
@@ -13,10 +17,6 @@
 #include "base/test/task_environment.h"
 #include "base/time/tick_clock.h"
 #include "base/timer/timer.h"
-#include "chromeos/attestation/attestation_flow_factory.h"
-#include "chromeos/attestation/attestation_flow_integrated.h"
-#include "chromeos/attestation/attestation_flow_utils.h"
-#include "chromeos/attestation/mock_attestation_flow.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/attestation/attestation_client.h"
 #include "components/account_id/account_id.h"
@@ -33,7 +33,7 @@
 using testing::StrictMock;
 using testing::WithArgs;
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 namespace {
@@ -1039,4 +1039,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/attestation_flow_utils.cc b/ash/components/attestation/attestation_flow_utils.cc
similarity index 90%
rename from chromeos/attestation/attestation_flow_utils.cc
rename to ash/components/attestation/attestation_flow_utils.cc
index 6d90e12..6cea580 100644
--- a/chromeos/attestation/attestation_flow_utils.cc
+++ b/ash/components/attestation/attestation_flow_utils.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/attestation/attestation_flow_utils.h"
+#include "ash/components/attestation/attestation_flow_utils.h"
 
 #include <string>
 
 #include "base/notreached.h"
 #include "chromeos/dbus/constants/attestation_constants.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 std::string GetKeyNameForProfile(
@@ -32,4 +32,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/attestation_flow_utils.h b/ash/components/attestation/attestation_flow_utils.h
similarity index 78%
rename from chromeos/attestation/attestation_flow_utils.h
rename to ash/components/attestation/attestation_flow_utils.h
index c7edbea3..e1c5156 100644
--- a/chromeos/attestation/attestation_flow_utils.h
+++ b/ash/components/attestation/attestation_flow_utils.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_ATTESTATION_ATTESTATION_FLOW_UTILS_H_
-#define CHROMEOS_ATTESTATION_ATTESTATION_FLOW_UTILS_H_
+#ifndef ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_UTILS_H_
+#define ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_UTILS_H_
 
 #include <string>
 
 #include "base/component_export.h"
 #include "chromeos/dbus/constants/attestation_constants.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 // Returns the name of the key for a given certificate profile. The
@@ -22,12 +22,12 @@
 //   request_origin - For content protection profiles, certificate requests
 //                    are origin-specific.  This string must uniquely identify
 //                    the origin of the request.
-COMPONENT_EXPORT(CHROMEOS_ATTESTATION)
+COMPONENT_EXPORT(ASH_ATTESTATION)
 std::string GetKeyNameForProfile(
     AttestationCertificateProfile certificate_profile,
     const std::string& request_origin);
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROMEOS_ATTESTATION_ATTESTATION_FLOW_UTILS_H_
+#endif  // ASH_COMPONENTS_ATTESTATION_ATTESTATION_FLOW_UTILS_H_
diff --git a/chromeos/attestation/attestation_flow_utils_unittest.cc b/ash/components/attestation/attestation_flow_utils_unittest.cc
similarity index 90%
rename from chromeos/attestation/attestation_flow_utils_unittest.cc
rename to ash/components/attestation/attestation_flow_utils_unittest.cc
index 2e1868f..a71e8be 100644
--- a/chromeos/attestation/attestation_flow_utils_unittest.cc
+++ b/ash/components/attestation/attestation_flow_utils_unittest.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/attestation/attestation_flow_utils.h"
+#include "ash/components/attestation/attestation_flow_utils.h"
 
 #include <string>
 
 #include "chromeos/dbus/constants/attestation_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 namespace {
@@ -34,4 +34,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/fake_attestation_flow.cc b/ash/components/attestation/fake_attestation_flow.cc
similarity index 92%
rename from chromeos/attestation/fake_attestation_flow.cc
rename to ash/components/attestation/fake_attestation_flow.cc
index 0954d4b..a33f8ef 100644
--- a/chromeos/attestation/fake_attestation_flow.cc
+++ b/ash/components/attestation/fake_attestation_flow.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/attestation/fake_attestation_flow.h"
+#include "ash/components/attestation/fake_attestation_flow.h"
 
 #include <string>
 #include <utility>
@@ -12,7 +12,7 @@
 #include "chromeos/dbus/constants/attestation_constants.h"
 #include "components/account_id/account_id.h"
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 namespace {
@@ -45,4 +45,4 @@
 }
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/fake_attestation_flow.h b/ash/components/attestation/fake_attestation_flow.h
similarity index 73%
rename from chromeos/attestation/fake_attestation_flow.h
rename to ash/components/attestation/fake_attestation_flow.h
index 467c833..e6466c9 100644
--- a/chromeos/attestation/fake_attestation_flow.h
+++ b/ash/components/attestation/fake_attestation_flow.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_ATTESTATION_FAKE_ATTESTATION_FLOW_H_
-#define CHROMEOS_ATTESTATION_FAKE_ATTESTATION_FLOW_H_
+#ifndef ASH_COMPONENTS_ATTESTATION_FAKE_ATTESTATION_FLOW_H_
+#define ASH_COMPONENTS_ATTESTATION_FAKE_ATTESTATION_FLOW_H_
 
 #include <string>
 
-#include "chromeos/attestation/attestation_flow.h"
+#include "ash/components/attestation/attestation_flow.h"
 
 class AccountId;
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 // This fake class always returns a fake certificate.
@@ -29,6 +29,6 @@
 };
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROMEOS_ATTESTATION_FAKE_ATTESTATION_FLOW_H_
+#endif  // ASH_COMPONENTS_ATTESTATION_FAKE_ATTESTATION_FLOW_H_
diff --git a/chromeos/attestation/mock_attestation_flow.cc b/ash/components/attestation/mock_attestation_flow.cc
similarity index 94%
rename from chromeos/attestation/mock_attestation_flow.cc
rename to ash/components/attestation/mock_attestation_flow.cc
index 7de121f..cac6fc8 100644
--- a/chromeos/attestation/mock_attestation_flow.cc
+++ b/ash/components/attestation/mock_attestation_flow.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/attestation/mock_attestation_flow.h"
+#include "ash/components/attestation/mock_attestation_flow.h"
 
 #include <memory>
 
@@ -12,7 +12,7 @@
 using testing::DefaultValue;
 using testing::Invoke;
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 FakeServerProxy::FakeServerProxy() : result_(true) {}
@@ -60,4 +60,4 @@
 MockAttestationFlow::~MockAttestationFlow() = default;
 
 }  // namespace attestation
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/attestation/mock_attestation_flow.h b/ash/components/attestation/mock_attestation_flow.h
similarity index 84%
rename from chromeos/attestation/mock_attestation_flow.h
rename to ash/components/attestation/mock_attestation_flow.h
index e5eaa266..388c59c0b 100644
--- a/chromeos/attestation/mock_attestation_flow.h
+++ b/ash/components/attestation/mock_attestation_flow.h
@@ -2,19 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_ATTESTATION_MOCK_ATTESTATION_FLOW_H_
-#define CHROMEOS_ATTESTATION_MOCK_ATTESTATION_FLOW_H_
+#ifndef ASH_COMPONENTS_ATTESTATION_MOCK_ATTESTATION_FLOW_H_
+#define ASH_COMPONENTS_ATTESTATION_MOCK_ATTESTATION_FLOW_H_
 
 #include <string>
 
-#include "chromeos/attestation/attestation_flow.h"
-
+#include "ash/components/attestation/attestation_flow.h"
 #include "base/callback.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 class AccountId;
 
-namespace chromeos {
+namespace ash {
 namespace attestation {
 
 // A fake server proxy which just appends "_response" to every request if no
@@ -97,14 +96,6 @@
 };
 
 }  // namespace attestation
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove when //chromeos/attestation
-// moved to ash
-namespace ash {
-namespace attestation {
-using ::chromeos::attestation::MockAttestationFlow;
-}  // namespace attestation
 }  // namespace ash
 
-#endif  // CHROMEOS_ATTESTATION_MOCK_ATTESTATION_FLOW_H_
+#endif  // ASH_COMPONENTS_ATTESTATION_MOCK_ATTESTATION_FLOW_H_
diff --git a/ash/components/drivefs/BUILD.gn b/ash/components/drivefs/BUILD.gn
index 86df647..a7008236 100644
--- a/ash/components/drivefs/BUILD.gn
+++ b/ash/components/drivefs/BUILD.gn
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/chromeos/ui_mode.gni")
-import("//chromeos/dbus/use_real_dbus_clients.gni")
+import("//chromeos/dbus/config/use_real_dbus_clients.gni")
 
 assert(is_chromeos_ash, "Non-ChromeOS builds cannot depend on //ash")
 
diff --git a/ash/components/fwupd/BUILD.gn b/ash/components/fwupd/BUILD.gn
index b3c5d9c..2af6b318a 100644
--- a/ash/components/fwupd/BUILD.gn
+++ b/ash/components/fwupd/BUILD.gn
@@ -26,8 +26,11 @@
 
   deps = [
     ":fwupd",
+    "//ash/constants",
+    "//base/test:test_support",
     "//chromeos/dbus/fwupd",
     "//dbus:test_support",
+    "//testing/gmock",
     "//testing/gtest",
   ]
 
diff --git a/ash/components/fwupd/firmware_update_manager.cc b/ash/components/fwupd/firmware_update_manager.cc
index 4d0aefc..fd05f44 100644
--- a/ash/components/fwupd/firmware_update_manager.cc
+++ b/ash/components/fwupd/firmware_update_manager.cc
@@ -5,6 +5,7 @@
 #include "ash/components/fwupd/firmware_update_manager.h"
 
 #include "base/check_op.h"
+#include "base/containers/contains.h"
 #include "chromeos/dbus/fwupd/fwupd_client.h"
 #include "dbus/message.h"
 
@@ -16,6 +17,14 @@
 
 }  // namespace
 
+FirmwareUpdateManager::FirmwareUpdate::FirmwareUpdate() = default;
+FirmwareUpdateManager::FirmwareUpdate::FirmwareUpdate(FirmwareUpdate&& other) =
+    default;
+FirmwareUpdateManager::FirmwareUpdate&
+FirmwareUpdateManager::FirmwareUpdate::operator=(FirmwareUpdate&& other) =
+    default;
+FirmwareUpdateManager::FirmwareUpdate::~FirmwareUpdate() = default;
+
 FirmwareUpdateManager::FirmwareUpdateManager() {
   DCHECK(chromeos::FwupdClient::Get());
   chromeos::FwupdClient::Get()->AddObserver(this);
@@ -36,6 +45,12 @@
   return g_instance;
 }
 
+// Query all updates for all devices.
+void FirmwareUpdateManager::RequestAllUpdates() {
+  DCHECK(devices_pending_update_.empty());
+  RequestDevices();
+}
+
 void FirmwareUpdateManager::RequestDevices() {
   chromeos::FwupdClient::Get()->RequestDevices();
 }
@@ -47,16 +62,47 @@
 void FirmwareUpdateManager::OnDeviceListResponse(
     chromeos::FwupdDeviceList* devices) {
   DCHECK(devices);
-  // TODO(swifton): This is a stub implementation.
-  ++on_device_list_response_count_for_testing_;
+  DCHECK(devices_pending_update_.empty());
+
+  // TODO(zentaro): When mojo is implemented, fire the observer with an empty
+  // list if there are no devices in the response.
+  for (const auto& device : *devices) {
+    devices_pending_update_[device.id] = device;
+    RequestUpdates(device.id);
+  }
 }
 
 void FirmwareUpdateManager::OnUpdateListResponse(
     const std::string& device_id,
     chromeos::FwupdUpdateList* updates) {
   DCHECK(updates);
-  // TODO(swifton): This is a stub implementation.
-  ++on_update_list_response_count_for_testing_;
+  DCHECK(base::Contains(devices_pending_update_, device_id));
+
+  // If there are updates, then choose the first one.
+  if (!updates->empty()) {
+    const chromeos::FwupdUpdate& update_details = updates->front();
+
+    // Create a complete FirmwareUpdate and add to updates_.
+    FirmwareUpdate update;
+    update.device_id = device_id;
+    update.device_name = devices_pending_update_[device_id].device_name;
+    update.version = update_details.version;
+    update.description = update_details.description;
+    update.priority = update_details.priority;
+    updates_.push_back(std::move(update));
+  }
+
+  // Remove the pending device.
+  devices_pending_update_.erase(device_id);
+
+  // TODO(zentaro): When mojo is implemented, fire the observer with `updates_`
+  // if there are no more devices pending an update.
+}
+
+const std::vector<FirmwareUpdateManager::FirmwareUpdate>&
+FirmwareUpdateManager::GetCachedUpdatesForTesting() {
+  DCHECK(devices_pending_update_.empty());
+  return updates_;
 }
 
 }  // namespace ash
diff --git a/ash/components/fwupd/firmware_update_manager.h b/ash/components/fwupd/firmware_update_manager.h
index 082f0a3..7505e05 100644
--- a/ash/components/fwupd/firmware_update_manager.h
+++ b/ash/components/fwupd/firmware_update_manager.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/component_export.h"
+#include "base/containers/flat_map.h"
 #include "chromeos/dbus/fwupd/fwupd_client.h"
 #include "chromeos/dbus/fwupd/fwupd_device.h"
 #include "chromeos/dbus/fwupd/fwupd_update.h"
@@ -17,6 +18,20 @@
 class COMPONENT_EXPORT(ASH_FIRMWARE_UPDATE_MANAGER) FirmwareUpdateManager
     : public chromeos::FwupdClient::Observer {
  public:
+  // TODO(zentaro): Replace this struct with mojo struct when implemented.
+  struct FirmwareUpdate {
+    FirmwareUpdate();
+    FirmwareUpdate(FirmwareUpdate&& other);
+    FirmwareUpdate& operator=(FirmwareUpdate&& other);
+    ~FirmwareUpdate();
+
+    std::string device_id;
+    std::string device_name;
+    std::string version;
+    std::string description;
+    uint32_t priority;
+  };
+
   FirmwareUpdateManager();
   FirmwareUpdateManager(const FirmwareUpdateManager&) = delete;
   FirmwareUpdateManager& operator=(const FirmwareUpdateManager&) = delete;
@@ -35,18 +50,27 @@
   void OnUpdateListResponse(const std::string& device_id,
                             chromeos::FwupdUpdateList* updates) override;
 
+  // Query all updates for all devices.
+  void RequestAllUpdates();
+
+  // Get the currently cached set of updates.
+  // TODO(zentaro): Remove once mojo api fires observers.
+  const std::vector<FirmwareUpdate>& GetCachedUpdatesForTesting();
+
+ private:
   // Query the fwupd DBus client for currently connected devices.
   void RequestDevices();
 
   // Query the fwupd DBus client for updates for a certain device.
   void RequestUpdates(const std::string& device_id);
 
- protected:
-  friend class FirmwareUpdateManagerTest;
-  // Temporary auxiliary variables for testing.
-  // TODO(swifton): Replace with mock observers.
-  int on_device_list_response_count_for_testing_ = 0;
-  int on_update_list_response_count_for_testing_ = 0;
+  // Map of a device ID to `FwupdDevice` which is waiting for the list
+  // of updates.
+  base::flat_map<std::string, chromeos::FwupdDevice> devices_pending_update_;
+
+  // List of all available updates. If `devices_pending_update_` is not
+  // empty then this list is not yet complete.
+  std::vector<FirmwareUpdate> updates_;
 };
 }  // namespace ash
 
diff --git a/ash/components/fwupd/firmware_update_manager_unittest.cc b/ash/components/fwupd/firmware_update_manager_unittest.cc
index 284c3c18..90c14da 100644
--- a/ash/components/fwupd/firmware_update_manager_unittest.cc
+++ b/ash/components/fwupd/firmware_update_manager_unittest.cc
@@ -4,52 +4,324 @@
 
 #include "ash/components/fwupd/firmware_update_manager.h"
 
+#include <deque>
 #include <memory>
 
-#include "chromeos/dbus/fwupd/fake_fwupd_client.h"
+#include "ash/constants/ash_features.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "chromeos/dbus/fwupd/fwupd_client.h"
+#include "dbus/message.h"
+#include "dbus/mock_bus.h"
+#include "dbus/mock_object_proxy.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
 
-const char kFakeDeviceIdForTesting[] = "0123";
+const char kFakeDeviceIdForTesting[] = "Fake Device ID";
+const char kFakeDeviceNameForTesting[] = "Fake Device Name";
+const char kFakeUpdateDescriptionForTesting[] =
+    "This is a fake update for testing.";
+const uint32_t kFakeUpdatePriorityForTesting = 1;
+const char kFakeUpdateVersionForTesting[] = "1.0.0";
+const char kFwupdServiceName[] = "org.freedesktop.fwupd";
+const char kFwupdServicePath[] = "/";
+const char kDescriptionKey[] = "Description";
+const char kIdKey[] = "DeviceId";
+const char kNameKey[] = "Name";
+const char kPriorityKey[] = "Urgency";
+const char kVersionKey[] = "Version";
+
+void RunResponseCallback(dbus::ObjectProxy::ResponseOrErrorCallback callback,
+                         std::unique_ptr<dbus::Response> response) {
+  std::move(callback).Run(response.get(), nullptr);
+}
 
 }  // namespace
 
+using chromeos::FwupdClient;
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::Return;
+
 namespace ash {
 
 class FirmwareUpdateManagerTest : public testing::Test {
  public:
-  FirmwareUpdateManagerTest() {}
+  FirmwareUpdateManagerTest() {
+    scoped_feature_list_.InitAndEnableFeature(
+        ::ash::features::kFirmwareUpdaterApp);
+
+    dbus::Bus::Options options;
+    options.bus_type = dbus::Bus::SYSTEM;
+    bus_ = base::MakeRefCounted<dbus::MockBus>(options);
+
+    dbus::ObjectPath fwupd_service_path(kFwupdServicePath);
+    proxy_ = base::MakeRefCounted<dbus::MockObjectProxy>(
+        bus_.get(), kFwupdServiceName, fwupd_service_path);
+
+    EXPECT_CALL(*bus_.get(),
+                GetObjectProxy(kFwupdServiceName, fwupd_service_path))
+        .WillRepeatedly(testing::Return(proxy_.get()));
+
+    EXPECT_CALL(*proxy_, DoConnectToSignal(kFwupdServiceName, _, _, _))
+        .WillRepeatedly(Return());
+
+    dbus_client_ = FwupdClient::Create();
+    dbus_client_->InitForTesting(bus_.get());
+    firmware_update_manager_ = std::make_unique<FirmwareUpdateManager>();
+  }
   FirmwareUpdateManagerTest(const FirmwareUpdateManagerTest&) = delete;
   FirmwareUpdateManagerTest& operator=(const FirmwareUpdateManagerTest&) =
       delete;
   ~FirmwareUpdateManagerTest() override = default;
 
-  int GetOnDevicesResponseCallbackCallCountForTesting() {
-    return firmware_update_manager_.on_device_list_response_count_for_testing_;
+  void OnMethodCalled(dbus::MethodCall* method_call,
+                      int timeout_ms,
+                      dbus::ObjectProxy::ResponseOrErrorCallback* callback) {
+    ASSERT_FALSE(dbus_responses_.empty());
+    auto response = std::move(dbus_responses_.front());
+    task_environment_.GetMainThreadTaskRunner()->PostTask(
+        FROM_HERE, base::BindOnce(&RunResponseCallback, std::move(*callback),
+                                  std::move(response)));
+    dbus_responses_.pop_front();
   }
 
-  int GetOnUpdatesResponseCallbackCallCountForTesting() {
-    return firmware_update_manager_.on_update_list_response_count_for_testing_;
+ protected:
+  std::unique_ptr<dbus::Response> CreateEmptyDeviceResponse() {
+    auto response = dbus::Response::CreateEmpty();
+
+    dbus::MessageWriter response_writer(response.get());
+    dbus::MessageWriter response_array_writer(nullptr);
+    dbus::MessageWriter device_array_writer(nullptr);
+
+    // The response is an array of arrays of dictionaries. Each dictionary is
+    // one device description.
+    response_writer.OpenArray("a{sv}", &response_array_writer);
+    response_array_writer.OpenArray("{sv}", &device_array_writer);
+
+    response_array_writer.CloseContainer(&device_array_writer);
+    response_writer.CloseContainer(&response_array_writer);
+
+    return response;
   }
 
-  chromeos::FakeFwupdClient dbus_client_;
-  FirmwareUpdateManager firmware_update_manager_;
+  std::unique_ptr<dbus::Response> CreateOneDeviceResponse() {
+    auto response = dbus::Response::CreateEmpty();
+
+    dbus::MessageWriter response_writer(response.get());
+    dbus::MessageWriter response_array_writer(nullptr);
+    dbus::MessageWriter device_array_writer(nullptr);
+    dbus::MessageWriter dict_writer(nullptr);
+
+    // The response is an array of arrays of dictionaries. Each dictionary is
+    // one device description.
+    response_writer.OpenArray("a{sv}", &response_array_writer);
+    response_array_writer.OpenArray("{sv}", &device_array_writer);
+
+    device_array_writer.OpenDictEntry(&dict_writer);
+    dict_writer.AppendString(kNameKey);
+    dict_writer.AppendVariantOfString(kFakeDeviceNameForTesting);
+    device_array_writer.CloseContainer(&dict_writer);
+
+    device_array_writer.OpenDictEntry(&dict_writer);
+    dict_writer.AppendString(kIdKey);
+    dict_writer.AppendVariantOfString(kFakeDeviceIdForTesting);
+    device_array_writer.CloseContainer(&dict_writer);
+
+    response_array_writer.CloseContainer(&device_array_writer);
+    response_writer.CloseContainer(&response_array_writer);
+
+    return response;
+  }
+
+  std::unique_ptr<dbus::Response> CreateTwoDeviceResponse() {
+    auto response = dbus::Response::CreateEmpty();
+
+    dbus::MessageWriter response_writer(response.get());
+    dbus::MessageWriter response_array_writer(nullptr);
+    dbus::MessageWriter device_array_writer(nullptr);
+    dbus::MessageWriter dict_writer(nullptr);
+
+    // The response is an array of arrays of dictionaries. Each dictionary is
+    // one device description.
+    response_writer.OpenArray("a{sv}", &response_array_writer);
+    response_array_writer.OpenArray("{sv}", &device_array_writer);
+
+    device_array_writer.OpenDictEntry(&dict_writer);
+    dict_writer.AppendString(kNameKey);
+    dict_writer.AppendVariantOfString(std::string(kFakeDeviceNameForTesting) +
+                                      "1");
+    device_array_writer.CloseContainer(&dict_writer);
+
+    device_array_writer.OpenDictEntry(&dict_writer);
+    dict_writer.AppendString(kIdKey);
+    dict_writer.AppendVariantOfString(std::string(kFakeDeviceIdForTesting) +
+                                      "1");
+    device_array_writer.CloseContainer(&dict_writer);
+
+    // Prepare the next device entry.
+    response_array_writer.CloseContainer(&device_array_writer);
+    response_array_writer.OpenArray("{sv}", &device_array_writer);
+
+    device_array_writer.OpenDictEntry(&dict_writer);
+    dict_writer.AppendString(kNameKey);
+    dict_writer.AppendVariantOfString(std::string(kFakeDeviceNameForTesting) +
+                                      "2");
+    device_array_writer.CloseContainer(&dict_writer);
+
+    device_array_writer.OpenDictEntry(&dict_writer);
+    dict_writer.AppendString(kIdKey);
+    dict_writer.AppendVariantOfString(std::string(kFakeDeviceIdForTesting) +
+                                      "2");
+    device_array_writer.CloseContainer(&dict_writer);
+
+    response_array_writer.CloseContainer(&device_array_writer);
+    response_writer.CloseContainer(&response_array_writer);
+
+    return response;
+  }
+
+  std::unique_ptr<dbus::Response> CreateOneUpdateResponse() {
+    auto response = dbus::Response::CreateEmpty();
+
+    dbus::MessageWriter response_writer(response.get());
+    dbus::MessageWriter response_array_writer(nullptr);
+    dbus::MessageWriter device_array_writer(nullptr);
+    dbus::MessageWriter dict_writer(nullptr);
+
+    // The response is an array of arrays of dictionaries. Each dictionary is
+    // one device description.
+    response_writer.OpenArray("a{sv}", &response_array_writer);
+    response_array_writer.OpenArray("{sv}", &device_array_writer);
+
+    device_array_writer.OpenDictEntry(&dict_writer);
+    dict_writer.AppendString(kDescriptionKey);
+    dict_writer.AppendVariantOfString(kFakeUpdateDescriptionForTesting);
+    device_array_writer.CloseContainer(&dict_writer);
+
+    device_array_writer.OpenDictEntry(&dict_writer);
+    dict_writer.AppendString(kVersionKey);
+    dict_writer.AppendVariantOfString(kFakeUpdateVersionForTesting);
+    device_array_writer.CloseContainer(&dict_writer);
+
+    device_array_writer.OpenDictEntry(&dict_writer);
+    dict_writer.AppendString(kPriorityKey);
+    dict_writer.AppendVariantOfUint32(kFakeUpdatePriorityForTesting);
+    device_array_writer.CloseContainer(&dict_writer);
+
+    response_array_writer.CloseContainer(&device_array_writer);
+    response_writer.CloseContainer(&response_array_writer);
+
+    return response;
+  }
+
+  std::unique_ptr<dbus::Response> CreateNoUpdateResponse() {
+    auto response = dbus::Response::CreateEmpty();
+
+    dbus::MessageWriter response_writer(response.get());
+    dbus::MessageWriter response_array_writer(nullptr);
+    dbus::MessageWriter device_array_writer(nullptr);
+
+    // The response is an array of arrays of dictionaries. Each dictionary is
+    // one device description.
+    response_writer.OpenArray("a{sv}", &response_array_writer);
+    response_array_writer.OpenArray("{sv}", &device_array_writer);
+
+    response_array_writer.CloseContainer(&device_array_writer);
+    response_writer.CloseContainer(&response_array_writer);
+
+    return response;
+  }
+
+  // `FwupdClient` must be be before `FirmwareUpdateManager`.
+  std::unique_ptr<FwupdClient> dbus_client_;
+  std::unique_ptr<FirmwareUpdateManager> firmware_update_manager_;
+
+  // Mock bus for simulating calls.
+  scoped_refptr<dbus::MockBus> bus_;
+  scoped_refptr<dbus::MockObjectProxy> proxy_;
+
+  // Fake responses.
+  std::deque<std::unique_ptr<dbus::Response>> dbus_responses_;
+
+  base::test::SingleThreadTaskEnvironment task_environment_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-// TODO(swifton): Rewrite this test with an observer.
-TEST_F(FirmwareUpdateManagerTest, RequestDeviceList) {
-  // FirmwareUpdateManager requests devices when it is created.
-  EXPECT_EQ(0, GetOnDevicesResponseCallbackCallCountForTesting());
-  firmware_update_manager_.RequestDevices();
-  EXPECT_EQ(1, GetOnDevicesResponseCallbackCallCountForTesting());
+TEST_F(FirmwareUpdateManagerTest, CorrectMockInstance) {
+  EXPECT_EQ(dbus_client_.get(), FwupdClient::Get());
 }
 
-// TODO(swifton): Rewrite this test with an observer.
-TEST_F(FirmwareUpdateManagerTest, RequestUpdateList) {
-  EXPECT_EQ(0, GetOnUpdatesResponseCallbackCallCountForTesting());
-  firmware_update_manager_.RequestUpdates(kFakeDeviceIdForTesting);
-  EXPECT_EQ(1, GetOnUpdatesResponseCallbackCallCountForTesting());
+TEST_F(FirmwareUpdateManagerTest, RequestAllUpdatesNoDevices) {
+  EXPECT_CALL(*proxy_, DoCallMethodWithErrorResponse(_, _, _))
+      .WillRepeatedly(Invoke(this, &FirmwareUpdateManagerTest::OnMethodCalled));
+
+  dbus_responses_.push_back(CreateEmptyDeviceResponse());
+  firmware_update_manager_->RequestAllUpdates();
+  const std::vector<FirmwareUpdateManager::FirmwareUpdate>& updates =
+      firmware_update_manager_->GetCachedUpdatesForTesting();
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(updates.empty());
+}
+
+TEST_F(FirmwareUpdateManagerTest, RequestAllUpdatesOneDeviceNoUpdates) {
+  EXPECT_CALL(*proxy_, DoCallMethodWithErrorResponse(_, _, _))
+      .WillRepeatedly(Invoke(this, &FirmwareUpdateManagerTest::OnMethodCalled));
+
+  dbus_responses_.push_back(CreateOneDeviceResponse());
+  dbus_responses_.push_back(CreateNoUpdateResponse());
+  firmware_update_manager_->RequestAllUpdates();
+  const std::vector<FirmwareUpdateManager::FirmwareUpdate>& updates =
+      firmware_update_manager_->GetCachedUpdatesForTesting();
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(updates.empty());
+}
+
+TEST_F(FirmwareUpdateManagerTest, RequestAllUpdatesOneDeviceOneUpdate) {
+  EXPECT_CALL(*proxy_, DoCallMethodWithErrorResponse(_, _, _))
+      .WillRepeatedly(Invoke(this, &FirmwareUpdateManagerTest::OnMethodCalled));
+
+  dbus_responses_.push_back(CreateOneDeviceResponse());
+  dbus_responses_.push_back(CreateOneUpdateResponse());
+  firmware_update_manager_->RequestAllUpdates();
+  const std::vector<FirmwareUpdateManager::FirmwareUpdate>& updates =
+      firmware_update_manager_->GetCachedUpdatesForTesting();
+
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(1U, updates.size());
+
+  EXPECT_EQ(kFakeDeviceIdForTesting, updates[0].device_id);
+  EXPECT_EQ(kFakeDeviceNameForTesting, updates[0].device_name);
+  EXPECT_EQ(kFakeUpdateVersionForTesting, updates[0].version);
+  EXPECT_EQ(kFakeUpdateDescriptionForTesting, updates[0].description);
+  EXPECT_EQ(kFakeUpdatePriorityForTesting, updates[0].priority);
+}
+
+TEST_F(FirmwareUpdateManagerTest, RequestAllUpdatesTwoDeviceOneWithUpdate) {
+  EXPECT_CALL(*proxy_, DoCallMethodWithErrorResponse(_, _, _))
+      .WillRepeatedly(Invoke(this, &FirmwareUpdateManagerTest::OnMethodCalled));
+
+  dbus_responses_.push_back(CreateTwoDeviceResponse());
+  dbus_responses_.push_back(CreateNoUpdateResponse());
+  dbus_responses_.push_back(CreateOneUpdateResponse());
+  firmware_update_manager_->RequestAllUpdates();
+  const std::vector<FirmwareUpdateManager::FirmwareUpdate>& updates =
+      firmware_update_manager_->GetCachedUpdatesForTesting();
+
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(1U, updates.size());
+
+  // The second device was the one with the update.
+  EXPECT_EQ(std::string(kFakeDeviceIdForTesting) + "2", updates[0].device_id);
+  EXPECT_EQ(std::string(kFakeDeviceNameForTesting) + "2",
+            updates[0].device_name);
+  EXPECT_EQ(kFakeUpdateVersionForTesting, updates[0].version);
+  EXPECT_EQ(kFakeUpdateDescriptionForTesting, updates[0].description);
+  EXPECT_EQ(kFakeUpdatePriorityForTesting, updates[0].priority);
 }
 
 }  // namespace ash
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 3be2928..9a879de 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -291,6 +291,9 @@
                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables or disables Crostini GPU support.
+// Note that this feature can be overridden by login_manager based on
+// whether a per-board build sets the USE virtio_gpu flag.
+// Refer to: chromiumos/src/platform2/login_manager/chrome_setup.cc
 const base::Feature kCrostiniGpuSupport{"CrostiniGpuSupport",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -674,14 +677,14 @@
 // transfer or access it later.
 const base::Feature kHoldingSpaceInProgressDownloadsIntegration{
     "HoldingSpaceInProgressDownloadsIntegration",
-    base::FEATURE_ENABLED_BY_DEFAULT};
+    base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Enables in-progress downloads notification suppression with the productivity
 // feature that aims to reduce context switching by enabling users to collect
 // content and transfer or access it later.
 const base::Feature kHoldingSpaceInProgressDownloadsNotificationSuppression{
     "HoldingSpaceInProgressNotificationSuppression",
-    base::FEATURE_ENABLED_BY_DEFAULT};
+    base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Enables incognito profile integration with the productivity feature that
 // aims to reduce context switching by enabling users to collect content and
@@ -694,6 +697,10 @@
 const base::Feature kSnoopingProtection{"SnoopingProtection",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Controls whether the HPS Sense prototype is enabled.
+const base::Feature kLeaveDetection{"LeaveDetection",
+                                    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enable or disable MOZC IME to use protobuf as interactive message format.
 const base::Feature kImeMozcProto{"ImeMozcProto",
                                   base::FEATURE_ENABLED_BY_DEFAULT};
@@ -1512,6 +1519,10 @@
   return base::FeatureList::IsEnabled(kSnoopingProtection);
 }
 
+bool IsLeaveDetectionEnabled() {
+  return base::FeatureList::IsEnabled(kLeaveDetection);
+}
+
 bool IsIdleInhibitEnabled() {
   return base::FeatureList::IsEnabled(kEnableIdleInhibit);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 7bd3dd9..c97aa99 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -263,6 +263,8 @@
     kHoldingSpaceInProgressDownloadsNotificationSuppression;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kHoldingSpaceIncognitoProfileIntegration;
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kLeaveDetection;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kImeMozcProto;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kImeOptionsInSettings;
@@ -540,6 +542,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsHoldingSpaceIncognitoProfileIntegrationEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHostnameSettingEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsLeaveDetectionEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsIdleInhibitEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsImprovedDesksKeyboardShortcutsEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsInputInDiagnosticsAppEnabled();
diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc
index 3a1e899..fa226f5 100644
--- a/ash/drag_drop/drag_drop_controller.cc
+++ b/ash/drag_drop/drag_drop_controller.cc
@@ -87,7 +87,6 @@
                    aura::client::DragUpdateInfo& drag_info,
                    base::OnceClosure drop_cb) {
   DCHECK(drag_data);
-
   if (ui::DataTransferPolicyController::HasInstance()) {
     ui::DataTransferPolicyController::Get()->DropIfAllowed(
         drag_data->GetSource(), &drag_info.data_endpoint, std::move(drop_cb));
@@ -319,13 +318,16 @@
     event->StopPropagation();
     return;
   }
-
+  // If the event ET_MOUSE_RELEASED is received we must allow the event
+  // to propagate so that the target window eventually releases capture.
+  bool stop_propagation = true;
   auto translated_event = ConvertEvent(translated_target, *event);
   switch (translated_event->type()) {
     case ui::ET_MOUSE_DRAGGED:
       DragUpdate(translated_target, *translated_event.get());
       break;
     case ui::ET_MOUSE_RELEASED:
+      stop_propagation = false;
       Drop(translated_target, *translated_event.get());
       break;
     default:
@@ -342,7 +344,8 @@
     toplevel_window_drag_delegate_->OnToplevelWindowDragEvent(
         translated_event.get());
 
-  event->StopPropagation();
+  if (stop_propagation)
+    event->StopPropagation();
 }
 
 void DragDropController::OnTouchEvent(ui::TouchEvent* event) {
diff --git a/ash/drag_drop/drag_drop_controller_unittest.cc b/ash/drag_drop/drag_drop_controller_unittest.cc
index e3bc806..298df6c 100644
--- a/ash/drag_drop/drag_drop_controller_unittest.cc
+++ b/ash/drag_drop/drag_drop_controller_unittest.cc
@@ -1679,4 +1679,42 @@
             delegate.state());
 }
 
+TEST_F(DragDropControllerTest,
+       ToplevelWindowDragDelegateForwardsMouseReleased) {
+  std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
+      aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), -1,
+      gfx::Rect(0, 0, 100, 100)));
+
+  // Emulate a drag session completion to verify that the ET_MOUSE_RELEASED
+  // event can release capture.
+  {
+    TestToplevelWindowDragDelegate delegate;
+    drag_drop_controller_->set_toplevel_window_drag_delegate(&delegate);
+
+    ui::test::EventGenerator generator(window->GetRootWindow(), window.get());
+    generator.PressLeftButton();
+
+    auto data(std::make_unique<ui::OSExchangeData>());
+    drag_drop_controller_->StartDragAndDrop(
+        std::move(data), window->GetRootWindow(), window.get(),
+        gfx::Point(5, 5), ui::DragDropTypes::DRAG_MOVE,
+        ui::mojom::DragEventSource::kMouse);
+
+    // Send a fake mouse up event and assert that it can continue
+    // propagation.
+    auto event = std::make_unique<ui::MouseEvent>(
+        ui::ET_MOUSE_RELEASED, gfx::Point(5, 5), gfx::Point(5, 5),
+        ui::EventTimeForNow(), 0, 0);
+    ui::Event::DispatcherApi(event.get()).set_phase(ui::EP_PRETARGET);
+    ui::Event::DispatcherApi(event.get())
+        .set_target(window->GetToplevelWindow());
+
+    drag_drop_controller_->OnMouseEvent(event.get());
+
+    EXPECT_EQ(TestToplevelWindowDragDelegate::State::kDragDroppedInvoked,
+              delegate.state());
+    EXPECT_FALSE(event.get()->stopped_propagation());
+  }
+}
+
 }  // namespace ash
diff --git a/ash/login/ui/auth_factor_model.cc b/ash/login/ui/auth_factor_model.cc
index a03d6dc..b840246 100644
--- a/ash/login/ui/auth_factor_model.cc
+++ b/ash/login/ui/auth_factor_model.cc
@@ -12,10 +12,10 @@
 AuthFactorModel::~AuthFactorModel() = default;
 
 void AuthFactorModel::Init(AuthIconView* icon,
-                           base::RepeatingClosure on_state_changed_callback) {
+                           base::RepeatingClosure update_state_callback) {
   DCHECK(!icon_) << "Init should only be called once.";
   icon_ = icon;
-  on_state_changed_callback_ = on_state_changed_callback;
+  update_state_callback_ = update_state_callback;
 }
 
 void AuthFactorModel::SetVisible(bool visible) {
@@ -28,10 +28,38 @@
     UpdateIcon(icon_);
 }
 
-void AuthFactorModel::NotifyOnStateChanged() {
+void AuthFactorModel::HandleTapOrClick() {
+  // If an auth factor icon is clicked while the auth factor has a permanent
+  // error, then show the error again by marking it as not timed out.
+  if (GetAuthFactorState() == AuthFactorState::kErrorPermanent)
+    has_permanent_error_display_timed_out_ = false;
+
+  DoHandleTapOrClick();
+
+  // Call `RefreshUI` here in case |has_permanent_error_display_timed_out_|
+  // changed. It's called regardless of whether or not there was an actual
+  // change so that `DoHandleTapOrClick` can avoid calling `RefreshUI`, which
+  // could result in multiple calls.
+  RefreshUI();
+}
+
+void AuthFactorModel::HandleErrorTimeout() {
+  if (GetAuthFactorState() == AuthFactorState::kErrorPermanent)
+    has_permanent_error_display_timed_out_ = true;
+
+  DoHandleErrorTimeout();
+
+  // Call `RefreshUI` here in case |has_permanent_error_display_timed_out_|
+  // changed. It's called regardless of whether or not there was an actual
+  // change so that `DoHandleErrorTimeout` can avoid calling `RefreshUI`, which
+  // could result in multiple calls.
+  RefreshUI();
+}
+
+void AuthFactorModel::RefreshUI() {
   DCHECK(icon_);
-  if (on_state_changed_callback_) {
-    on_state_changed_callback_.Run();
+  if (update_state_callback_) {
+    update_state_callback_.Run();
   }
   UpdateIcon(icon_);
 }
diff --git a/ash/login/ui/auth_factor_model.h b/ash/login/ui/auth_factor_model.h
index 924beeb49..8b18d89b 100644
--- a/ash/login/ui/auth_factor_model.h
+++ b/ash/login/ui/auth_factor_model.h
@@ -35,37 +35,30 @@
 // display a list of auth factors.
 class ASH_EXPORT AuthFactorModel {
  public:
-  // DO NOT change the relative ordering of these enum values. The values
-  // assigned here correspond to the priority of these states. For example, if
-  // LoginAuthFactorsView has one auth factor in the kClickRequired state and
-  // one auth factor in the kReady state, then it will prioritize showing the
-  // kClickRequired state since it's assigned a higher priority. With the
-  // exception of the error states, a higher priority generally implies that
-  // there are fewer steps left to complete authentication.
   enum class AuthFactorState {
     // The feature is disabled, disallowed by policy, or requires
     // hardware that isn’t present.
-    kUnavailable = 0,
+    kUnavailable,
     // The auth factor cannot be used because of an unrecoverable
     // error, e.g. Fingerprint’s “Too many attempts”. GetLabel()
     // and UpdateIcon() show the relevant messages.
-    kErrorPermanent = 1,
+    kErrorPermanent,
     // The auth factor can be used but requires additional steps
     // before use, e.g. turn on Bluetooth.
-    kAvailable = 2,
+    kAvailable,
     // The auth factor is ready to authenticate. This state should
     // only be returned if authentication can be completed in one
     // step (two if a click is required).
-    kReady = 3,
+    kReady,
     // The auth factor has a non-blocking error to show the
     // user, e.g. Fingerprint’s “Not recognized”, which clears
     // after a few seconds. GetLabel() and UpdateIcon() show the
     // relevant messages.
-    kErrorTemporary = 4,
+    kErrorTemporary,
     // The auth factor requires the user to tap/click to enter.
-    kClickRequired = 5,
+    kClickRequired,
     // Authentication is complete.
-    kAuthenticated = 6,
+    kAuthenticated,
   };
 
   AuthFactorModel();
@@ -73,14 +66,13 @@
   AuthFactorModel& operator=(AuthFactorModel&) = delete;
   virtual ~AuthFactorModel();
 
-  // Initializes |icon_| and |on_state_changed_callback_|. Should be called
-  // exactly once before any other methods. The |on_state_changed_callback| is
+  // Initializes |icon_| and |update_state_callback_|. Should be called
+  // exactly once before any other methods. The |update_state_callback| is
   // used by LoginAuthFactorsView to determine when it is necessary to update
   // the displayed icons and label.
   // TODO(crbug.com/1233614): Refactor to disallow the creation of partially
   // initialized objects.
-  void Init(AuthIconView* icon,
-            base::RepeatingClosure on_state_changed_callback);
+  void Init(AuthIconView* icon, base::RepeatingClosure update_state_callback);
 
   // Set the visibility of the associated icon.
   void SetVisible(bool visible);
@@ -88,45 +80,65 @@
   // Should be called when the parent View's theme changes.
   void OnThemeChanged();
 
+  // Should be called when the auth factor's icon is tapped or clicked.
+  void HandleTapOrClick();
+
+  // Should be called after an error is shown to the user.
+  void HandleErrorTimeout();
+
   // Return the current state of this auth factor.
-  virtual AuthFactorState GetAuthFactorState() = 0;
+  virtual AuthFactorState GetAuthFactorState() const = 0;
 
   // Returns the type of the auth factor. Each implementation of AuthFactorModel
   // should add a new type to the AuthFactorType enum.
-  virtual AuthFactorType GetType() = 0;
+  virtual AuthFactorType GetType() const = 0;
 
   // The ID of the label that should be shown in the current state.
-  virtual int GetLabelId() = 0;
+  virtual int GetLabelId() const = 0;
 
   // Controls whether the label is announced by Chromevox.
-  virtual bool ShouldAnnounceLabel() = 0;
+  virtual bool ShouldAnnounceLabel() const = 0;
 
   // Alternative text to be provided to screen readers.
-  virtual int GetAccessibleNameId() = 0;
-
-  // This will be called when the auth factor's icon is tapped or clicked.
-  virtual void OnTapOrClickEvent() = 0;
+  virtual int GetAccessibleNameId() const = 0;
 
   // This will be called when the arrow button owned by `LoginAuthFactorsView`
   // is tapped or clicked.
   virtual void OnArrowButtonTapOrClickEvent();
 
-  // This will be called after the latest error has been shown to the user to
-  // signal that any transient error state should be cleared out.
-  virtual void OnErrorTimeout() = 0;
+  // If the auth factor state is kErrorPermanent, this indicates whether the
+  // error has been shown to the user and timed out.
+  bool has_permanent_error_display_timed_out() const {
+    return has_permanent_error_display_timed_out_;
+  }
 
  protected:
   // Should be called whenever the internal state of the auth model changes to
-  // invoke the |on_state_changed_callback_| if set. Calls UpdateIcon().
-  void NotifyOnStateChanged();
+  // invoke the |update_state_callback_| if set. Calls `UpdateIcon`.
+  void RefreshUI();
+
+  // If the auth factor state is kErrorPermanent, this indicates whether the
+  // error has been shown to the user and timed out, which determines whether
+  // the error icon or the disabled icon should be shown.
+  bool has_permanent_error_display_timed_out_ = false;
 
  private:
   // Update |icon| to represent the current state of the auth factor. Called by
-  // NotifyOnStateChanged(), so implementations do not need to call this
-  // method directly.
+  // RefreshUI, so implementations do not need to call this method directly.
   virtual void UpdateIcon(AuthIconView* icon) = 0;
 
-  base::RepeatingClosure on_state_changed_callback_;
+  // This will be called after the latest error has been shown to the user to
+  // signal that any transient error state should be cleared out.
+  // Implementations should not call `RefreshUI` since that is handled by
+  // `HandleErrorTimeout`.
+  virtual void DoHandleErrorTimeout() = 0;
+
+  // This will be called when the auth factor's icon is tapped or clicked.
+  // Implementations should not call `RefreshUI` since that is handled by
+  // `HandleTapOrClick`.
+  virtual void DoHandleTapOrClick() = 0;
+
+  base::RepeatingClosure update_state_callback_;
   AuthIconView* icon_ = nullptr;
 };
 
diff --git a/ash/login/ui/auth_icon_view.cc b/ash/login/ui/auth_icon_view.cc
index 6dd2fe1..b335508 100644
--- a/ash/login/ui/auth_icon_view.cc
+++ b/ash/login/ui/auth_icon_view.cc
@@ -4,7 +4,12 @@
 
 #include "ash/login/ui/auth_icon_view.h"
 
+#include "ash/login/ui/horizontal_image_sequence_animation_decoder.h"
 #include "ash/style/ash_color_provider.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animation_sequence.h"
+#include "ui/compositor/layer_animator.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/vector_icon_types.h"
@@ -12,20 +17,81 @@
 namespace ash {
 
 namespace {
+
+struct ShakeAnimationStep {
+  int x_offset;
+  int duration_ms;
+};
+
 constexpr int kAuthIconSizeDp = 32;
+
+// See spec:
+// https://carbon.googleplex.com/cr-os-motion-work/pages/sign-in/undefined/e05c4091-eea2-4c5a-a6f8-38fd37953e7b#a929eb9f-2840-4b37-be52-97d96ca2aafa
+constexpr ShakeAnimationStep kShakeAnimationSteps[] = {
+    {-5, 83}, {8, 83}, {-7, 66}, {7, 66}, {-7, 66}, {7, 66}, {-3, 83}};
+
+SkColor GetColor(AuthIconView::Color color) {
+  switch (color) {
+    case AuthIconView::Color::kPrimary:
+      return AshColorProvider::Get()->GetContentLayerColor(
+          AshColorProvider::ContentLayerType::kIconColorPrimary);
+    case AuthIconView::Color::kDisabled:
+      return AshColorProvider::Get()->GetDisabledColor(
+          GetColor(AuthIconView::Color::kPrimary));
+    case AuthIconView::Color::kError:
+      // TODO(crbug.com/1233614): Either find a system color to match the color
+      // in the Fingerprint animation png sequence, or upload new png files with
+      // the right color.
+      return AshColorProvider::Get()->GetContentLayerColor(
+          AshColorProvider::ContentLayerType::kIconColorAlert);
+  }
 }
 
+}  // namespace
+
 AuthIconView::AuthIconView()
     : AnimatedRoundedImageView(gfx::Size(kAuthIconSizeDp, kAuthIconSizeDp),
-                               /*corner_radius=*/0) {}
+                               /*corner_radius=*/0) {
+  // Set up layer to allow for animation.
+  SetPaintToLayer();
+  layer()->SetFillsBoundsOpaquely(false);
+  layer()->GetAnimator()->set_preemption_strategy(
+      ui::LayerAnimator::PreemptionStrategy::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+}
 
 AuthIconView::~AuthIconView() = default;
 
-void AuthIconView::SetIcon(const gfx::VectorIcon& icon) {
-  const SkColor icon_color = AshColorProvider::Get()->GetContentLayerColor(
-      AshColorProvider::ContentLayerType::kIconColorPrimary);
+void AuthIconView::SetIcon(const gfx::VectorIcon& icon, Color color) {
+  SetImage(gfx::CreateVectorIcon(icon, kAuthIconSizeDp, GetColor(color)));
+}
 
-  SetImage(gfx::CreateVectorIcon(icon, kAuthIconSizeDp, icon_color));
+void AuthIconView::SetAnimation(int animation_resource_id,
+                                base::TimeDelta duration,
+                                int num_frames) {
+  SetAnimationDecoder(
+      std::make_unique<HorizontalImageSequenceAnimationDecoder>(
+          *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+              animation_resource_id),
+          duration, num_frames),
+      AnimatedRoundedImageView::Playback::kSingle);
+}
+
+void AuthIconView::RunErrorShakeAnimation() {
+  // Stop any existing animation.
+  layer()->GetAnimator()->StopAnimating();
+
+  auto transform_sequence = std::make_unique<ui::LayerAnimationSequence>();
+  gfx::Transform transform;
+  for (const ShakeAnimationStep& step : kShakeAnimationSteps) {
+    transform.Translate(step.x_offset, /*y=*/0);
+    auto element = ui::LayerAnimationElement::CreateTransformElement(
+        transform, base::Milliseconds(step.duration_ms));
+    element->set_tween_type(gfx::Tween::Type::EASE_IN_OUT_2);
+    transform_sequence->AddElement(std::move(element));
+  }
+
+  // Animator takes ownership of transform_sequence.
+  layer()->GetAnimator()->StartAnimation(transform_sequence.release());
 }
 
 // views::View:
diff --git a/ash/login/ui/auth_icon_view.h b/ash/login/ui/auth_icon_view.h
index 327d7b1..d047d880 100644
--- a/ash/login/ui/auth_icon_view.h
+++ b/ash/login/ui/auth_icon_view.h
@@ -21,16 +21,31 @@
 // TODO(crbug.com/1252880): Add progress animation.
 class ASH_EXPORT AuthIconView : public AnimatedRoundedImageView {
  public:
+  enum class Color {
+    kPrimary,
+    kDisabled,
+    kError,
+  };
+
   AuthIconView();
   AuthIconView(AuthIconView&) = delete;
   AuthIconView& operator=(AuthIconView&) = delete;
   ~AuthIconView() override;
 
   // Show a static icon.
-  void SetIcon(const gfx::VectorIcon& icon);
+  void SetIcon(const gfx::VectorIcon& icon, Color color = Color::kPrimary);
 
-  // TODO(crbug.com/1233614): Add additional convenience methods here so that
-  // calling classes don't have to provide colors and sizes.
+  // Show a sequence of animation frames. |animation_resource_id| should refer
+  // to an image with the frames of the animation layed out horizontally.
+  // |duration| is the total duration of the animation. |num_frames| is the
+  // number of frames in the image referred to by |animation_resource_id|.
+  void SetAnimation(int animation_resource_id,
+                    base::TimeDelta duration,
+                    int num_frames);
+
+  // Cause the icon to briefly shake left and right to signify that an error has
+  // occurred.
+  void RunErrorShakeAnimation();
 
   void set_on_tap_or_click_callback(base::RepeatingClosure on_tap_or_click) {
     on_tap_or_click_callback_ = on_tap_or_click;
diff --git a/ash/login/ui/fingerprint_auth_factor_model.cc b/ash/login/ui/fingerprint_auth_factor_model.cc
index 8df0e76..19029c8c 100644
--- a/ash/login/ui/fingerprint_auth_factor_model.cc
+++ b/ash/login/ui/fingerprint_auth_factor_model.cc
@@ -6,21 +6,19 @@
 
 #include "ash/login/resources/grit/login_resources.h"
 #include "ash/login/ui/auth_icon_view.h"
-#include "ash/login/ui/horizontal_image_sequence_animation_decoder.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
-#include "ui/base/resource/resource_bundle.h"
+#include "base/time/time.h"
 #include "ui/gfx/geometry/size.h"
-#include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/vector_icon_types.h"
 
 namespace ash {
 
 namespace {
 
-constexpr int kFingerprintIconSizeDp = 32;
-constexpr int kFingerprintFailedAnimationDurationMs = 700;
+constexpr base::TimeDelta kFingerprintFailedAnimationDuration =
+    base::Milliseconds(700);
 constexpr int kFingerprintFailedAnimationNumFrames = 45;
 
 }  // namespace
@@ -33,22 +31,27 @@
   if (state_ == state)
     return;
 
+  // Clear out the timeout if the state changes. This shouldn't happen
+  // ordinarily -- permanent error states are permanent after all -- but this is
+  // required for the debug overlay to work properly when cycling states.
+  has_permanent_error_display_timed_out_ = false;
+
   state_ = state;
-  NotifyOnStateChanged();
+  RefreshUI();
 }
 
 void FingerprintAuthFactorModel::NotifyFingerprintAuthResult(bool result) {
   auth_result_ = result;
-  NotifyOnStateChanged();
+  RefreshUI();
 }
 
 void FingerprintAuthFactorModel::SetCanUsePin(bool can_use_pin) {
   can_use_pin_ = can_use_pin;
-  NotifyOnStateChanged();
+  RefreshUI();
 }
 
 AuthFactorModel::AuthFactorState
-FingerprintAuthFactorModel::GetAuthFactorState() {
+FingerprintAuthFactorModel::GetAuthFactorState() const {
   if (!available_)
     return AuthFactorState::kUnavailable;
 
@@ -74,11 +77,11 @@
   }
 }
 
-AuthFactorType FingerprintAuthFactorModel::GetType() {
+AuthFactorType FingerprintAuthFactorModel::GetType() const {
   return AuthFactorType::kFingerprint;
 }
 
-int FingerprintAuthFactorModel::GetLabelId() {
+int FingerprintAuthFactorModel::GetLabelId() const {
   if (auth_result_.has_value()) {
     if (auth_result_.value()) {
       return IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_AUTH_SUCCESS;
@@ -108,13 +111,13 @@
   NOTREACHED();
 }
 
-bool FingerprintAuthFactorModel::ShouldAnnounceLabel() {
+bool FingerprintAuthFactorModel::ShouldAnnounceLabel() const {
   return state_ == FingerprintState::DISABLED_FROM_ATTEMPTS ||
          state_ == FingerprintState::DISABLED_FROM_TIMEOUT ||
          (auth_result_.has_value() && !auth_result_.value());
 }
 
-int FingerprintAuthFactorModel::GetAccessibleNameId() {
+int FingerprintAuthFactorModel::GetAccessibleNameId() const {
   if (state_ == FingerprintState::DISABLED_FROM_ATTEMPTS)
     return IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_ACCESSIBLE_AUTH_DISABLED_FROM_ATTEMPTS;
 
@@ -123,24 +126,12 @@
 
 void FingerprintAuthFactorModel::UpdateIcon(AuthIconView* icon) {
   if (auth_result_.has_value() && !auth_result_.value()) {
-    icon->SetAnimationDecoder(
-        std::make_unique<HorizontalImageSequenceAnimationDecoder>(
-            *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-                IDR_LOGIN_FINGERPRINT_UNLOCK_SPINNER),
-            base::Milliseconds(kFingerprintFailedAnimationDurationMs),
-            kFingerprintFailedAnimationNumFrames),
-        AnimatedRoundedImageView::Playback::kSingle);
+    icon->SetAnimation(IDR_LOGIN_FINGERPRINT_UNLOCK_SPINNER,
+                       kFingerprintFailedAnimationDuration,
+                       kFingerprintFailedAnimationNumFrames);
     return;
   }
 
-  const SkColor icon_color = AshColorProvider::Get()->GetContentLayerColor(
-      AshColorProvider::ContentLayerType::kIconColorPrimary);
-  const SkColor color =
-      state_ == FingerprintState::AVAILABLE_DEFAULT ||
-              state_ == FingerprintState::AVAILABLE_WITH_TOUCH_SENSOR_WARNING
-          ? icon_color
-          : AshColorProvider::Get()->GetDisabledColor(icon_color);
-
   switch (state_) {
     case FingerprintState::AVAILABLE_DEFAULT:
       FALLTHROUGH;
@@ -150,32 +141,29 @@
     case FingerprintState::UNAVAILABLE:
       FALLTHROUGH;
     case FingerprintState::DISABLED_FROM_TIMEOUT:
-      icon->SetImage(gfx::CreateVectorIcon(kLockScreenFingerprintDisabledIcon,
-                                           kFingerprintIconSizeDp, color));
+      icon->SetIcon(kLockScreenFingerprintDisabledIcon,
+                    AuthIconView::Color::kDisabled);
       break;
     case FingerprintState::DISABLED_FROM_ATTEMPTS:
-      icon->SetAnimationDecoder(
-          std::make_unique<HorizontalImageSequenceAnimationDecoder>(
-              *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-                  IDR_LOGIN_FINGERPRINT_UNLOCK_SPINNER),
-              base::Milliseconds(kFingerprintFailedAnimationDurationMs),
-              kFingerprintFailedAnimationNumFrames),
-          AnimatedRoundedImageView::Playback::kSingle);
+      if (has_permanent_error_display_timed_out_) {
+        icon->SetIcon(kLockScreenFingerprintDisabledIcon,
+                      AuthIconView::Color::kDisabled);
+      } else {
+        icon->SetAnimation(IDR_LOGIN_FINGERPRINT_UNLOCK_SPINNER,
+                           kFingerprintFailedAnimationDuration,
+                           kFingerprintFailedAnimationNumFrames);
+      }
       break;
   }
 }
 
-void FingerprintAuthFactorModel::OnTapOrClickEvent() {
+void FingerprintAuthFactorModel::DoHandleTapOrClick() {
   if (state_ == FingerprintState::AVAILABLE_DEFAULT) {
     state_ = FingerprintState::AVAILABLE_WITH_TOUCH_SENSOR_WARNING;
   }
-
-  // TODO(crbug.com/1233614): Move this call into the AuthFactorModel base class
-  // so that the derived classes don't have to call it.
-  NotifyOnStateChanged();
 }
 
-void FingerprintAuthFactorModel::OnErrorTimeout() {
+void FingerprintAuthFactorModel::DoHandleErrorTimeout() {
   if (auth_result_.has_value() && !auth_result_.value()) {
     // Clear failed auth attempt to allow retry.
     auth_result_.reset();
@@ -183,10 +171,6 @@
   if (GetAuthFactorState() == AuthFactorState::kErrorTemporary) {
     state_ = FingerprintState::AVAILABLE_DEFAULT;
   }
-
-  // TODO(crbug.com/1233614): Move this call into the AuthFactorModel base class
-  // so that the derived classes don't have to call it.
-  NotifyOnStateChanged();
 }
 
 }  // namespace ash
diff --git a/ash/login/ui/fingerprint_auth_factor_model.h b/ash/login/ui/fingerprint_auth_factor_model.h
index adc7feb..fd541a0 100644
--- a/ash/login/ui/fingerprint_auth_factor_model.h
+++ b/ash/login/ui/fingerprint_auth_factor_model.h
@@ -32,13 +32,13 @@
 
  private:
   // AuthFactorModel:
-  AuthFactorState GetAuthFactorState() override;
-  AuthFactorType GetType() override;
-  int GetLabelId() override;
-  bool ShouldAnnounceLabel() override;
-  int GetAccessibleNameId() override;
-  void OnTapOrClickEvent() override;
-  void OnErrorTimeout() override;
+  AuthFactorState GetAuthFactorState() const override;
+  AuthFactorType GetType() const override;
+  int GetLabelId() const override;
+  bool ShouldAnnounceLabel() const override;
+  int GetAccessibleNameId() const override;
+  void DoHandleTapOrClick() override;
+  void DoHandleErrorTimeout() override;
   void UpdateIcon(AuthIconView* icon) override;
 
   FingerprintState state_ = FingerprintState::AVAILABLE_DEFAULT;
diff --git a/ash/login/ui/login_auth_factors_view.cc b/ash/login/ui/login_auth_factors_view.cc
index ee16b12..7d387c8 100644
--- a/ash/login/ui/login_auth_factors_view.cc
+++ b/ash/login/ui/login_auth_factors_view.cc
@@ -28,6 +28,8 @@
 
 namespace {
 
+using AuthFactorState = AuthFactorModel::AuthFactorState;
+
 constexpr int kAuthFactorsViewWidthDp = 204;
 constexpr int kSpacingBetweenIconsAndLabelDp = 15;
 constexpr int kIconTopSpacingDp = 20;
@@ -36,22 +38,87 @@
 constexpr int kIconSizeDp = 32;
 constexpr base::TimeDelta kErrorTimeout = base::Seconds(3);
 
-// Return the AuthFactorModel whose AuthFactorState has the highest priority.
-// "Priority" here roughly corresponds with how close the given state is to
-// completing the auth flow. E.g. kAvailable < kReady because there are fewer
-// steps to complete authentication for a Ready auth factor. The highest
-// priority auth factor's state determines the behavior of LoginAuthFactorsView.
+// The values of this enum should be nearly the same as the values of
+// AuthFactorState, except instead of kErrorTemporary and kErrorPermanent, we
+// have kErrorForeground and kErrorBackground.
+//
+// Foreground/background here refers to whether or not the error has already
+// been displayed to the user. Permanent errors, which can't be recovered from,
+// start in the foreground and then transition to the background after having
+// been displayed. Temporary errors, on the other hand, start in the foreground
+// and then transition to a non-error state after display.
+//
+// The idea is to provide separation of concerns: AuthFactorModel is concerned
+// with the type of error being shown, but LoginAuthFactorsView is concerned
+// with how to show the error. When deciding how to prioritize which states to
+// show, what matters is whether the error is currently in the foreground or
+// background, not whether the underlying error state is temporary or permanent.
+//
+// DO NOT change the relative ordering of these enum values. The values
+// assigned here correspond to the priority of these states. For example, if
+// LoginAuthFactorsView has one auth factor in the kClickRequired state and
+// one auth factor in the kReady state, then it will prioritize showing the
+// kClickRequired state since it's assigned a higher priority.
+enum class PrioritizedAuthFactorViewState {
+  // All auth factors are unavailable, and LoginAuthFactorsView should not be
+  // visible.
+  kUnavailable = 0,
+  // All auth factors are either unavailable or have permanent errors that have
+  // already been displayed.
+  kErrorBackground = 1,
+  // There is at least one auth factor that is available, but it requires extra
+  // steps to authenticate.
+  kAvailable = 2,
+  // There is at least one auth factor that is ready to authenticate.
+  kReady = 3,
+  // An auth factor has an error message to display.
+  kErrorForeground = 4,
+  // An auth factor requires a tap or click as the last step in its
+  // authentication flow.
+  kClickRequired = 5,
+  // Authentication is complete.
+  kAuthenticated = 6,
+};
+
+PrioritizedAuthFactorViewState GetPrioritizedAuthFactorViewState(
+    const AuthFactorModel& auth_factor) {
+  switch (auth_factor.GetAuthFactorState()) {
+    case AuthFactorState::kUnavailable:
+      return PrioritizedAuthFactorViewState::kUnavailable;
+    case AuthFactorState::kErrorPermanent:
+      if (auth_factor.has_permanent_error_display_timed_out())
+        return PrioritizedAuthFactorViewState::kErrorBackground;
+
+      return PrioritizedAuthFactorViewState::kErrorForeground;
+    case AuthFactorState::kAvailable:
+      return PrioritizedAuthFactorViewState::kAvailable;
+    case AuthFactorState::kReady:
+      return PrioritizedAuthFactorViewState::kReady;
+    case AuthFactorState::kErrorTemporary:
+      return PrioritizedAuthFactorViewState::kErrorForeground;
+    case AuthFactorState::kClickRequired:
+      return PrioritizedAuthFactorViewState::kClickRequired;
+    case AuthFactorState::kAuthenticated:
+      return PrioritizedAuthFactorViewState::kAuthenticated;
+  }
+}
+
+// Return the AuthFactorModel whose state has the highest priority. "Priority"
+// here roughly corresponds with how close the given state is to completing the
+// auth flow. E.g. kAvailable < kReady because there are fewer steps to complete
+// authentication for a Ready auth factor. The highest priority auth factor's
+// state determines the behavior of LoginAuthFactorsView.
 AuthFactorModel* GetHighestPriorityAuthFactor(
     const std::vector<std::unique_ptr<AuthFactorModel>>& auth_factors) {
   if (auth_factors.empty())
     return nullptr;
 
-  // AuthFactorState's enum values are assigned so that the highest numerical
-  // value corresponds to the highest priority.
+  // PrioritizedAuthFactorViewState enum values are assigned so that the
+  // highest numerical value corresponds to the highest priority.
   auto compare_by_priority = [](const std::unique_ptr<AuthFactorModel>& a,
                                 const std::unique_ptr<AuthFactorModel>& b) {
-    return static_cast<int>(a->GetAuthFactorState()) <
-           static_cast<int>(b->GetAuthFactorState());
+    return static_cast<int>(GetPrioritizedAuthFactorViewState(*a)) <
+           static_cast<int>(GetPrioritizedAuthFactorViewState(*b));
   };
 
   auto& max = *std::max_element(auth_factors.begin(), auth_factors.end(),
@@ -187,11 +254,10 @@
       auth_factor_icon_row_->AddChildView(std::make_unique<AuthIconView>());
   auth_factor->Init(
       icon,
-      /*on_state_changed_callback=*/base::BindRepeating(
+      /*update_state_callback=*/base::BindRepeating(
           &LoginAuthFactorsView::UpdateState, base::Unretained(this)));
-  icon->set_on_tap_or_click_callback(
-      base::BindRepeating(&AuthFactorModel::OnTapOrClickEvent,
-                          base::Unretained(auth_factor.get())));
+  icon->set_on_tap_or_click_callback(base::BindRepeating(
+      &AuthFactorModel::HandleTapOrClick, base::Unretained(auth_factor.get())));
   auth_factors_.push_back(std::move(auth_factor));
   UpdateState();
 }
@@ -199,22 +265,27 @@
 void LoginAuthFactorsView::UpdateState() {
   AuthFactorModel* active_auth_factor =
       GetHighestPriorityAuthFactor(auth_factors_);
+  if (!active_auth_factor) {
+    SetVisible(false);
+    return;
+  }
 
-  if (!active_auth_factor || active_auth_factor->GetAuthFactorState() ==
-                                 AuthFactorState::kUnavailable) {
+  PrioritizedAuthFactorViewState state =
+      GetPrioritizedAuthFactorViewState(*active_auth_factor);
+  if (state == PrioritizedAuthFactorViewState::kUnavailable) {
     SetVisible(false);
     return;
   }
   SetVisible(true);
 
-  if (active_auth_factor->GetAuthFactorState() !=
-      AuthFactorState::kErrorTemporary) {
+  if (state != PrioritizedAuthFactorViewState::kErrorForeground) {
     error_timer_.Stop();
   }
 
   int ready_label_id;
-  switch (active_auth_factor->GetAuthFactorState()) {
-    case AuthFactorState::kAuthenticated:
+  size_t num_factors_in_error_background_state;
+  switch (state) {
+    case PrioritizedAuthFactorViewState::kAuthenticated:
       // An auth factor has successfully authenticated. Show a green checkmark.
       ShowCheckmark();
       // TODO(crbug.com/1233614): If we're on the login page, show "Signed in"
@@ -222,27 +293,39 @@
       SetLabelTextAndAccessibleName(IDS_AUTH_FACTOR_LABEL_UNLOCKED,
                                     IDS_AUTH_FACTOR_LABEL_UNLOCKED);
       return;
-    case AuthFactorState::kClickRequired:
+    case PrioritizedAuthFactorViewState::kClickRequired:
       // An auth factor requires a click to enter. Show arrow button.
       // TODO(crbug.com/1233614): collapse password/pin
       ShowArrowButton();
       SetLabelTextAndAccessibleName(IDS_AUTH_FACTOR_LABEL_CLICK_TO_ENTER,
                                     IDS_AUTH_FACTOR_LABEL_CLICK_TO_ENTER);
       FireAlert();
+
+      // Dismiss any errors in the background.
+      OnErrorTimeout();
       return;
-    case AuthFactorState::kReady:
+    case PrioritizedAuthFactorViewState::kReady:
       // One or more auth factors is in the Ready state. Show the ready auth
       // factors.
-      // TODO(crbug.com/1233614): show disabled auth factors
-      ShowReadyAuthFactors();
+      ShowReadyAndDisabledAuthFactors();
       ready_label_id = GetReadyLabelId();
       SetLabelTextAndAccessibleName(ready_label_id, ready_label_id);
       // TODO(crbug.com/1233614): Should FireAlert() be called here?
       FireAlert();
       return;
-    case AuthFactorState::kErrorTemporary:
-      // An auth factor has an error to show temporarily. Show the error for a
-      // period of time.
+    case PrioritizedAuthFactorViewState::kAvailable:
+      // At least one auth factor is available, but none are ready. Show first
+      // available auth factor.
+      ShowSingleAuthFactor(active_auth_factor);
+      SetLabelTextAndAccessibleName(active_auth_factor->GetLabelId(),
+                                    active_auth_factor->GetAccessibleNameId());
+      if (active_auth_factor->ShouldAnnounceLabel()) {
+        FireAlert();
+      }
+      return;
+    case PrioritizedAuthFactorViewState::kErrorForeground:
+      // An auth factor has either a temporary or permanent error to show. Show
+      // the error for a period of time.
 
       // Do not replace the current error if an error is already showing.
       if (error_timer_.IsRunning())
@@ -259,28 +342,31 @@
         FireAlert();
       }
       return;
-    case AuthFactorState::kAvailable:
-      // At least one auth factor is available, but none are ready. Show first
-      // available auth factor.
-      ShowSingleAuthFactor(active_auth_factor);
-      SetLabelTextAndAccessibleName(active_auth_factor->GetLabelId(),
-                                    active_auth_factor->GetAccessibleNameId());
-      if (active_auth_factor->ShouldAnnounceLabel()) {
-        FireAlert();
+    case PrioritizedAuthFactorViewState::kErrorBackground:
+      // Any auth factors that were available have errors that cannot be
+      // resolved, and those errors have already been displayed in the
+      // foreground. Show the "disabled" icons and instruct the user to enter
+      // their password.
+      ShowReadyAndDisabledAuthFactors();
+
+      num_factors_in_error_background_state = std::count_if(
+          auth_factors_.begin(), auth_factors_.end(), [](const auto& factor) {
+            return GetPrioritizedAuthFactorViewState(*factor) ==
+                   PrioritizedAuthFactorViewState::kErrorBackground;
+          });
+
+      if (num_factors_in_error_background_state == 1) {
+        SetLabelTextAndAccessibleName(
+            active_auth_factor->GetLabelId(),
+            active_auth_factor->GetAccessibleNameId());
+      } else {
+        // TODO(crbug.com/1233614): Check if pin is visible and use "enter
+        // password or PIN" string if it is.
+        SetLabelTextAndAccessibleName(IDS_AUTH_FACTOR_LABEL_UNLOCK_PASSWORD,
+                                      IDS_AUTH_FACTOR_LABEL_UNLOCK_PASSWORD);
       }
       return;
-    case AuthFactorState::kErrorPermanent:
-      // Any auth factors that were available have errors that cannot be
-      // resolved. Show the "disabled" icons and instruct the user to enter
-      // their password.
-      // TODO(crbug.com/1233614): show disabled auth factors
-      auth_factor_icon_row_->SetVisible(false);
-      arrow_button_->SetVisible(false);
-      checkmark_icon_->SetVisible(false);
-      SetLabelTextAndAccessibleName(IDS_AUTH_FACTOR_LABEL_UNLOCK_PASSWORD,
-                                    IDS_AUTH_FACTOR_LABEL_UNLOCK_PASSWORD);
-      return;
-    case AuthFactorState::kUnavailable:
+    case PrioritizedAuthFactorViewState::kUnavailable:
       NOTREACHED();
       return;
   }
@@ -302,12 +388,17 @@
   }
 }
 
-void LoginAuthFactorsView::ShowReadyAuthFactors() {
+void LoginAuthFactorsView::ShowReadyAndDisabledAuthFactors() {
   auth_factor_icon_row_->SetVisible(true);
   arrow_button_->SetVisible(false);
   checkmark_icon_->SetVisible(false);
+
   for (auto& factor : auth_factors_) {
-    factor->SetVisible(factor->GetAuthFactorState() == AuthFactorState::kReady);
+    PrioritizedAuthFactorViewState state =
+        GetPrioritizedAuthFactorViewState(*factor);
+    factor->SetVisible(state == PrioritizedAuthFactorViewState::kReady ||
+                       state ==
+                           PrioritizedAuthFactorViewState::kErrorBackground);
   }
 }
 
@@ -390,8 +481,9 @@
     // If additional errors occur during the error timeout, then mark all
     // errors timed out instead of trying to queue them. The user can still get
     // the error messages by clicking on the icons.
-    if (factor->GetAuthFactorState() == AuthFactorState::kErrorTemporary) {
-      factor->OnErrorTimeout();
+    if (GetPrioritizedAuthFactorViewState(*factor) ==
+        PrioritizedAuthFactorViewState::kErrorForeground) {
+      factor->HandleErrorTimeout();
     }
   }
 }
diff --git a/ash/login/ui/login_auth_factors_view.h b/ash/login/ui/login_auth_factors_view.h
index 7750c740..c344f18 100644
--- a/ash/login/ui/login_auth_factors_view.h
+++ b/ash/login/ui/login_auth_factors_view.h
@@ -71,7 +71,7 @@
 
   void ShowArrowButton();
   void ShowSingleAuthFactor(AuthFactorModel* auth_factor);
-  void ShowReadyAuthFactors();
+  void ShowReadyAndDisabledAuthFactors();
   void ShowCheckmark();
 
   // Sets the text and accessible name of the label using the provided string
@@ -111,7 +111,7 @@
 
   /////////////////////////////////////////////////////////////////////////////
 
-  // The auth factor models that have been added by calling AddAuthFactor().
+  // The auth factor models that have been added by calling `AddAuthFactor`.
   // The order here should match the order in which they appear in the UI when
   // multiple are visible.
   std::vector<std::unique_ptr<AuthFactorModel>> auth_factors_;
diff --git a/ash/login/ui/login_auth_factors_view_unittest.cc b/ash/login/ui/login_auth_factors_view_unittest.cc
index 98f1c6f..eec83409 100644
--- a/ash/login/ui/login_auth_factors_view_unittest.cc
+++ b/ash/login/ui/login_auth_factors_view_unittest.cc
@@ -39,27 +39,29 @@
   ~FakeAuthFactorModel() override = default;
 
   // AuthFactorModel:
-  AuthFactorState GetAuthFactorState() override { return state_; }
+  AuthFactorState GetAuthFactorState() const override { return state_; }
 
   // AuthFactorModel:
-  AuthFactorType GetType() override { return type_; }
+  AuthFactorType GetType() const override { return type_; }
 
   // AuthFactorModel:
-  int GetLabelId() override { return IDS_SMART_LOCK_LABEL_LOOKING_FOR_PHONE; }
-
-  // AuthFactorModel:
-  bool ShouldAnnounceLabel() override { return should_announce_label_; }
-
-  // AuthFactorModel:
-  int GetAccessibleNameId() override {
+  int GetLabelId() const override {
     return IDS_SMART_LOCK_LABEL_LOOKING_FOR_PHONE;
   }
 
   // AuthFactorModel:
-  void OnTapOrClickEvent() override { on_tap_or_click_event_called_ = true; }
+  bool ShouldAnnounceLabel() const override { return should_announce_label_; }
 
   // AuthFactorModel:
-  void OnErrorTimeout() override { on_error_timeout_called_ = true; }
+  int GetAccessibleNameId() const override {
+    return IDS_SMART_LOCK_LABEL_LOOKING_FOR_PHONE;
+  }
+
+  // AuthFactorModel:
+  void DoHandleTapOrClick() override { do_handle_tap_or_click_called_ = true; }
+
+  // AuthFactorModel:
+  void DoHandleErrorTimeout() override { do_handle_error_timeout_num_calls_++; }
 
   // AuthFactorModel:
   void UpdateIcon(AuthIconView* icon) override {
@@ -67,14 +69,15 @@
     icon_ = icon;
   }
 
-  using AuthFactorModel::NotifyOnStateChanged;
+  using AuthFactorModel::has_permanent_error_display_timed_out_;
+  using AuthFactorModel::RefreshUI;
 
   AuthFactorType type_;
   AuthFactorState state_ = AuthFactorState::kReady;
   AuthIconView* icon_ = nullptr;
-  bool on_tap_or_click_event_called_ = false;
+  bool do_handle_tap_or_click_called_ = false;
   bool should_announce_label_ = false;
-  bool on_error_timeout_called_ = false;
+  int do_handle_error_timeout_num_calls_ = 0;
 };
 
 class ScopedAXEventObserver : public views::AXEventObserver {
@@ -196,15 +199,15 @@
   AddAuthFactors({AuthFactorType::kFingerprint, AuthFactorType::kSmartLock});
   auto* factor = auth_factors_[0];
 
-  // NotifyOnStateChanged() calls UpdateIcon(), which captures a pointer to the
+  // RefreshUI() calls UpdateIcon(), which captures a pointer to the
   // icon.
-  factor->NotifyOnStateChanged();
+  factor->RefreshUI();
 
-  EXPECT_FALSE(factor->on_tap_or_click_event_called_);
+  EXPECT_FALSE(factor->do_handle_tap_or_click_called_);
   const gfx::Point point(0, 0);
   factor->icon_->OnMousePressed(ui::MouseEvent(
       ui::ET_MOUSE_PRESSED, point, point, base::TimeTicks::Now(), 0, 0));
-  EXPECT_TRUE(factor->on_tap_or_click_event_called_);
+  EXPECT_TRUE(factor->do_handle_tap_or_click_called_);
 }
 
 TEST_F(LoginAuthFactorsViewUnittest, ShouldAnnounceLabel) {
@@ -326,9 +329,64 @@
   // state update.
   EXPECT_EQ(1u, GetVisibleIconCount());
 
-  ASSERT_FALSE(auth_factors_[0]->on_error_timeout_called_);
+  ASSERT_EQ(0, auth_factors_[0]->do_handle_error_timeout_num_calls_);
   task_environment()->FastForwardBy(kErrorTimeout);
-  EXPECT_TRUE(auth_factors_[0]->on_error_timeout_called_);
+  EXPECT_EQ(1, auth_factors_[0]->do_handle_error_timeout_num_calls_);
+}
+
+TEST_F(LoginAuthFactorsViewUnittest, ErrorPermanent) {
+  AddAuthFactors({AuthFactorType::kFingerprint, AuthFactorType::kSmartLock});
+  LoginAuthFactorsView::TestApi test_api(view_);
+  auth_factors_[0]->state_ = AuthFactorState::kErrorPermanent;
+  auth_factors_[1]->state_ = AuthFactorState::kReady;
+  test_api.UpdateState();
+  auto* factor = auth_factors_[0];
+
+  EXPECT_TRUE(test_api.auth_factor_icon_row()->GetVisible());
+  EXPECT_FALSE(test_api.checkmark_icon()->GetVisible());
+  EXPECT_FALSE(test_api.arrow_button()->GetVisible());
+
+  // Only the error should be visible for the first three seconds after the
+  // state update.
+  EXPECT_EQ(1u, GetVisibleIconCount());
+
+  // Fast-forward four seconds. Ensure that the OnErrorTimeout() callback gets
+  // called, and |has_permanent_error_display_timed_out_| correctly reflects
+  // whether the most recent timeout has expired.
+  ASSERT_EQ(0, factor->do_handle_error_timeout_num_calls_);
+  EXPECT_FALSE(factor->has_permanent_error_display_timed_out_);
+  task_environment()->FastForwardBy(base::Seconds(4));
+  EXPECT_EQ(1, factor->do_handle_error_timeout_num_calls_);
+  EXPECT_TRUE(factor->has_permanent_error_display_timed_out_);
+
+  // After timeout, permanent errors are shown alongside ready auth factors.
+  test_api.UpdateState();
+  EXPECT_EQ(2u, GetVisibleIconCount());
+
+  // Simulate a click event.
+  EXPECT_FALSE(factor->do_handle_tap_or_click_called_);
+  factor->RefreshUI();
+  const gfx::Point point(0, 0);
+  factor->icon_->OnMousePressed(ui::MouseEvent(
+      ui::ET_MOUSE_PRESSED, point, point, base::TimeTicks::Now(), 0, 0));
+  EXPECT_TRUE(factor->do_handle_tap_or_click_called_);
+
+  // Clicking causes only the error to be visible.
+  test_api.UpdateState();
+  EXPECT_EQ(1u, GetVisibleIconCount());
+
+  // Fast-forward four seconds. Ensure that the OnErrorTimeout() callback gets
+  // called, and |has_permanent_error_display_timed_out_| correctly reflects
+  // whether the most recent timeout has expired.
+  ASSERT_EQ(1, factor->do_handle_error_timeout_num_calls_);
+  EXPECT_FALSE(factor->has_permanent_error_display_timed_out_);
+  task_environment()->FastForwardBy(base::Seconds(4));
+  EXPECT_EQ(2, factor->do_handle_error_timeout_num_calls_);
+  EXPECT_TRUE(factor->has_permanent_error_display_timed_out_);
+
+  // After timeout, permanent errors are shown alongside ready auth factors.
+  test_api.UpdateState();
+  EXPECT_EQ(2u, GetVisibleIconCount());
 }
 
 }  // namespace ash
diff --git a/ash/login/ui/smart_lock_auth_factor_model.cc b/ash/login/ui/smart_lock_auth_factor_model.cc
index 87e42d6..89cb553f 100644
--- a/ash/login/ui/smart_lock_auth_factor_model.cc
+++ b/ash/login/ui/smart_lock_auth_factor_model.cc
@@ -14,12 +14,6 @@
 
 namespace ash {
 
-namespace {
-
-constexpr int kSmartLockIconSizeDp = 32;
-
-}  // namespace
-
 SmartLockAuthFactorModel::SmartLockAuthFactorModel(
     base::RepeatingCallback<void()> arrow_button_tap_callback)
     : arrow_button_tap_callback_(arrow_button_tap_callback) {}
@@ -56,17 +50,22 @@
   if (state_ == state)
     return;
 
+  // Clear out the timeout if the state changes. This shouldn't happen
+  // ordinarily -- permanent error states are permanent after all -- but this is
+  // required for the debug overlay to work properly when cycling states.
+  has_permanent_error_display_timed_out_ = false;
+
   state_ = state;
-  NotifyOnStateChanged();
+  RefreshUI();
 }
 
 void SmartLockAuthFactorModel::NotifySmartLockAuthResult(bool result) {
   auth_result_ = result;
-  NotifyOnStateChanged();
+  RefreshUI();
 }
 
-AuthFactorModel::AuthFactorState
-SmartLockAuthFactorModel::GetAuthFactorState() {
+AuthFactorModel::AuthFactorState SmartLockAuthFactorModel::GetAuthFactorState()
+    const {
   if (auth_result_.has_value()) {
     return auth_result_.value() ? AuthFactorState::kAuthenticated
                                 : AuthFactorState::kErrorPermanent;
@@ -102,11 +101,11 @@
   }
 }
 
-AuthFactorType SmartLockAuthFactorModel::GetType() {
+AuthFactorType SmartLockAuthFactorModel::GetType() const {
   return AuthFactorType::kSmartLock;
 }
 
-int SmartLockAuthFactorModel::GetLabelId() {
+int SmartLockAuthFactorModel::GetLabelId() const {
   if (auth_result_.has_value()) {
     return auth_result_.value() ? IDS_SMART_LOCK_LABEL_PHONE_LOCKED
                                 : IDS_AUTH_FACTOR_LABEL_CANNOT_UNLOCK;
@@ -143,51 +142,47 @@
   NOTREACHED();
 }
 
-bool SmartLockAuthFactorModel::ShouldAnnounceLabel() {
+bool SmartLockAuthFactorModel::ShouldAnnounceLabel() const {
   // TODO(crbug.com/1233614): Return 'true' depending on SmartLockState.
   return false;
 }
 
-int SmartLockAuthFactorModel::GetAccessibleNameId() {
+int SmartLockAuthFactorModel::GetAccessibleNameId() const {
   // TODO(crbug.com/1233614): Determine whether any state needs to have a
   // different label for a11y.
   return GetLabelId();
 }
 
 void SmartLockAuthFactorModel::UpdateIcon(AuthIconView* icon) {
-  const SkColor primary_color = AshColorProvider::Get()->GetContentLayerColor(
-      AshColorProvider::ContentLayerType::kIconColorPrimary);
-  const SkColor disabled_color =
-      AshColorProvider::Get()->GetDisabledColor(primary_color);
-
-  // TODO(crbug.com/1233614): Either find a system color to match the color in
-  // the Fingerprint animation png sequence, or upload new png files with the
-  // right color.
-  const SkColor alert_color = AshColorProvider::Get()->GetContentLayerColor(
-      AshColorProvider::ContentLayerType::kIconColorAlert);
-
   if (auth_result_.has_value() && !auth_result_.value()) {
-    // TODO(crbug.com/1233614): Get actual failure icon once asset is ready.
-    icon->SetImage(gfx::CreateVectorIcon(kLockScreenSmartCardFailureIcon,
-                                         kSmartLockIconSizeDp, alert_color));
+    if (has_permanent_error_display_timed_out_) {
+      icon->SetIcon(kLockScreenSmartLockDisabledIcon,
+                    AuthIconView::Color::kDisabled);
+    } else {
+      // TODO(crbug.com/1233614): Get actual failure icon once asset is ready.
+      icon->SetIcon(kLockScreenSmartCardFailureIcon,
+                    AuthIconView::Color::kError);
+    }
     return;
   }
 
   switch (state_) {
     case SmartLockState::kPhoneNotFound:
-      FALLTHROUGH;
+      icon->SetIcon(kLockScreenSmartLockBluetoothIcon,
+                    AuthIconView::Color::kPrimary);
+      icon->RunErrorShakeAnimation();
+      return;
     case SmartLockState::kPhoneFoundLockedAndDistant:
       FALLTHROUGH;
     case SmartLockState::kPhoneFoundUnlockedAndDistant:
       FALLTHROUGH;
     case SmartLockState::kConnectingToPhone:
-      icon->SetImage(gfx::CreateVectorIcon(kLockScreenSmartLockBluetoothIcon,
-                                           kSmartLockIconSizeDp,
-                                           primary_color));
+      icon->SetIcon(kLockScreenSmartLockBluetoothIcon,
+                    AuthIconView::Color::kPrimary);
       return;
     case SmartLockState::kPhoneFoundLockedAndProximate:
-      icon->SetImage(gfx::CreateVectorIcon(
-          kLockScreenSmartLockPhoneIcon, kSmartLockIconSizeDp, primary_color));
+      icon->SetIcon(kLockScreenSmartLockPhoneIcon,
+                    AuthIconView::Color::kPrimary);
       return;
     case SmartLockState::kPrimaryUserAbsent:
       FALLTHROUGH;
@@ -198,9 +193,8 @@
     case SmartLockState::kPhoneNotLockable:
       FALLTHROUGH;
     case SmartLockState::kBluetoothDisabled:
-      icon->SetImage(gfx::CreateVectorIcon(kLockScreenSmartLockDisabledIcon,
-                                           kSmartLockIconSizeDp,
-                                           disabled_color));
+      icon->SetIcon(kLockScreenSmartLockDisabledIcon,
+                    AuthIconView::Color::kDisabled);
       return;
     case SmartLockState::kPhoneAuthenticated:
       // Click to enter -- icon handled by parent view.
@@ -213,7 +207,10 @@
   }
 }
 
-void SmartLockAuthFactorModel::OnTapOrClickEvent() {}
+void SmartLockAuthFactorModel::DoHandleTapOrClick() {
+  // Do Nothing: Smart Lock does not react to taps on its icon. Clicks on the
+  // arrow button are handled in LoginAuthFactorsView.
+}
 
 void SmartLockAuthFactorModel::OnArrowButtonTapOrClickEvent() {
   if (state_ == SmartLockState::kPhoneAuthenticated) {
@@ -221,6 +218,9 @@
   }
 }
 
-void SmartLockAuthFactorModel::OnErrorTimeout() {}
+void SmartLockAuthFactorModel::DoHandleErrorTimeout() {
+  // Do Nothing: Smart Lock has no temporary errors to restore from, so there is
+  // nothing to do.
+}
 
 }  // namespace ash
diff --git a/ash/login/ui/smart_lock_auth_factor_model.h b/ash/login/ui/smart_lock_auth_factor_model.h
index 7ab7cc1..3753efe9 100644
--- a/ash/login/ui/smart_lock_auth_factor_model.h
+++ b/ash/login/ui/smart_lock_auth_factor_model.h
@@ -35,14 +35,14 @@
 
  private:
   // AuthFactorModel:
-  AuthFactorState GetAuthFactorState() override;
-  AuthFactorType GetType() override;
-  int GetLabelId() override;
-  bool ShouldAnnounceLabel() override;
-  int GetAccessibleNameId() override;
+  AuthFactorState GetAuthFactorState() const override;
+  AuthFactorType GetType() const override;
+  int GetLabelId() const override;
+  bool ShouldAnnounceLabel() const override;
+  int GetAccessibleNameId() const override;
   void UpdateIcon(AuthIconView* icon) override;
-  void OnTapOrClickEvent() override;
-  void OnErrorTimeout() override;
+  void DoHandleTapOrClick() override;
+  void DoHandleErrorTimeout() override;
 
   base::RepeatingCallback<void()> arrow_button_tap_callback_;
   SmartLockState state_ = SmartLockState::kInactive;
diff --git a/ash/login/ui/smart_lock_auth_factor_model_unittest.cc b/ash/login/ui/smart_lock_auth_factor_model_unittest.cc
index d3b6ff286..14bad928 100644
--- a/ash/login/ui/smart_lock_auth_factor_model_unittest.cc
+++ b/ash/login/ui/smart_lock_auth_factor_model_unittest.cc
@@ -86,6 +86,22 @@
   }
 }
 
+TEST_F(SmartLockAuthFactorModelUnittest, ErrorStates) {
+  for (SmartLockState state : {SmartLockState::kPasswordReentryRequired,
+                               SmartLockState::kPrimaryUserAbsent,
+                               SmartLockState::kPhoneNotAuthenticated,
+                               SmartLockState::kBluetoothDisabled,
+                               SmartLockState::kPhoneNotLockable}) {
+    smart_lock_model_->SetSmartLockState(state);
+    EXPECT_TRUE(on_state_changed_called_);
+    EXPECT_EQ(AuthFactorState::kErrorPermanent, model_->GetAuthFactorState());
+    EXPECT_FALSE(model_->has_permanent_error_display_timed_out());
+    model_->HandleErrorTimeout();
+    EXPECT_TRUE(model_->has_permanent_error_display_timed_out());
+    on_state_changed_called_ = false;
+  }
+}
+
 TEST_F(SmartLockAuthFactorModelUnittest, ReadyStates) {
   smart_lock_model_->SetSmartLockState(
       SmartLockState::kPhoneFoundLockedAndProximate);
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 87649c1c..aa5ee54 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -232,12 +232,6 @@
     "projector/projector_controller.h",
     "projector/projector_session.cc",
     "projector/projector_session.h",
-    "quick_answers/controller/quick_answers_browser_client.cc",
-    "quick_answers/controller/quick_answers_browser_client.h",
-    "quick_answers/controller/quick_answers_controller.cc",
-    "quick_answers/controller/quick_answers_controller.h",
-    "quick_answers/quick_answers_state.cc",
-    "quick_answers/quick_answers_state.h",
     "resize_shadow_type.h",
     "rounded_corner_utils.cc",
     "rounded_corner_utils.h",
@@ -351,7 +345,6 @@
     "//ash/public/cpp/ambient/proto",
     "//ash/strings",
     "//base",
-    "//chromeos/components/quick_answers/public/cpp:prefs",
     "//chromeos/dbus/power:power_manager_proto",
     "//chromeos/services/assistant/public/cpp",
     "//chromeos/services/bluetooth_config:in_process_bluetooth_config",
diff --git a/ash/public/cpp/desk_template.cc b/ash/public/cpp/desk_template.cc
index bffd118..9c419c7 100644
--- a/ash/public/cpp/desk_template.cc
+++ b/ash/public/cpp/desk_template.cc
@@ -4,7 +4,11 @@
 
 #include "ash/public/cpp/desk_template.h"
 
+#include "ash/constants/app_types.h"
+#include "ash/constants/ash_features.h"
 #include "base/strings/utf_string_conversions.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
 
 namespace ash {
 
@@ -19,6 +23,30 @@
 
 DeskTemplate::~DeskTemplate() = default;
 
+// static
+bool DeskTemplate::IsAppTypeSupported(aura::Window* window) {
+  // For now we'll crostini and lacros windows in desk template. We'll also
+  // ignore ARC apps unless the flag is turned on.
+  const AppType app_type =
+      static_cast<AppType>(window->GetProperty(aura::client::kAppType));
+  switch (app_type) {
+    case AppType::NON_APP:
+    case AppType::CROSTINI_APP:
+    case AppType::LACROS:
+      return false;
+    case AppType::ARC_APP:
+      if (!features::AreDesksTemplatesEnabled())
+        return false;
+      break;
+    case AppType::BROWSER:
+    case AppType::CHROME_APP:
+    case AppType::SYSTEM_APP:
+      break;
+  }
+
+  return true;
+}
+
 DeskTemplate::DeskTemplate()
     : uuid_(base::GUID::GenerateRandomV4()),
       source_(DeskTemplateSource::kUnknownSource),
@@ -35,4 +63,4 @@
   return desk_template;
 }
 
-}  // namespace ash
\ No newline at end of file
+}  // namespace ash
diff --git a/ash/public/cpp/desk_template.h b/ash/public/cpp/desk_template.h
index 9f1dd89..928f98931 100644
--- a/ash/public/cpp/desk_template.h
+++ b/ash/public/cpp/desk_template.h
@@ -12,6 +12,10 @@
 #include "base/time/time.h"
 #include "components/app_restore/restore_data.h"
 
+namespace aura {
+class Window;
+}  // namespace aura
+
 namespace ash {
 
 // Indicates where a desk template originated from.
@@ -41,6 +45,9 @@
   DeskTemplate& operator=(const DeskTemplate&) = delete;
   ~DeskTemplate();
 
+  // Returns whether desk templates support the `window`'s app type.
+  static bool IsAppTypeSupported(aura::Window* window);
+
   base::GUID uuid() const { return uuid_; }
   DeskTemplateSource source() const { return source_; }
   base::Time created_time() const { return created_time_; }
diff --git a/ash/public/cpp/desks_templates_delegate.h b/ash/public/cpp/desks_templates_delegate.h
index 3b315f60..58c5c290 100644
--- a/ash/public/cpp/desks_templates_delegate.h
+++ b/ash/public/cpp/desks_templates_delegate.h
@@ -5,9 +5,12 @@
 #ifndef ASH_PUBLIC_CPP_DESKS_TEMPLATES_DELEGATE_H_
 #define ASH_PUBLIC_CPP_DESKS_TEMPLATES_DELEGATE_H_
 
+#include <string>
+
 #include "ash/public/cpp/ash_public_export.h"
 #include "components/favicon_base/favicon_callback.h"
 #include "components/services/app_service/public/cpp/icon_types.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace app_restore {
 struct AppLaunchInfo;
@@ -25,6 +28,10 @@
 class DeskModel;
 }
 
+namespace gfx {
+class ImageSkia;
+}
+
 namespace ash {
 
 class DeskTemplate;
@@ -47,6 +54,11 @@
   // backend depending on the feature flag DeskTemplateSync.
   virtual desks_storage::DeskModel* GetDeskModel() = 0;
 
+  // Returns the chrome icon if `page_url` is the new tab page, otherwise
+  // returns `absl::nullopt`.
+  virtual absl::optional<gfx::ImageSkia> MaybeRetrieveChromeIconForNTPUrl(
+      const std::string& page_url) const = 0;
+
   // Fetches the favicon for `page_url` and returns it via the provided
   // `callback`. `callback` may be called synchronously.
   virtual void GetFaviconForUrl(const std::string& page_url,
diff --git a/ash/public/cpp/quick_answers/test_support/BUILD.gn b/ash/public/cpp/quick_answers/test_support/BUILD.gn
deleted file mode 100644
index 2148d4a..0000000
--- a/ash/public/cpp/quick_answers/test_support/BUILD.gn
+++ /dev/null
@@ -1,18 +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.
-
-static_library("test_support") {
-  testonly = true
-
-  sources = [
-    "quick_answers_test_base.cc",
-    "quick_answers_test_base.h",
-  ]
-
-  deps = [
-    "//ash/public/cpp",
-    "//chromeos/services/assistant:test_support",
-    "//testing/gtest",
-  ]
-}
diff --git a/ash/public/cpp/test/test_desks_templates_delegate.cc b/ash/public/cpp/test/test_desks_templates_delegate.cc
index b8a8979..f62946b 100644
--- a/ash/public/cpp/test/test_desks_templates_delegate.cc
+++ b/ash/public/cpp/test/test_desks_templates_delegate.cc
@@ -4,11 +4,11 @@
 
 #include "ash/public/cpp/test/test_desks_templates_delegate.h"
 
-#include "ash/constants/app_types.h"
 #include "ash/public/cpp/desk_template.h"
 #include "components/app_restore/app_launch_info.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
+#include "ui/gfx/image/image_skia.h"
 
 namespace ash {
 
@@ -26,6 +26,12 @@
   return desk_model_;
 }
 
+absl::optional<gfx::ImageSkia>
+TestDesksTemplatesDelegate::MaybeRetrieveChromeIconForNTPUrl(
+    const std::string& page_url) const {
+  return absl::nullopt;
+}
+
 void TestDesksTemplatesDelegate::GetFaviconForUrl(
     const std::string& page_url,
     int desired_icon_size,
@@ -42,16 +48,7 @@
 
 bool TestDesksTemplatesDelegate::IsWindowSupportedForDeskTemplate(
     aura::Window* window) const {
-  const ash::AppType app_type =
-      static_cast<ash::AppType>(window->GetProperty(aura::client::kAppType));
-  switch (app_type) {
-    case AppType::CROSTINI_APP:
-    case AppType::LACROS:
-      return false;
-    default:
-      break;
-  }
-  return true;
+  return DeskTemplate::IsAppTypeSupported(window);
 }
 
 }  // namespace ash
diff --git a/ash/public/cpp/test/test_desks_templates_delegate.h b/ash/public/cpp/test/test_desks_templates_delegate.h
index ee5bade..f8a2f80 100644
--- a/ash/public/cpp/test/test_desks_templates_delegate.h
+++ b/ash/public/cpp/test/test_desks_templates_delegate.h
@@ -40,6 +40,8 @@
   std::unique_ptr<app_restore::AppLaunchInfo> GetAppLaunchDataForDeskTemplate(
       aura::Window* window) const override;
   desks_storage::DeskModel* GetDeskModel() override;
+  absl::optional<gfx::ImageSkia> MaybeRetrieveChromeIconForNTPUrl(
+      const std::string& page_url) const override;
   void GetFaviconForUrl(const std::string& page_url,
                         int desired_icon_size,
                         favicon_base::FaviconRawBitmapCallback callback,
diff --git a/ash/public/cpp/update_types.h b/ash/public/cpp/update_types.h
index 912b427..649505b0 100644
--- a/ash/public/cpp/update_types.h
+++ b/ash/public/cpp/update_types.h
@@ -32,13 +32,6 @@
   kSystem,
 };
 
-// Notification style for system updates, set by different policies.
-enum class NotificationStyle {
-  kDefault,
-  kAdminRecommended,  // Relaunch Notification policy
-  kAdminRequired,     // Relaunch Notification policy
-};
-
 // Notification state for system updates, set by policies.
 struct RelaunchNotificationState {
   enum {
diff --git a/ash/quick_pair/scanning/BUILD.gn b/ash/quick_pair/scanning/BUILD.gn
index 50a4366..cb8f5b3 100644
--- a/ash/quick_pair/scanning/BUILD.gn
+++ b/ash/quick_pair/scanning/BUILD.gn
@@ -16,10 +16,6 @@
     "fast_pair/fast_pair_scanner.h",
     "fast_pair/fast_pair_scanner_impl.cc",
     "fast_pair/fast_pair_scanner_impl.h",
-    "range_calculations.cc",
-    "range_calculations.h",
-    "range_tracker.cc",
-    "range_tracker.h",
     "scanner_broker.h",
     "scanner_broker_impl.cc",
     "scanner_broker_impl.h",
@@ -64,8 +60,6 @@
     "fast_pair/fast_pair_discoverable_scanner_unittest.cc",
     "fast_pair/fast_pair_not_discoverable_scanner_unittest.cc",
     "fast_pair/fast_pair_scanner_unittest.cc",
-    "range_calculations_unittest.cc",
-    "range_tracker_unittest.cc",
   ]
 
   deps = [
diff --git a/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner.cc b/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner.cc
index cd3870a..261d517 100644
--- a/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner.cc
+++ b/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner.cc
@@ -14,7 +14,6 @@
 #include "ash/quick_pair/common/logging.h"
 #include "ash/quick_pair/common/protocol.h"
 #include "ash/quick_pair/repository/fast_pair_repository.h"
-#include "ash/quick_pair/scanning/range_tracker.h"
 #include "ash/services/quick_pair/quick_pair_process.h"
 #include "ash/services/quick_pair/quick_pair_process_manager.h"
 #include "base/bind.h"
@@ -30,7 +29,6 @@
 namespace {
 
 constexpr char kNearbyShareModelId[] = "fc128e";
-constexpr double kDefaultRangeInMeters = 2;
 constexpr int kMaxParseModelIdRetryCount = 5;
 
 }  // namespace
@@ -40,11 +38,9 @@
 
 FastPairDiscoverableScanner::FastPairDiscoverableScanner(
     scoped_refptr<FastPairScanner> scanner,
-    std::unique_ptr<RangeTracker> range_tracker,
     DeviceCallback found_callback,
     DeviceCallback lost_callback)
     : scanner_(scanner),
-      range_tracker_(std::move(range_tracker)),
       found_callback_(std::move(found_callback)),
       lost_callback_(std::move(lost_callback)) {
   observation_.Observe(scanner.get());
@@ -104,7 +100,7 @@
 }
 
 void FastPairDiscoverableScanner::OnDeviceMetadataRetrieved(
-    device::BluetoothDevice* device,
+    device::BluetoothDevice* bluetooth_device,
     const std::string model_id,
     DeviceMetadata* device_metadata) {
   if (!device_metadata) {
@@ -114,27 +110,14 @@
     return;
   }
 
-  auto& details = device_metadata->GetDetails();
-  double trigger_distance;
-  if (details.trigger_distance() > 0) {
-    trigger_distance = details.trigger_distance();
-  } else {
-    NOTREACHED();
-    trigger_distance = kDefaultRangeInMeters;
-  }
+  QP_LOG(VERBOSE) << __func__ << ": Id: " << model_id;
 
-  QP_LOG(INFO) << __func__
-               << ": Checking if device is in range, and waiting if not.  "
-                  "trigger_distance="
-               << trigger_distance;
+  auto device = base::MakeRefCounted<Device>(
+      model_id, bluetooth_device->GetAddress(), Protocol::kFastPairInitial);
 
-  int tx_power = details.ble_tx_power();
+  notified_devices_[bluetooth_device->GetAddress()] = device;
 
-  range_tracker_->Track(
-      device, trigger_distance,
-      base::BindRepeating(&FastPairDiscoverableScanner::NotifyDeviceFound,
-                          weak_pointer_factory_.GetWeakPtr(), model_id),
-      tx_power == 0 ? absl::nullopt : absl::make_optional(tx_power));
+  found_callback_.Run(device);
 }
 
 void FastPairDiscoverableScanner::OnDeviceLost(
@@ -145,8 +128,6 @@
   // from this map will ensure the result is ignored.
   model_id_parse_attempts_.erase(device->GetAddress());
 
-  range_tracker_->StopTracking(device);
-
   auto it = notified_devices_.find(device->GetAddress());
 
   // Don't invoke callback if we didn't notify this device.
@@ -158,19 +139,6 @@
   lost_callback_.Run(std::move(notified_device));
 }
 
-void FastPairDiscoverableScanner::NotifyDeviceFound(
-    const std::string model_id,
-    device::BluetoothDevice* bluetooth_device) {
-  QP_LOG(VERBOSE) << __func__ << ": Id: " << model_id;
-
-  auto device = base::MakeRefCounted<Device>(
-      model_id, bluetooth_device->GetAddress(), Protocol::kFastPairInitial);
-
-  notified_devices_[bluetooth_device->GetAddress()] = device;
-
-  found_callback_.Run(device);
-}
-
 void FastPairDiscoverableScanner::OnUtilityProcessStopped(
     device::BluetoothDevice* device,
     QuickPairProcessManager::ShutdownReason shutdown_reason) {
diff --git a/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner.h b/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner.h
index 7cc7669..d617b79f 100644
--- a/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner.h
+++ b/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner.h
@@ -5,11 +5,9 @@
 #ifndef ASH_QUICK_PAIR_SCANNING_FAST_PAIR_FAST_PAIR_DISCOVERABLE_SCANNER_H_
 #define ASH_QUICK_PAIR_SCANNING_FAST_PAIR_FAST_PAIR_DISCOVERABLE_SCANNER_H_
 
-#include <memory>
 #include <string>
 
 #include "ash/quick_pair/scanning/fast_pair/fast_pair_scanner.h"
-#include "ash/quick_pair/scanning/range_tracker.h"
 #include "ash/services/quick_pair/quick_pair_process_manager.h"
 #include "base/callback_forward.h"
 #include "base/containers/flat_map.h"
@@ -37,7 +35,6 @@
 class FastPairDiscoverableScanner final : public FastPairScanner::Observer {
  public:
   FastPairDiscoverableScanner(scoped_refptr<FastPairScanner> scanner,
-                              std::unique_ptr<RangeTracker> range_tracker,
                               DeviceCallback found_callback,
                               DeviceCallback lost_callback);
   FastPairDiscoverableScanner(const FastPairDiscoverableScanner&) = delete;
@@ -52,8 +49,6 @@
  private:
   void OnModelIdRetrieved(device::BluetoothDevice* device,
                           const absl::optional<std::string>& model_id);
-  void NotifyDeviceFound(const std::string model_id,
-                         device::BluetoothDevice* device);
   void OnDeviceMetadataRetrieved(device::BluetoothDevice* device,
                                  const std::string model_id,
                                  DeviceMetadata* device_metadata);
@@ -62,7 +57,6 @@
       QuickPairProcessManager::ShutdownReason shutdown_reason);
 
   scoped_refptr<FastPairScanner> scanner_;
-  std::unique_ptr<RangeTracker> range_tracker_;
   DeviceCallback found_callback_;
   DeviceCallback lost_callback_;
   base::flat_map<std::string, scoped_refptr<Device>> notified_devices_;
diff --git a/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner_unittest.cc b/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner_unittest.cc
index 21805aa..a3bd237 100644
--- a/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner_unittest.cc
+++ b/ash/quick_pair/scanning/fast_pair/fast_pair_discoverable_scanner_unittest.cc
@@ -9,7 +9,6 @@
 #include "ash/quick_pair/common/device.h"
 #include "ash/quick_pair/repository/fake_fast_pair_repository.h"
 #include "ash/quick_pair/scanning/fast_pair/fake_fast_pair_scanner.h"
-#include "ash/quick_pair/scanning/range_tracker.h"
 #include "ash/services/quick_pair/fast_pair_data_parser.h"
 #include "ash/services/quick_pair/mock_quick_pair_process_manager.h"
 #include "ash/services/quick_pair/quick_pair_process.h"
@@ -68,10 +67,7 @@
         });
 
     discoverable_scanner_ = std::make_unique<FastPairDiscoverableScanner>(
-        scanner_,
-        std::make_unique<RangeTracker>(
-            static_cast<scoped_refptr<device::BluetoothAdapter>>(adapter_)),
-        found_device_callback_.Get(), lost_device_callback_.Get());
+        scanner_, found_device_callback_.Get(), lost_device_callback_.Get());
   }
 
   MockQuickPairProcessManager* mock_process_manager() {
@@ -79,29 +75,20 @@
   }
 
  protected:
-  std::unique_ptr<device::BluetoothDevice> GetInRangeDevice(
+  std::unique_ptr<device::BluetoothDevice> GetDevice(
       const std::string& hex_model_id,
       bool expect_call) {
-    testing::NiceMock<device::MockBluetoothDevice>* device =
-        new testing::NiceMock<device::MockBluetoothDevice>(
-            adapter_.get(), 0, "test_name", "test_address", /*paired=*/false,
-            /*connected=*/false);
+    auto device = std::make_unique<device::MockBluetoothDevice>(
+        adapter_.get(), 0, "test_name", "test_address", /*paired=*/false,
+        /*connected=*/false);
 
     if (!hex_model_id.empty()) {
       std::vector<uint8_t> model_id_bytes;
       base::HexStringToBytes(hex_model_id, &model_id_bytes);
       device->SetServiceDataForUUID(kFastPairBluetoothUuid, model_id_bytes);
-
-      EXPECT_CALL(*device, GetInquiryRSSI)
-          .Times(expect_call ? 1 : 0)
-          .WillOnce(testing::Return(-80));
-      EXPECT_CALL(*device, GetInquiryTxPower)
-          .Times(expect_call ? 1 : 0)
-          .WillOnce(testing::Return(-40));
-      ;
     }
 
-    return base::WrapUnique(static_cast<device::BluetoothDevice*>(device));
+    return device;
   }
 
   base::test::SingleThreadTaskEnvironment task_enviornment_;
@@ -122,7 +109,8 @@
   std::unique_ptr<device::BluetoothDevice> device =
       base::WrapUnique(static_cast<device::BluetoothDevice*>(
           new testing::NiceMock<device::MockBluetoothDevice>(
-              adapter_.get(), 0, "test_name", "test_address", /*paired=*/false,
+              adapter_.get(), 0, "test_name", "test_address",
+              /*paired=*/false,
               /*connected=*/false)));
 
   scanner_->NotifyDeviceFound(device.get());
@@ -132,7 +120,7 @@
 TEST_F(FastPairDiscoverableScannerTest, NoModelId) {
   EXPECT_CALL(found_device_callback_, Run).Times(0);
   std::unique_ptr<device::BluetoothDevice> device =
-      GetInRangeDevice("", /*expect_call=*/false);
+      GetDevice("", /*expect_call=*/false);
   scanner_->NotifyDeviceFound(device.get());
   base::RunLoop().RunUntilIdle();
 }
@@ -140,7 +128,7 @@
 TEST_F(FastPairDiscoverableScannerTest, ValidModelId) {
   EXPECT_CALL(found_device_callback_, Run).Times(1);
   std::unique_ptr<device::BluetoothDevice> device =
-      GetInRangeDevice(kValidModelId, /*expect_call=*/true);
+      GetDevice(kValidModelId, /*expect_call=*/true);
   scanner_->NotifyDeviceFound(device.get());
   base::RunLoop().RunUntilIdle();
 }
@@ -148,14 +136,14 @@
 TEST_F(FastPairDiscoverableScannerTest, NearbyShareModelId) {
   EXPECT_CALL(found_device_callback_, Run).Times(0);
   std::unique_ptr<device::BluetoothDevice> device =
-      GetInRangeDevice("fc128e", /*expect_call=*/false);
+      GetDevice("fc128e", /*expect_call=*/false);
   scanner_->NotifyDeviceFound(device.get());
   base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(FastPairDiscoverableScannerTest, InvokesLostCallbackAfterFound) {
   std::unique_ptr<device::BluetoothDevice> device =
-      GetInRangeDevice(kValidModelId, /*expect_call=*/true);
+      GetDevice(kValidModelId, /*expect_call=*/true);
 
   EXPECT_CALL(found_device_callback_, Run).Times(1);
   scanner_->NotifyDeviceFound(device.get());
@@ -173,7 +161,7 @@
   EXPECT_CALL(found_device_callback_, Run).Times(0);
   EXPECT_CALL(lost_device_callback_, Run).Times(0);
   std::unique_ptr<device::BluetoothDevice> device =
-      GetInRangeDevice(kValidModelId, /*expect_call=*/false);
+      GetDevice(kValidModelId, /*expect_call=*/false);
   scanner_->NotifyDeviceLost(device.get());
   base::RunLoop().RunUntilIdle();
 }
diff --git a/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner.cc b/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner.cc
index ba3b4144..c75d9a1 100644
--- a/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner.cc
+++ b/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner.cc
@@ -18,7 +18,6 @@
 #include "ash/quick_pair/repository/fast_pair/device_metadata.h"
 #include "ash/quick_pair/repository/fast_pair/pairing_metadata.h"
 #include "ash/quick_pair/repository/fast_pair_repository.h"
-#include "ash/quick_pair/scanning/range_tracker.h"
 #include "ash/services/quick_pair/public/cpp/account_key_filter.h"
 #include "ash/services/quick_pair/public/cpp/not_discoverable_advertisement.h"
 #include "ash/services/quick_pair/quick_pair_process.h"
@@ -77,11 +76,9 @@
 
 FastPairNotDiscoverableScanner::FastPairNotDiscoverableScanner(
     scoped_refptr<FastPairScanner> scanner,
-    std::unique_ptr<RangeTracker> range_tracker,
     DeviceCallback found_callback,
     DeviceCallback lost_callback)
     : scanner_(scanner),
-      range_tracker_(std::move(range_tracker)),
       found_callback_(std::move(found_callback)),
       lost_callback_(std::move(lost_callback)) {
   observation_.Observe(scanner.get());
@@ -120,8 +117,6 @@
   // the result is ignored.
   advertisement_parse_attempts_.erase(device->GetAddress());
 
-  range_tracker_->StopTracking(device);
-
   auto it = notified_devices_.find(device->GetAddress());
 
   // Don't invoke callback if we didn't notify this device.
@@ -169,9 +164,9 @@
 }
 
 void FastPairNotDiscoverableScanner::OnAccountKeyFilterCheckResult(
-    device::BluetoothDevice* device,
+    device::BluetoothDevice* bluetooth_device,
     absl::optional<PairingMetadata> metadata) {
-  account_key_filters_.erase(device->GetAddress());
+  account_key_filters_.erase(bluetooth_device->GetAddress());
 
   QP_LOG(VERBOSE) << __func__ << " Metadata: " << (metadata ? "yes" : "no");
 
@@ -180,34 +175,16 @@
 
   auto& details = metadata->device_metadata->GetDetails();
 
-  QP_LOG(INFO) << __func__
-               << ": Checking if device is in range, and waiting if not.  "
-                  "trigger_distance="
-               << details.trigger_distance();
-
   // Convert the integer model id to uppercase hex string.
   std::stringstream model_id_stream;
   model_id_stream << std::uppercase << std::hex << details.id();
+  std::string model_id = model_id_stream.str();
 
-  int tx_power = details.ble_tx_power();
-
-  range_tracker_->Track(
-      device, details.trigger_distance(),
-      base::BindRepeating(&FastPairNotDiscoverableScanner::NotifyDeviceFound,
-                          weak_pointer_factory_.GetWeakPtr(),
-                          model_id_stream.str(), metadata->account_key),
-      tx_power == 0 ? absl::nullopt : absl::make_optional(tx_power));
-}
-
-void FastPairNotDiscoverableScanner::NotifyDeviceFound(
-    const std::string model_id,
-    std::vector<uint8_t> account_key,
-    device::BluetoothDevice* bluetooth_device) {
   QP_LOG(VERBOSE) << __func__ << ": Id: " << model_id;
   auto device = base::MakeRefCounted<Device>(
       model_id, bluetooth_device->GetAddress(), Protocol::kFastPairSubsequent);
   device->SetAdditionalData(Device::AdditionalDataType::kAccountKey,
-                            account_key);
+                            metadata->account_key);
 
   notified_devices_[bluetooth_device->GetAddress()] = device;
 
diff --git a/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner.h b/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner.h
index 993fd9e..ee6316d 100644
--- a/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner.h
+++ b/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "ash/quick_pair/scanning/fast_pair/fast_pair_scanner.h"
-#include "ash/quick_pair/scanning/range_tracker.h"
 #include "ash/services/quick_pair/quick_pair_process_manager.h"
 #include "base/callback_forward.h"
 #include "base/containers/flat_map.h"
@@ -39,7 +38,6 @@
 class FastPairNotDiscoverableScanner final : public FastPairScanner::Observer {
  public:
   FastPairNotDiscoverableScanner(scoped_refptr<FastPairScanner> scanner,
-                                 std::unique_ptr<RangeTracker> range_tracker,
                                  DeviceCallback found_callback,
                                  DeviceCallback lost_callback);
   FastPairNotDiscoverableScanner(const FastPairNotDiscoverableScanner&) =
@@ -58,15 +56,11 @@
       const absl::optional<NotDiscoverableAdvertisement>& advertisement);
   void OnAccountKeyFilterCheckResult(device::BluetoothDevice* device,
                                      absl::optional<PairingMetadata> metadata);
-  void NotifyDeviceFound(const std::string model_id,
-                         std::vector<uint8_t> account_key,
-                         device::BluetoothDevice* device);
   void OnUtilityProcessStopped(
       device::BluetoothDevice* device,
       QuickPairProcessManager::ShutdownReason shutdown_reason);
 
   scoped_refptr<FastPairScanner> scanner_;
-  std::unique_ptr<RangeTracker> range_tracker_;
   DeviceCallback found_callback_;
   DeviceCallback lost_callback_;
   base::flat_map<std::string, scoped_refptr<Device>> notified_devices_;
diff --git a/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_unittest.cc b/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_unittest.cc
index 153bae8..651bce7 100644
--- a/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_unittest.cc
+++ b/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <cstdint>
 #include <iomanip>
+#include <memory>
 #include <sstream>
 #include <vector>
 
@@ -17,7 +18,6 @@
 #include "ash/quick_pair/repository/fast_pair/device_metadata.h"
 #include "ash/quick_pair/repository/fast_pair/pairing_metadata.h"
 #include "ash/quick_pair/scanning/fast_pair/fake_fast_pair_scanner.h"
-#include "ash/quick_pair/scanning/range_tracker.h"
 #include "ash/services/quick_pair/fast_pair_data_parser.h"
 #include "ash/services/quick_pair/mock_quick_pair_process_manager.h"
 #include "ash/services/quick_pair/quick_pair_process.h"
@@ -80,10 +80,8 @@
 
     not_discoverable_scanner_ =
         std::make_unique<FastPairNotDiscoverableScanner>(
-            scanner_,
-            std::make_unique<RangeTracker>(
-                static_cast<scoped_refptr<device::BluetoothAdapter>>(adapter_)),
-            found_device_callback_.Get(), lost_device_callback_.Get());
+            scanner_, found_device_callback_.Get(),
+            lost_device_callback_.Get());
   }
 
  protected:
@@ -135,25 +133,16 @@
         ->CreateServiceData();
   }
 
-  std::unique_ptr<device::BluetoothDevice> GetInRangeDevice(
+  std::unique_ptr<device::BluetoothDevice> GetDevice(
       const std::vector<uint8_t>& service_data,
       bool expect_call) {
-    testing::NiceMock<device::MockBluetoothDevice>* device =
-        new testing::NiceMock<device::MockBluetoothDevice>(
-            adapter_.get(), 0, "test_name", "test_address", /*paired=*/false,
-            /*connected=*/false);
+    auto device = std::make_unique<device::MockBluetoothDevice>(
+        adapter_.get(), 0, "test_name", "test_address", /*paired=*/false,
+        /*connected=*/false);
 
     device->SetServiceDataForUUID(kFastPairBluetoothUuid, service_data);
 
-    if (expect_call) {
-      EXPECT_CALL(*device, GetInquiryRSSI).WillOnce(testing::Return(-80));
-      EXPECT_CALL(*device, GetInquiryTxPower).WillOnce(testing::Return(-40));
-    } else {
-      EXPECT_CALL(*device, GetInquiryRSSI).Times(0);
-      EXPECT_CALL(*device, GetInquiryTxPower).Times(0);
-    }
-
-    return base::WrapUnique(static_cast<device::BluetoothDevice*>(device));
+    return device;
   }
 
   base::test::SingleThreadTaskEnvironment task_enviornment_;
@@ -185,8 +174,8 @@
 TEST_F(FastPairNotDiscoverableScannerTest, NoParsedAdvertisement) {
   EXPECT_CALL(found_device_callback_, Run).Times(0);
   std::unique_ptr<device::BluetoothDevice> device =
-      GetInRangeDevice(GetDiscoverableAdvServicedata(),
-                       /*expect_call=*/false);
+      GetDevice(GetDiscoverableAdvServicedata(),
+                /*expect_call=*/false);
   scanner_->NotifyDeviceFound(device.get());
   base::RunLoop().RunUntilIdle();
 }
@@ -194,7 +183,7 @@
 TEST_F(FastPairNotDiscoverableScannerTest, DontShowUI) {
   EXPECT_CALL(found_device_callback_, Run).Times(0);
   std::unique_ptr<device::BluetoothDevice> device =
-      GetInRangeDevice(GetAdvNoUiServicedata(), /*expect_call=*/false);
+      GetDevice(GetAdvNoUiServicedata(), /*expect_call=*/false);
   scanner_->NotifyDeviceFound(device.get());
   base::RunLoop().RunUntilIdle();
 }
@@ -202,14 +191,14 @@
 TEST_F(FastPairNotDiscoverableScannerTest, NoMetadata) {
   EXPECT_CALL(found_device_callback_, Run).Times(0);
   std::unique_ptr<device::BluetoothDevice> device =
-      GetInRangeDevice(GetAdvServicedata(), /*expect_call=*/false);
+      GetDevice(GetAdvServicedata(), /*expect_call=*/false);
   scanner_->NotifyDeviceFound(device.get());
   base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(FastPairNotDiscoverableScannerTest, InvokesLostCallbackAfterFound) {
   std::unique_ptr<device::BluetoothDevice> device =
-      GetInRangeDevice(GetAdvServicedata(), /*expect_call=*/true);
+      GetDevice(GetAdvServicedata(), /*expect_call=*/true);
 
   nearby::fastpair::GetObservedDeviceResponse response;
   response.mutable_device()->set_id(kModelIdLong);
@@ -237,7 +226,7 @@
   EXPECT_CALL(found_device_callback_, Run).Times(0);
   EXPECT_CALL(lost_device_callback_, Run).Times(0);
   std::unique_ptr<device::BluetoothDevice> device =
-      GetInRangeDevice(std::vector<uint8_t>(), /*expect_call=*/false);
+      GetDevice(std::vector<uint8_t>(), /*expect_call=*/false);
   scanner_->NotifyDeviceLost(device.get());
   base::RunLoop().RunUntilIdle();
 }
@@ -256,8 +245,8 @@
   EXPECT_CALL(found_device_callback_, Run).Times(1);
 
   std::unique_ptr<device::BluetoothDevice> device =
-      GetInRangeDevice(GetAdvBatteryServicedata(),
-                       /*expect_call=*/true);
+      GetDevice(GetAdvBatteryServicedata(),
+                /*expect_call=*/true);
   scanner_->NotifyDeviceFound(device.get());
   base::RunLoop().RunUntilIdle();
 
diff --git a/ash/quick_pair/scanning/range_calculations.cc b/ash/quick_pair/scanning/range_calculations.cc
deleted file mode 100644
index 55dfaed..0000000
--- a/ash/quick_pair/scanning/range_calculations.cc
+++ /dev/null
@@ -1,122 +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 "ash/quick_pair/scanning/range_calculations.h"
-
-#include <cmath>
-
-namespace {
-
-// See http://en.wikipedia.org/wiki/Free-space_path_loss.
-//
-// c   = speed of light (2.9979 x 10^8 m/s);
-// f   = frequency (Bluetooth center frequency is 2.44175GHz = 2.44175x10^9 Hz);
-// l   = wavelength (in meters);
-// d   = distance (from transmitter to receiver in meters);
-// dB  = decibels
-// dBm = decibel milliwatts
-//
-// Free-space path loss (FSPL) is proportional to the square of the distance
-// between the transmitter and the receiver, and also proportional to the square
-// of the frequency of the radio signal.
-//
-// FSPL      = (4 * pi * d / l)^2 = (4 * pi * d * f / c)^2
-//
-// FSPL (dB) = 10 * log10((4 * pi * d  * f / c)^2)
-//           = 20 * log10(4 * pi * d * f / c)
-//           = (20 * log10(d)) + (20 * log10(f)) + (20 * log10(4 * pi/c))
-//
-// Calculating constants:
-//
-// FSPL_FREQ        = 20 * log10(f)
-//                  = 20 * log10(2.44175 * 10^9)
-//                  = 187.75
-//
-// FSPL_LIGHT       = 20 * log10(4 * pi/c)
-//                  = 20 * log10(4 * pi/(2.9979 * 10^8))
-//                  = 20 * log10(4 * pi/(2.9979 * 10^8))
-//                  = 20 * log10(41.9172441s * 10^-9)
-//                  = -147.55
-//
-// FSPL_DISTANCE_1M = 20 * log10(1)
-//                  = 0
-//
-// PATH_LOSS_AT_1M  = FSPL_DISTANCE_1M + FSPL_FREQ + FSPL_LIGHT
-//                  =       0          + 187.75    + (-147.55)
-//                  = 40.20db [round to 41db]
-//
-// Note: Rounding up makes us "closer" and makes us more aggressive at showing
-// notifications.
-constexpr int kRssiDropOffAtOneMeter = 41;
-
-}  // namespace
-
-namespace ash {
-namespace quick_pair {
-namespace range_calculations {
-
-int8_t RssiFromTargetDistance(double distance_in_meters, int8_t tx_power) {
-  // See https://en.wikipedia.org/wiki/Log-distance_path_loss_model
-  //
-  // PL       = total path loss in db
-  // tx_power = TxPower in dbm
-  // rssi     = Received signal strength in dbm
-  // PL_0     = Path loss at reference distance d_0 kRssiDropOffAtOneMeter dbm
-  // d        = length of path
-  // d_0      = reference distance  (1 m)
-  // gamma    = path loss exponent (2 in free space)
-  //
-  // Log-distance path loss (LDPL) formula:
-  //
-  // PL = tx_power - rssi = PL_0 + 10 * gamma * log_10(d / d_0)
-  //
-  // PL = tx_power - rssi = kRssiDropOffAtOneMeter + 10 * 2 *
-  //      log_10(distanceInMeters / 1)
-  //
-  // PL = - rssi = -tx_power + kRssiDropOffAtOneMeter + 20 *
-  //               log_10(distanceInMeters)
-  //
-  // PL = rssi = tx_power - kRssiDropOffAtOneMeter - 20 *
-  //             log_10(distanceInMeters)
-  return distance_in_meters <= 0 ? tx_power
-                                 : floor((tx_power - kRssiDropOffAtOneMeter) -
-                                         20 * log10(distance_in_meters));
-}
-
-double DistanceFromRssiAndTxPower(int8_t rssi, int8_t tx_power) {
-  // See https://en.wikipedia.org/wiki/Log-distance_path_loss_model
-  //
-  // PL       = total path loss in db
-  // tx_power = TxPower in dbm
-  // rssi     = Received signal strength in dbm
-  // PL_0     = Path loss at reference distance d_0 kRssiDropOffAtOneMeter} dbm
-  // d        = length of path
-  // d_0      = reference distance  (1 m)
-  // gamma    = path loss exponent (2 in free space)
-  //
-  // Log-distance path loss (LDPL) formula:
-  //
-  // PL = tx_power - rssi = PL_0 + 10 * gamma  * log_10(d / d_0)
-  //
-  // PL = tx_power - rssi = kRssiDropOffAtOneMeter + 10 * gamma * log_10(d /
-  // d_0)
-  //
-  // PL = tx_power - rssi - kRssiDropOffAtOneMeter = 10 * 2 *
-  // log_10(distanceInMeters / 1)
-  //
-  // PL = tx_power - rssi - kRssiDropOffAtOneMeter = 20 *
-  // log_10(distanceInMeters / 1)
-  //
-  // PL = (tx_power - rssi - kRssiDropOffAtOneMeter) / 20 =
-  // log_10(distanceInMeters)
-  //
-  // PL = 10 ^ ((tx_power - rssi - kRssiDropOffAtOneMeter) / 20) =
-  // distanceInMeters
-  //
-  return pow(10, (tx_power - rssi - kRssiDropOffAtOneMeter) / 20.0);
-}
-
-}  // namespace range_calculations
-}  // namespace quick_pair
-}  // namespace ash
diff --git a/ash/quick_pair/scanning/range_calculations.h b/ash/quick_pair/scanning/range_calculations.h
deleted file mode 100644
index c0e84eb..0000000
--- a/ash/quick_pair/scanning/range_calculations.h
+++ /dev/null
@@ -1,28 +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 ASH_QUICK_PAIR_SCANNING_RANGE_CALCULATIONS_H_
-#define ASH_QUICK_PAIR_SCANNING_RANGE_CALCULATIONS_H_
-
-#include <stdint.h>
-
-namespace ash {
-namespace quick_pair {
-namespace range_calculations {
-
-// Convert target distance and txPower to a RSSI value using the Log-distance
-// path loss model with Path Loss at 1m of 41db.
-// See https://en.wikipedia.org/wiki/Log-distance_path_loss_model
-int8_t RssiFromTargetDistance(double distance_in_meters, int8_t tx_power);
-
-// Convert RSSI and txPower to a distance value using the Log-distance path loss
-// model with Path Loss at 1m of 41db.
-// See https://en.wikipedia.org/wiki/Log-distance_path_loss_model
-double DistanceFromRssiAndTxPower(int8_t rssi, int8_t tx_power);
-
-}  // namespace range_calculations
-}  // namespace quick_pair
-}  // namespace ash
-
-#endif  // ASH_QUICK_PAIR_SCANNING_RANGE_CALCULATIONS_H_
diff --git a/ash/quick_pair/scanning/range_calculations_unittest.cc b/ash/quick_pair/scanning/range_calculations_unittest.cc
deleted file mode 100644
index 513b198..0000000
--- a/ash/quick_pair/scanning/range_calculations_unittest.cc
+++ /dev/null
@@ -1,39 +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 "ash/quick_pair/scanning/range_calculations.h"
-
-#include <cmath>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash {
-namespace quick_pair {
-namespace range_calculations {
-
-class RangeCalculationsTest : public testing::Test {};
-
-TEST_F(RangeCalculationsTest,
-       RssiFromTargetDistance_ReturnsTxPowerForZeroDistance) {
-  int8_t tx_power = 1;
-  EXPECT_EQ(RssiFromTargetDistance(0, tx_power), tx_power);
-}
-
-TEST_F(RangeCalculationsTest,
-       RssiFromTargetDistance_ReturnsTxPowerForNegativeDistance) {
-  int8_t tx_power = 1;
-  EXPECT_EQ(RssiFromTargetDistance(-10, tx_power), tx_power);
-}
-
-TEST_F(RangeCalculationsTest, RssiFromTargetDistance) {
-  EXPECT_EQ(RssiFromTargetDistance(2, -40), -88);
-}
-
-TEST_F(RangeCalculationsTest, DistanceFromRssiAndTxPower) {
-  EXPECT_EQ(floor(DistanceFromRssiAndTxPower(-100, -24)), 56);
-}
-
-}  // namespace range_calculations
-}  // namespace quick_pair
-}  // namespace ash
diff --git a/ash/quick_pair/scanning/range_tracker.cc b/ash/quick_pair/scanning/range_tracker.cc
deleted file mode 100644
index d52152b4..0000000
--- a/ash/quick_pair/scanning/range_tracker.cc
+++ /dev/null
@@ -1,154 +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 "ash/quick_pair/scanning/range_tracker.h"
-
-#include <tuple>
-
-#include "ash/quick_pair/common/logging.h"
-#include "ash/quick_pair/scanning/range_calculations.h"
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/timer/timer.h"
-#include "device/bluetooth/bluetooth_adapter.h"
-#include "device/bluetooth/bluetooth_device.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-
-using device::BluetoothAdapter;
-using device::BluetoothDevice;
-
-namespace ash {
-namespace quick_pair {
-
-// The amount of time we will wait for the rssi and tx power values to be
-// reported before timing out and assuming the device is in range.
-constexpr int kTimeOutInSeconds = 1;
-
-RangeTracker::RangeTracker(scoped_refptr<BluetoothAdapter> adapter)
-    : adapter_(adapter) {
-  observation_.Observe(adapter_.get());
-}
-
-RangeTracker::~RangeTracker() = default;
-
-void RangeTracker::Track(BluetoothDevice* device,
-                         double threshold_in_meters,
-                         RangeTrackerCallback callback,
-                         const absl::optional<int8_t>& known_tx_power) {
-  // Immediately save a TrackingInfo object because IsDevicewithinThreshold will
-  // query for it.
-  auto it = device_callbacks_.emplace(
-      device->GetAddress(),
-      TrackingInfo(threshold_in_meters, std::move(callback), known_tx_power));
-
-  if (IsDeviceWithinThreshold(device, threshold_in_meters, known_tx_power)) {
-    // Immediately invoke callback if device is already in range.
-    std::move(it.first->second.callback).Run(device);
-    device_callbacks_.erase(device->GetAddress());
-  }
-}
-
-bool RangeTracker::IsDeviceWithinThreshold(
-    BluetoothDevice* device,
-    double threshold_in_meters,
-    const absl::optional<int8_t>& known_tx_power) {
-  absl::optional<int8_t> rssi = device->GetInquiryRSSI();
-  absl::optional<int8_t> tx_power =
-      known_tx_power.has_value() ? known_tx_power : device->GetInquiryTxPower();
-
-  auto it = device_callbacks_.find(device->GetAddress());
-  DCHECK(it != device_callbacks_.end());
-
-  if ((!rssi || !tx_power) && !it->second.timeout_timer.IsRunning()) {
-    // Start timeout if there is no rssi or tx power values currently.
-    it->second.timeout_timer.Start(
-        FROM_HERE, base::Seconds(kTimeOutInSeconds),
-        base::BindOnce(&RangeTracker::OnTimeout,
-                       weak_pointer_factory_.GetWeakPtr(),
-                       device->GetAddress()));
-  }
-
-  if (!rssi) {
-    QP_LOG(WARNING) << "RSSI value isn't available for device.";
-    return false;
-  }
-
-  if (!tx_power) {
-    QP_LOG(WARNING) << "TxPower value isn't available for device.";
-    return false;
-  }
-
-  // We have a rssi and tx_power value for this device, stop the timeout.
-  it->second.timeout_timer.AbandonAndStop();
-
-  return range_calculations::DistanceFromRssiAndTxPower(
-             rssi.value(), tx_power.value()) <= threshold_in_meters;
-}
-
-void RangeTracker::DeviceChanged(BluetoothAdapter* adapter,
-                                 BluetoothDevice* device) {
-  auto it = device_callbacks_.find(device->GetAddress());
-
-  // Early return if we aren't tracking this device.
-  if (it == device_callbacks_.end())
-    return;
-
-  TrackingInfo& info = it->second;
-
-  if (IsDeviceWithinThreshold(device, info.threshold_in_meters,
-                              info.known_tx_power)) {
-    std::move(info.callback).Run(device);
-    device_callbacks_.erase(it);
-  }
-}
-
-void RangeTracker::StopTracking(BluetoothDevice* device) {
-  device_callbacks_.erase(device->GetAddress());
-}
-
-void RangeTracker::OnTimeout(const std::string& address) {
-  QP_LOG(WARNING) << __func__
-                  << ": Timed out waiting for device info (rssi, tx power).";
-  auto it = device_callbacks_.find(address);
-
-  // Return early if we are no longer tracking this device.
-  if (it == device_callbacks_.end()) {
-    QP_LOG(WARNING) << __func__ << ": No device info from callbacks";
-    return;
-  }
-
-  BluetoothDevice* device = adapter_->GetDevice(address);
-
-  if (!device) {
-    QP_LOG(WARNING) << __func__ << ": No device from adapter";
-    device_callbacks_.erase(it);
-    return;
-  }
-
-  std::move(it->second.callback).Run(device);
-  device_callbacks_.erase(it);
-}
-
-RangeTracker::TrackingInfo::TrackingInfo() = default;
-
-RangeTracker::TrackingInfo::TrackingInfo(double threshold_in_meters,
-                                         RangeTrackerCallback callback,
-                                         absl::optional<int8_t> known_tx_power)
-    : threshold_in_meters(threshold_in_meters),
-      callback(std::move(callback)),
-      known_tx_power(known_tx_power) {}
-
-RangeTracker::TrackingInfo::TrackingInfo(TrackingInfo&& other) {
-  DCHECK(!other.timeout_timer.IsRunning())
-      << "This move constructor is written with the assumption that the timer"
-         "field is not running, and thus can be made new again";
-  threshold_in_meters = other.threshold_in_meters;
-  callback = std::move(other.callback);
-  known_tx_power = std::move(other.known_tx_power);
-}
-
-RangeTracker::TrackingInfo::~TrackingInfo() = default;
-
-}  // namespace quick_pair
-}  // namespace ash
diff --git a/ash/quick_pair/scanning/range_tracker.h b/ash/quick_pair/scanning/range_tracker.h
deleted file mode 100644
index 36874a0..0000000
--- a/ash/quick_pair/scanning/range_tracker.h
+++ /dev/null
@@ -1,88 +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 ASH_QUICK_PAIR_SCANNING_RANGE_TRACKER_H_
-#define ASH_QUICK_PAIR_SCANNING_RANGE_TRACKER_H_
-
-#include <stdint.h>
-#include <cstdint>
-#include <map>
-#include <utility>
-#include "base/callback_forward.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/scoped_observation.h"
-#include "base/timer/timer.h"
-#include "device/bluetooth/bluetooth_adapter.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-
-namespace device {
-class BluetoothDevice;
-}  // namespace device
-
-namespace ash {
-namespace quick_pair {
-
-using RangeTrackerCallback = base::OnceCallback<void(device::BluetoothDevice*)>;
-
-// RangeTracker provides an API to invoke a callback when a BluetoothDevice
-// enters a given threshold range.
-class RangeTracker final : public device::BluetoothAdapter::Observer {
- public:
-  explicit RangeTracker(scoped_refptr<device::BluetoothAdapter> adapter);
-  RangeTracker(const RangeTracker&) = delete;
-  RangeTracker& operator=(const RangeTracker&) = delete;
-  ~RangeTracker() override;
-
-  // Start tracking |device| and invoke |callback| once it is within
-  // |threshold_in_meters|. |callback| is invoked immediately if the device
-  // is already in range, otherwise it is saved and invoked later when/if the
-  // |device| comes into range.
-  // Populate |known_tx_power| if you know the value the device is using,
-  // otherwise BluetoothDevice::GetInquiryTxPower is used.
-  // If |device| is already being tracked, the previous values are overridden.
-  void Track(device::BluetoothDevice* device,
-             double threshold_in_meters,
-             RangeTrackerCallback callback,
-             const absl::optional<int8_t>& known_tx_power = absl::nullopt);
-
-  void StopTracking(device::BluetoothDevice* device);
-
-  // BluetoothAdapter::Observer
-  void DeviceChanged(device::BluetoothAdapter* adapter,
-                     device::BluetoothDevice* device) override;
-
- private:
-  struct TrackingInfo {
-    TrackingInfo();
-    TrackingInfo(double threshold_in_meters,
-                 RangeTrackerCallback callback,
-                 absl::optional<int8_t> known_tx_power);
-    TrackingInfo(TrackingInfo&&);
-    ~TrackingInfo();
-
-    double threshold_in_meters;
-    RangeTrackerCallback callback;
-    absl::optional<int8_t> known_tx_power;
-    base::OneShotTimer timeout_timer;
-  };
-
-  bool IsDeviceWithinThreshold(device::BluetoothDevice* device,
-                               double threshold_in_meters,
-                               const absl::optional<int8_t>& known_tx_power);
-
-  void OnTimeout(const std::string& device_address);
-
-  scoped_refptr<device::BluetoothAdapter> adapter_;
-  std::map<std::string, TrackingInfo> device_callbacks_;
-  base::ScopedObservation<device::BluetoothAdapter,
-                          device::BluetoothAdapter::Observer>
-      observation_{this};
-  base::WeakPtrFactory<RangeTracker> weak_pointer_factory_{this};
-};
-
-}  // namespace quick_pair
-}  // namespace ash
-
-#endif  //  ASH_QUICK_PAIR_SCANNING_RANGE_TRACKER_H_
diff --git a/ash/quick_pair/scanning/range_tracker_unittest.cc b/ash/quick_pair/scanning/range_tracker_unittest.cc
deleted file mode 100644
index d010821..0000000
--- a/ash/quick_pair/scanning/range_tracker_unittest.cc
+++ /dev/null
@@ -1,139 +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 "ash/quick_pair/scanning/range_tracker.h"
-
-#include <cstdint>
-#include <memory>
-
-#include "base/test/mock_callback.h"
-#include "base/test/task_environment.h"
-#include "device/bluetooth/bluetooth_adapter.h"
-#include "device/bluetooth/bluetooth_adapter_factory.h"
-#include "device/bluetooth/test/mock_bluetooth_adapter.h"
-#include "device/bluetooth/test/mock_bluetooth_device.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-const std::string kAddress = "Test address";
-
-class FakeBluetoothAdapter
-    : public testing::NiceMock<device::MockBluetoothAdapter> {
- public:
-  void NotifiyDeviceChanged(device::BluetoothDevice* device) {
-    device::BluetoothAdapter::NotifyDeviceChanged(device);
-  }
-
- private:
-  ~FakeBluetoothAdapter() override = default;
-};
-
-}  // namespace
-
-namespace ash {
-namespace quick_pair {
-
-class RangeTrackerTest : public testing::Test {
- public:
-  void SetUp() override {
-    adapter_ = base::MakeRefCounted<FakeBluetoothAdapter>();
-    tracker_ = std::make_unique<RangeTracker>(
-        static_cast<scoped_refptr<device::BluetoothAdapter>>(adapter_));
-    device_ = std::make_unique<device::MockBluetoothDevice>(
-        adapter_.get(),
-        /*bluetooth_class=*/0, "Test device name", kAddress,
-        /*paired=*/false,
-        /*connected=*/false);
-
-    ON_CALL(*(adapter_.get()), GetDevice(kAddress))
-        .WillByDefault(testing::Return(device_.get()));
-  }
-
- protected:
-  void SetRssiAndTxPower(int8_t rssi, int8_t tx_power) {
-    EXPECT_CALL(*(device_.get()), GetInquiryRSSI)
-        .WillOnce(testing::Return(rssi));
-    EXPECT_CALL(*(device_.get()), GetInquiryTxPower)
-        .WillOnce(testing::Return(tx_power));
-  }
-
-  base::test::TaskEnvironment task_environment_{
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-  std::unique_ptr<device::MockBluetoothDevice> device_;
-  scoped_refptr<FakeBluetoothAdapter> adapter_;
-  std::unique_ptr<RangeTracker> tracker_;
-  base::MockCallback<base::OnceCallback<void(device::BluetoothDevice*)>>
-      callback_;
-};
-
-TEST_F(RangeTrackerTest, DeviceAlreadyInRange) {
-  SetRssiAndTxPower(-88, -40);
-  EXPECT_CALL(callback_, Run(device_.get()));
-  tracker_->Track(device_.get(), 3, callback_.Get());
-}
-
-TEST_F(RangeTrackerTest, DeviceAlreadyInRange_KnownTxPower) {
-  EXPECT_CALL(*(device_.get()), GetInquiryRSSI).WillOnce(testing::Return(-88));
-  EXPECT_CALL(*(device_.get()), GetInquiryTxPower).Times(0);
-  EXPECT_CALL(callback_, Run(device_.get()));
-  tracker_->Track(device_.get(), 3, callback_.Get(), -40);
-}
-
-TEST_F(RangeTrackerTest, DeviceNotInRange) {
-  SetRssiAndTxPower(-88, -40);
-  EXPECT_CALL(callback_, Run(device_.get())).Times(0);
-  tracker_->Track(device_.get(), 2, callback_.Get());
-}
-
-TEST_F(RangeTrackerTest, DeviceComesIntoRange) {
-  SetRssiAndTxPower(-100, -40);
-  EXPECT_CALL(callback_, Run(device_.get())).Times(0);
-  tracker_->Track(device_.get(), 3, callback_.Get());
-
-  SetRssiAndTxPower(-88, -40);
-  EXPECT_CALL(callback_, Run(device_.get()));
-  adapter_->NotifiyDeviceChanged(device_.get());
-}
-
-TEST_F(RangeTrackerTest, DoesntCallbackForUntrackedDevice) {
-  SetRssiAndTxPower(-88, -40);
-  EXPECT_CALL(callback_, Run(device_.get())).Times(0);
-  tracker_->Track(device_.get(), 2, callback_.Get());
-
-  std::unique_ptr<device::MockBluetoothDevice> untracked_device =
-      std::make_unique<device::MockBluetoothDevice>(
-          adapter_.get(),
-          /*bluetooth_class=*/0, "Untracked device", "Untracked address",
-          /*paired=*/false,
-          /*connected=*/false);
-
-  EXPECT_CALL(*(untracked_device.get()), GetInquiryRSSI).Times(0);
-  EXPECT_CALL(*(untracked_device.get()), GetInquiryTxPower).Times(0);
-  EXPECT_CALL(callback_, Run).Times(0);
-
-  adapter_->NotifiyDeviceChanged(untracked_device.get());
-}
-
-TEST_F(RangeTrackerTest, StopTracking) {
-  SetRssiAndTxPower(-100, -40);
-  EXPECT_CALL(callback_, Run(device_.get())).Times(0);
-  tracker_->Track(device_.get(), 3, callback_.Get());
-
-  EXPECT_CALL(callback_, Run).Times(0);
-  EXPECT_CALL(*(device_.get()), GetInquiryRSSI).Times(0);
-  EXPECT_CALL(*(device_.get()), GetInquiryTxPower).Times(0);
-
-  tracker_->StopTracking(device_.get());
-  adapter_->NotifiyDeviceChanged(device_.get());
-}
-
-TEST_F(RangeTrackerTest, Timeout) {
-  EXPECT_CALL(callback_, Run(device_.get()));
-  tracker_->Track(device_.get(), 3, callback_.Get());
-  task_environment_.FastForwardUntilNoTasksRemain();
-}
-
-}  // namespace quick_pair
-}  // namespace ash
diff --git a/ash/quick_pair/scanning/scanner_broker_impl.cc b/ash/quick_pair/scanning/scanner_broker_impl.cc
index 31dd61d0..25d634f 100644
--- a/ash/quick_pair/scanning/scanner_broker_impl.cc
+++ b/ash/quick_pair/scanning/scanner_broker_impl.cc
@@ -13,7 +13,6 @@
 #include "ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner.h"
 #include "ash/quick_pair/scanning/fast_pair/fast_pair_scanner.h"
 #include "ash/quick_pair/scanning/fast_pair/fast_pair_scanner_impl.h"
-#include "ash/quick_pair/scanning/range_tracker.h"
 #include "ash/services/quick_pair/quick_pair_process_manager.h"
 #include "base/bind.h"
 #include "base/callback.h"
@@ -104,7 +103,7 @@
 
   fast_pair_discoverable_scanner_ =
       std::make_unique<FastPairDiscoverableScanner>(
-          fast_pair_scanner, std::make_unique<RangeTracker>(adapter_),
+          fast_pair_scanner,
           base::BindRepeating(&ScannerBrokerImpl::NotifyDeviceFound,
                               weak_pointer_factory_.GetWeakPtr()),
           base::BindRepeating(&ScannerBrokerImpl::NotifyDeviceLost,
@@ -112,7 +111,7 @@
 
   fast_pair_not_discoverable_scanner_ =
       std::make_unique<FastPairNotDiscoverableScanner>(
-          fast_pair_scanner, std::make_unique<RangeTracker>(adapter_),
+          fast_pair_scanner,
           base::BindRepeating(&ScannerBrokerImpl::NotifyDeviceFound,
                               weak_pointer_factory_.GetWeakPtr()),
           base::BindRepeating(&ScannerBrokerImpl::NotifyDeviceLost,
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 0236891..b7ac2f1 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -181,15 +181,12 @@
     "phone_hub_camera_roll_item_video.icon",
     "phone_hub_camera_roll_menu_download.icon",
     "phone_hub_default_favicon.icon",
-    "phone_hub_enable_hotspot_off.icon",
-    "phone_hub_enable_hotspot_on.icon",
-    "phone_hub_locate_phone_off.icon",
-    "phone_hub_locate_phone_on.icon",
+    "phone_hub_enable_hotspot.icon",
+    "phone_hub_locate_phone.icon",
     "phone_hub_mobile_no_connection.icon",
     "phone_hub_mobile_no_sim.icon",
     "phone_hub_phone.icon",
-    "phone_hub_silence_phone_off.icon",
-    "phone_hub_silence_phone_on.icon",
+    "phone_hub_silence_phone.icon",
     "pin_request_lock.icon",
     "pinned.icon",
     "privacy_screen.icon",
diff --git a/ash/resources/vector_icons/phone_hub_enable_hotspot_on.icon b/ash/resources/vector_icons/phone_hub_enable_hotspot.icon
similarity index 100%
rename from ash/resources/vector_icons/phone_hub_enable_hotspot_on.icon
rename to ash/resources/vector_icons/phone_hub_enable_hotspot.icon
diff --git a/ash/resources/vector_icons/phone_hub_enable_hotspot_off.icon b/ash/resources/vector_icons/phone_hub_enable_hotspot_off.icon
deleted file mode 100644
index ece1111d..0000000
--- a/ash/resources/vector_icons/phone_hub_enable_hotspot_off.icon
+++ /dev/null
@@ -1,37 +0,0 @@
-CANVAS_DIMENSIONS, 20,
-MOVE_TO, 2, 2.09f,
-LINE_TO, 17.56f, 17.64f,
-R_LINE_TO, -1.41f, 1.41f,
-R_LINE_TO, -9.09f, -9.09f,
-CUBIC_TO, 7.02f, 10.14f, 7, 10.32f, 7, 10.5f,
-R_CUBIC_TO, 0, 0.91f, 0.4f, 1.72f, 1.04f, 2.27f,
-R_LINE_TO, -1.49f, 1.34f,
-CUBIC_TO, 5.59f, 13.2f, 5, 11.92f, 5, 10.5f,
-R_CUBIC_TO, 0, -0.76f, 0.17f, -1.47f, 0.47f, -2.12f,
-LINE_TO, 4.36f, 7.27f,
-CUBIC_TO, 3.81f, 8.22f, 3.5f, 9.33f, 3.5f, 10.5f,
-R_CUBIC_TO, 0, 1.81f, 0.74f, 3.44f, 1.93f, 4.62f,
-R_LINE_TO, -1.49f, 1.34f,
-CUBIC_TO, 2.43f, 14.92f, 1.5f, 12.82f, 1.5f, 10.5f,
-R_CUBIC_TO, 0, -1.73f, 0.52f, -3.34f, 1.4f, -4.68f,
-LINE_TO, 0.59f, 3.5f,
-LINE_TO, 2, 2.09f,
-CLOSE,
-MOVE_TO, 10, 2,
-R_CUBIC_TO, 4.69f, 0, 8.5f, 3.81f, 8.5f, 8.5f,
-R_CUBIC_TO, 0, 1.45f, -0.36f, 2.81f, -1, 4,
-R_LINE_TO, -1.5f, -1.5f,
-CUBIC_TO, 16.32f, 12.23f, 16.5f, 11.39f, 16.5f, 10.5f,
-CUBIC_TO, 16.5f, 6.91f, 13.59f, 4, 10, 4,
-R_CUBIC_TO, -0.89f, 0, -1.73f, 0.18f, -2.5f, 0.5f,
-LINE_TO, 6, 3,
-CUBIC_TO, 7.19f, 2.36f, 8.55f, 2, 10, 2,
-CLOSE,
-R_MOVE_TO, 0, 3.5f,
-R_CUBIC_TO, 2.76f, 0, 5, 2.24f, 5, 5,
-R_CUBIC_TO, 0, 0.46f, -0.06f, 0.9f, -0.18f, 1.32f,
-R_LINE_TO, -1.87f, -1.87f,
-R_CUBIC_TO, -0.23f, -1.22f, -1.18f, -2.17f, -2.4f, -2.4f,
-LINE_TO, 8.68f, 5.68f,
-CUBIC_TO, 9.1f, 5.56f, 9.54f, 5.5f, 10, 5.5f,
-CLOSE
diff --git a/ash/resources/vector_icons/phone_hub_locate_phone_on.icon b/ash/resources/vector_icons/phone_hub_locate_phone.icon
similarity index 100%
rename from ash/resources/vector_icons/phone_hub_locate_phone_on.icon
rename to ash/resources/vector_icons/phone_hub_locate_phone.icon
diff --git a/ash/resources/vector_icons/phone_hub_locate_phone_off.icon b/ash/resources/vector_icons/phone_hub_locate_phone_off.icon
deleted file mode 100644
index 38649e71..0000000
--- a/ash/resources/vector_icons/phone_hub_locate_phone_off.icon
+++ /dev/null
@@ -1,55 +0,0 @@
-CANVAS_DIMENSIONS, 20,
-MOVE_TO, 2, 2.09f,
-LINE_TO, 17.56f, 17.64f,
-R_LINE_TO, -1.41f, 1.41f,
-R_LINE_TO, -1.29f, -1.29f,
-R_CUBIC_TO, -0.28f, 0.68f, -0.93f, 1.18f, -1.7f, 1.23f,
-LINE_TO, 13, 19,
-H_LINE_TO, 5,
-R_CUBIC_TO, -1.05f, 0, -1.92f, -0.82f, -1.99f, -1.85f,
-LINE_TO, 3, 17,
-LINE_TO, 3, 5.91f,
-R_LINE_TO, -2.41f, -2.41f,
-LINE_TO, 2, 2.09f,
-CLOSE,
-MOVE_TO, 13, 16,
-H_LINE_TO, 5,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, 8,
-R_V_LINE_TO, -1,
-CLOSE,
-R_MOVE_TO, -1.91f, -2,
-LINE_TO, 5, 7.91f,
-LINE_TO, 5, 14,
-R_H_LINE_TO, 6.09f,
-CLOSE,
-R_MOVE_TO, 5.1f, -8.5f,
-R_CUBIC_TO, 2.22f, 2.22f, 2.38f, 5.74f, 0.47f, 8.15f,
-R_LINE_TO, -1.17f, -1.16f,
-R_CUBIC_TO, 1.23f, -1.7f, 1.14f, -4.08f, -0.3f, -5.66f,
-R_LINE_TO, -0.16f, -0.17f,
-LINE_TO, 16.18f, 5.5f,
-CLOSE,
-R_MOVE_TO, -2.03f, 2.02f,
-R_CUBIC_TO, 1.11f, 1.11f, 1.25f, 2.81f, 0.44f, 4.08f,
-R_LINE_TO, -1.21f, -1.22f,
-R_CUBIC_TO, 0.19f, -0.53f, 0.1f, -1.14f, -0.28f, -1.59f,
-LINE_TO, 13, 8.67f,
-R_LINE_TO, 1.15f, -1.15f,
-CLOSE,
-MOVE_TO, 5, 1,
-R_LINE_TO, 8, 0.01f,
-R_CUBIC_TO, 1.05f, 0, 1.92f, 0.81f, 1.99f, 1.84f,
-LINE_TO, 15, 3,
-R_V_LINE_TO, 3.5f,
-R_H_LINE_TO, -2,
-V_LINE_TO, 6,
-H_LINE_TO, 9,
-LINE_TO, 7, 4,
-R_H_LINE_TO, 6,
-V_LINE_TO, 3,
-H_LINE_TO, 6,
-LINE_TO, 4.18f, 1.18f,
-R_CUBIC_TO, 0.21f, -0.09f, 0.43f, -0.15f, 0.67f, -0.17f,
-LINE_TO, 5, 1,
-CLOSE
diff --git a/ash/resources/vector_icons/phone_hub_silence_phone_on.icon b/ash/resources/vector_icons/phone_hub_silence_phone.icon
similarity index 100%
rename from ash/resources/vector_icons/phone_hub_silence_phone_on.icon
rename to ash/resources/vector_icons/phone_hub_silence_phone.icon
diff --git a/ash/resources/vector_icons/phone_hub_silence_phone_off.icon b/ash/resources/vector_icons/phone_hub_silence_phone_off.icon
deleted file mode 100644
index d201d6e9..0000000
--- a/ash/resources/vector_icons/phone_hub_silence_phone_off.icon
+++ /dev/null
@@ -1,54 +0,0 @@
-CANVAS_DIMENSIONS, 20,
-MOVE_TO, 2, 2.09f,
-LINE_TO, 17.56f, 17.64f,
-R_LINE_TO, -1.41f, 1.41f,
-LINE_TO, 13.09f, 16,
-H_LINE_TO, 2,
-R_V_LINE_TO, -2,
-R_H_LINE_TO, 2,
-V_LINE_TO, 9.5f,
-R_CUBIC_TO, 0, -0.8f, 0.11f, -1.56f, 0.32f, -2.26f,
-LINE_TO, 0.59f, 3.5f,
-LINE_TO, 2, 2.09f,
-CLOSE,
-MOVE_TO, 12, 17,
-R_CUBIC_TO, 0, 1.1f, -0.9f, 2, -2, 2,
-R_CUBIC_TO, -1.05f, 0, -1.92f, -0.82f, -1.99f, -1.85f,
-LINE_TO, 8, 17,
-R_H_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 6, -3,
-R_V_LINE_TO, 1,
-R_LINE_TO, -1, -1,
-R_H_LINE_TO, 1,
-CLOSE,
-R_MOVE_TO, -9.88f, -2.97f,
-LINE_TO, 6.03f, 8.94f,
-CUBIC_TO, 6.01f, 9.12f, 6, 9.31f, 6, 9.5f,
-V_LINE_TO, 14,
-R_H_LINE_TO, 5.09f,
-R_LINE_TO, -1, -1,
-H_LINE_TO, 7.75f,
-R_V_LINE_TO, -1.54f,
-LINE_TO, 8.12f, 11.03f,
-CLOSE,
-MOVE_TO, 10, 1,
-R_CUBIC_TO, 0.83f, 0, 1.5f, 0.67f, 1.5f, 1.5f,
-R_V_LINE_TO, 0.68f,
-R_CUBIC_TO, 2.87f, 0.68f, 4.5f, 3.25f, 4.5f, 6.32f,
-V_LINE_TO, 13,
-R_LINE_TO, -2, -2,
-V_LINE_TO, 9.5f,
-CUBIC_TO, 14, 7.02f, 12.49f, 5, 10, 5,
-R_CUBIC_TO, -0.61f, 0, -1.17f, 0.12f, -1.65f, 0.34f,
-R_LINE_TO, -1.49f, -1.49f,
-CUBIC_TO, 7.34f, 3.55f, 7.89f, 3.32f, 8.5f, 3.18f,
-V_LINE_TO, 2.5f,
-R_CUBIC_TO, 0, -0.83f, 0.67f, -1.5f, 1.5f, -1.5f,
-CLOSE,
-R_MOVE_TO, 2.75f, 6,
-R_V_LINE_TO, 1.54f,
-LINE_TO, 12.19f, 9.19f,
-LINE_TO, 10, 7,
-R_H_LINE_TO, 2.75f,
-CLOSE
diff --git a/ash/services/ime/public/mojom/input_method.mojom b/ash/services/ime/public/mojom/input_method.mojom
index 16d0270..16cb147 100644
--- a/ash/services/ime/public/mojom/input_method.mojom
+++ b/ash/services/ime/public/mojom/input_method.mojom
@@ -6,7 +6,7 @@
 // the Chromium repo. This file should be updated first, before syncing in the
 // other repos.
 
-// Next MinVersion: 7
+// Next MinVersion: 8
 
 module chromeos.ime.mojom;
 
@@ -331,9 +331,46 @@
   [MinVersion=6] bool default_to_full_width_punctuation@6;
 };
 
-// Next ordinal: 0
+// Next ordinal: 3
+[Stable, Extensible, MinVersion=7]
+enum ZhuyinLayout {
+  [Default] kStandard = 0,
+  kIbm = 1,
+  kEten = 2,
+};
+
+// The keys used to select candidates for Zhuyin.
+// There is a limited set of possible shortcut schemes.
+// Each scheme can be represented by a string, where the 1st character of the
+// string is used to select the 1st candidate, the 2nd character for the 2nd
+// candidate and so on.
+// See the default enum value for an example.
+//
+// Next ordinal: 5
+[Stable, Extensible, MinVersion=7]
+enum ZhuyinSelectionKeys {
+  // Corresponds to '1234567890'.
+  // '1' selects the 1st candidate, '2' selects the 2nd, and so on, and '0'
+  // selects the 10th candidate.
+  [Default] k1234567890 = 0,
+  // Corresponds to 'asdfghjkl;'.
+  kAsdfghjkl = 1,
+  // Corresponds to 'asdfzxcv89'.
+  kAsdfzxcv89 = 2,
+  // Corresponds to 'asdfjkl789'.
+  kAsdfjkl789 = 3,
+  // Corresponds to '1234qweras'.
+  k1234Qweras = 4,
+};
+
+// Next ordinal: 3
 [Stable]
 struct ZhuyinSettings {
+  [MinVersion=7] ZhuyinLayout layout@0;
+  [MinVersion=7] ZhuyinSelectionKeys selection_keys@1;
+
+  // Maximum number of candidates to display per page.
+  [MinVersion=7] uint32 page_size@2;
 };
 
 // An input method that is provided natively by the IME Service.
diff --git a/ash/shell.cc b/ash/shell.cc
index 739df2b..d2131c24 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -103,6 +103,7 @@
 #include "ash/shutdown_controller_impl.h"
 #include "ash/style/ash_color_provider.h"
 #include "ash/system/audio/display_speaker_controller.h"
+#include "ash/system/bluetooth/bluetooth_device_status_ui_handler.h"
 #include "ash/system/bluetooth/bluetooth_notification_controller.h"
 #include "ash/system/bluetooth/bluetooth_power_controller.h"
 #include "ash/system/bluetooth/tray_bluetooth_helper_experimental.h"
@@ -1275,6 +1276,12 @@
           user_activity_detector_.get(), std::move(fingerprint));
   video_activity_notifier_ =
       std::make_unique<VideoActivityNotifier>(video_detector_.get());
+
+  if (ash::features::IsBluetoothRevampEnabled()) {
+    bluetooth_device_status_ui_handler_ =
+        std::make_unique<BluetoothDeviceStatusUiHandler>();
+  }
+
   bluetooth_notification_controller_ =
       std::make_unique<BluetoothNotificationController>(
           message_center::MessageCenter::Get());
diff --git a/ash/shell.h b/ash/shell.h
index bba7dae..761587b6 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -97,6 +97,7 @@
 class AutoclickController;
 class BackGestureEventHandler;
 class BacklightsForcedOffSetter;
+class BluetoothDeviceStatusUiHandler;
 class BluetoothNotificationController;
 class BluetoothPowerController;
 class BrightnessControlDelegate;
@@ -854,6 +855,8 @@
       resolution_notification_controller_;
   std::unique_ptr<BluetoothNotificationController>
       bluetooth_notification_controller_;
+  std::unique_ptr<BluetoothDeviceStatusUiHandler>
+      bluetooth_device_status_ui_handler_;
   std::unique_ptr<BluetoothPowerController> bluetooth_power_controller_;
   std::unique_ptr<TrayBluetoothHelper> tray_bluetooth_helper_;
   std::unique_ptr<KeyboardControllerImpl> keyboard_controller_;
diff --git a/ash/system/bluetooth/bluetooth_device_status_ui_handler.cc b/ash/system/bluetooth/bluetooth_device_status_ui_handler.cc
new file mode 100644
index 0000000..0a71cbf0
--- /dev/null
+++ b/ash/system/bluetooth/bluetooth_device_status_ui_handler.cc
@@ -0,0 +1,65 @@
+// 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/system/bluetooth/bluetooth_device_status_ui_handler.h"
+
+#include "ash/constants/ash_features.h"
+#include "ash/public/cpp/bluetooth_config_service.h"
+#include "ash/public/cpp/toast_data.h"
+#include "ash/public/cpp/toast_manager.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "base/check.h"
+#include "chromeos/services/bluetooth_config/public/cpp/cros_bluetooth_config_util.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace ash {
+namespace {
+
+using chromeos::bluetooth_config::GetPairedDeviceName;
+using chromeos::bluetooth_config::mojom::PairedBluetoothDevicePropertiesPtr;
+
+const char kBluetoothToastIdPrefix[] = "cros_bluetooth_device_toast_id-";
+constexpr int kToastDurationMs = 6000;
+
+}  // namespace
+
+BluetoothDeviceStatusUiHandler::BluetoothDeviceStatusUiHandler() {
+  DCHECK(ash::features::IsBluetoothRevampEnabled());
+  GetBluetoothConfigService(
+      remote_cros_bluetooth_config_.BindNewPipeAndPassReceiver());
+  remote_cros_bluetooth_config_->ObserveDeviceStatusChanges(
+      cros_bluetooth_device_status_observer_receiver_
+          .BindNewPipeAndPassRemote());
+}
+
+BluetoothDeviceStatusUiHandler::~BluetoothDeviceStatusUiHandler() = default;
+
+void BluetoothDeviceStatusUiHandler::OnDevicePaired(
+    PairedBluetoothDevicePropertiesPtr device) {
+  ash::ToastData toast_data(
+      /*id=*/GetToastId(device.get()),
+      /*text=*/
+      l10n_util::GetStringFUTF16(
+          IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED_OR_CONNECTED_TOAST,
+          GetPairedDeviceName(device.get())),
+      /*timeout_ms=*/kToastDurationMs,
+      /*dismiss_text=*/absl::nullopt,
+      /*visible_on_lock_screen=*/false);
+
+  ShowToast(toast_data);
+}
+
+void BluetoothDeviceStatusUiHandler::ShowToast(
+    const ash::ToastData& toast_data) {
+  ash::ToastManager::Get()->Show(toast_data);
+}
+
+std::string BluetoothDeviceStatusUiHandler::GetToastId(
+    const chromeos::bluetooth_config::mojom::PairedBluetoothDeviceProperties*
+        paired_device_properties) {
+  return kBluetoothToastIdPrefix +
+         base::ToLowerASCII(paired_device_properties->device_properties->id);
+}
+
+}  // namespace ash
\ No newline at end of file
diff --git a/ash/system/bluetooth/bluetooth_device_status_ui_handler.h b/ash/system/bluetooth/bluetooth_device_status_ui_handler.h
new file mode 100644
index 0000000..13c729b
--- /dev/null
+++ b/ash/system/bluetooth/bluetooth_device_status_ui_handler.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 ASH_SYSTEM_BLUETOOTH_BLUETOOTH_DEVICE_STATUS_UI_HANDLER_H_
+#define ASH_SYSTEM_BLUETOOTH_BLUETOOTH_DEVICE_STATUS_UI_HANDLER_H_
+
+#include "ash/ash_export.h"
+#include "ash/public/cpp/toast_manager.h"
+#include "chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace ash {
+
+// Listens for changes in Bluetooth device status, like a when a new device is
+// paired, a device is disconnected or connected. It shows a toast when these
+// events occur.
+class ASH_EXPORT BluetoothDeviceStatusUiHandler
+    : public chromeos::bluetooth_config::mojom::BluetoothDeviceStatusObserver {
+ public:
+  BluetoothDeviceStatusUiHandler();
+  BluetoothDeviceStatusUiHandler(const BluetoothDeviceStatusUiHandler&) =
+      delete;
+  BluetoothDeviceStatusUiHandler& operator=(
+      const BluetoothDeviceStatusUiHandler&) = delete;
+  ~BluetoothDeviceStatusUiHandler() override;
+
+ private:
+  // chromeos::bluetooth_config::mojom::BluetoothDeviceStatusObserver:
+  void OnDevicePaired(
+      chromeos::bluetooth_config::mojom::PairedBluetoothDevicePropertiesPtr
+          device) override;
+
+  virtual void ShowToast(const ash::ToastData& toast_data);
+
+  // Returns a string which represents a toast id. Id is created from a
+  // constant string prefix concatenated to |paired_device_properties| id.
+  std::string GetToastId(
+      const chromeos::bluetooth_config::mojom::PairedBluetoothDeviceProperties*
+          paired_device_properties);
+
+  mojo::Remote<chromeos::bluetooth_config::mojom::CrosBluetoothConfig>
+      remote_cros_bluetooth_config_;
+  mojo::Receiver<
+      chromeos::bluetooth_config::mojom::BluetoothDeviceStatusObserver>
+      cros_bluetooth_device_status_observer_receiver_{this};
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_BLUETOOTH_BLUETOOTH_DEVICE_STATUS_UI_HANDLER_H_
\ No newline at end of file
diff --git a/ash/system/bluetooth/bluetooth_device_status_ui_handler_unittest.cc b/ash/system/bluetooth/bluetooth_device_status_ui_handler_unittest.cc
new file mode 100644
index 0000000..b50a372
--- /dev/null
+++ b/ash/system/bluetooth/bluetooth_device_status_ui_handler_unittest.cc
@@ -0,0 +1,86 @@
+// 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/system/bluetooth/bluetooth_device_status_ui_handler.h"
+
+#include "ash/constants/ash_features.h"
+#include "ash/public/cpp/toast_manager.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "ash/test/ash_test_base.h"
+#include "base/test/scoped_feature_list.h"
+#include "chromeos/services/bluetooth_config/fake_bluetooth_device_status_notifier.h"
+#include "chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h"
+#include "chromeos/services/bluetooth_config/scoped_bluetooth_config_test_helper.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using chromeos::bluetooth_config::mojom::BatteryProperties;
+using chromeos::bluetooth_config::mojom::BluetoothDeviceProperties;
+using chromeos::bluetooth_config::mojom::DeviceBatteryInfo;
+using chromeos::bluetooth_config::mojom::DeviceBatteryInfoPtr;
+using chromeos::bluetooth_config::mojom::DeviceConnectionState;
+using chromeos::bluetooth_config::mojom::PairedBluetoothDeviceProperties;
+using chromeos::bluetooth_config::mojom::PairedBluetoothDevicePropertiesPtr;
+using testing::NiceMock;
+
+namespace ash {
+
+namespace {
+
+class MockBluetoothDeviceStatusUiHandler
+    : public BluetoothDeviceStatusUiHandler {
+ public:
+  MOCK_METHOD(void, ShowToast, (const ash::ToastData& toast_data), (override));
+};
+
+}  // namespace
+
+class BluetoothDeviceStatusUiHandlerTest : public AshTestBase {
+ public:
+  void SetUp() override {
+    AshTestBase::SetUp();
+    feature_list_.InitAndEnableFeature(features::kBluetoothRevamp);
+    device_status_ui_handler_ =
+        std::make_unique<NiceMock<MockBluetoothDeviceStatusUiHandler>>();
+    base::RunLoop().RunUntilIdle();
+  }
+
+  MockBluetoothDeviceStatusUiHandler& device_status_ui_handler() {
+    return *device_status_ui_handler_;
+  }
+
+  void SetPairedDevices(
+      std::vector<PairedBluetoothDevicePropertiesPtr>& paired_devices) {
+    fake_device_status_notifier()->SetNewlyPairedDevices(
+        std::move(paired_devices));
+    base::RunLoop().RunUntilIdle();
+  }
+
+ private:
+  chromeos::bluetooth_config::FakeBluetoothDeviceStatusNotifier*
+  fake_device_status_notifier() {
+    return scoped_bluetooth_config_test_helper_
+        .fake_bluetooth_device_status_notifier();
+  }
+
+  std::unique_ptr<MockBluetoothDeviceStatusUiHandler> device_status_ui_handler_;
+  base::test::ScopedFeatureList feature_list_;
+  chromeos::bluetooth_config::ScopedBluetoothConfigTestHelper
+      scoped_bluetooth_config_test_helper_;
+};
+
+TEST_F(BluetoothDeviceStatusUiHandlerTest, PairedDevice) {
+  EXPECT_CALL(device_status_ui_handler(), ShowToast);
+  // Create a device paired device.
+  auto paired_device = PairedBluetoothDeviceProperties::New();
+  paired_device->nickname = "Beats X";
+  paired_device->device_properties = BluetoothDeviceProperties::New();
+  paired_device->device_properties->connection_state =
+      DeviceConnectionState::kConnected;
+
+  std::vector<PairedBluetoothDevicePropertiesPtr> paired_devices;
+  paired_devices.push_back(mojo::Clone(paired_device));
+  SetPairedDevices(paired_devices);
+}
+
+}  // namespace ash
\ No newline at end of file
diff --git a/ash/system/bluetooth/bluetooth_notification_controller.cc b/ash/system/bluetooth/bluetooth_notification_controller.cc
index 23885099..eaf06e2 100644
--- a/ash/system/bluetooth/bluetooth_notification_controller.cc
+++ b/ash/system/bluetooth/bluetooth_notification_controller.cc
@@ -377,6 +377,13 @@
     }
   }
 
+  // If bluetooth revamp flag is on, do not show a notification, this is
+  // because notifications will be handled by BluetoothDeviceStatusUiHandler
+  // when flag is on.
+  if (ash::features::IsBluetoothRevampEnabled()) {
+    return;
+  }
+
   std::unique_ptr<Notification> notification = CreateSystemNotification(
       message_center::NOTIFICATION_TYPE_SIMPLE, GetPairedNotificationId(device),
       std::u16string() /* title */,
diff --git a/ash/system/geolocation/geolocation_controller.cc b/ash/system/geolocation/geolocation_controller.cc
new file mode 100644
index 0000000..a3f0e28
--- /dev/null
+++ b/ash/system/geolocation/geolocation_controller.cc
@@ -0,0 +1,172 @@
+// 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/system/geolocation/geolocation_controller.h"
+
+#include <algorithm>
+
+#include "ash/components/geolocation/geoposition.h"
+#include "ash/system/time/time_of_day.h"
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/time/clock.h"
+#include "third_party/icu/source/i18n/astro.h"
+
+namespace ash {
+
+namespace {
+
+// Delay to wait for a response to our geolocation request, if we get a response
+// after which, we will consider the request a failure.
+constexpr base::TimeDelta kGeolocationRequestTimeout = base::Seconds(60);
+
+// Minimum delay to wait to fire a new request after a previous one failing.
+constexpr base::TimeDelta kMinimumDelayAfterFailure = base::Seconds(60);
+
+// Delay to wait to fire a new request after a previous one succeeding.
+constexpr base::TimeDelta kNextRequestDelayAfterSuccess = base::Days(1);
+
+// Default sunset time at 6:00 PM as an offset from 00:00.
+constexpr int kDefaultSunsetTimeOffsetMinutes = 18 * 60;
+
+// Default sunrise time at 6:00 AM as an offset from 00:00.
+constexpr int kDefaultSunriseTimeOffsetMinutes = 6 * 60;
+
+}  // namespace
+
+GeolocationController::GeolocationController(
+    scoped_refptr<network::SharedURLLoaderFactory> factory)
+    : provider_(std::move(factory),
+                SimpleGeolocationProvider::DefaultGeolocationProviderURL()),
+      backoff_delay_(kMinimumDelayAfterFailure),
+      timer_(std::make_unique<base::OneShotTimer>()) {
+  auto* timezone_settings = chromeos::system::TimezoneSettings::GetInstance();
+  current_timezone_id_ = timezone_settings->GetCurrentTimezoneID();
+  timezone_settings->AddObserver(this);
+}
+
+GeolocationController::~GeolocationController() {
+  chromeos::system::TimezoneSettings::GetInstance()->RemoveObserver(this);
+}
+
+void GeolocationController::AddObserver(Observer* observer) {
+  const bool is_first_observer = observers_.empty();
+  observers_.AddObserver(observer);
+  if (is_first_observer)
+    ScheduleNextRequest(base::Seconds(0));
+}
+
+void GeolocationController::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+  if (observers_.empty())
+    timer_->Stop();
+}
+
+void GeolocationController::TimezoneChanged(const icu::TimeZone& timezone) {
+  const std::u16string timezone_id =
+      chromeos::system::TimezoneSettings::GetTimezoneID(timezone);
+  if (current_timezone_id_ == timezone_id)
+    return;
+
+  current_timezone_id_ = timezone_id;
+
+  // On timezone changes, request an immediate geoposition.
+  ScheduleNextRequest(base::Seconds(0));
+}
+
+// static
+base::TimeDelta
+GeolocationController::GetNextRequestDelayAfterSuccessForTesting() {
+  return kNextRequestDelayAfterSuccess;
+}
+
+void GeolocationController::SetTimerForTesting(
+    std::unique_ptr<base::OneShotTimer> timer) {
+  timer_ = std::move(timer);
+}
+
+void GeolocationController::SetClockForTesting(base::Clock* clock) {
+  clock_ = clock;
+}
+
+void GeolocationController::SetCurrentTimezoneIdForTesting(
+    const std::u16string& timezone_id) {
+  current_timezone_id_ = timezone_id;
+}
+
+void GeolocationController::OnGeoposition(const Geoposition& position,
+                                          bool server_error,
+                                          const base::TimeDelta elapsed) {
+  if (server_error || !position.Valid() ||
+      elapsed > kGeolocationRequestTimeout) {
+    VLOG(1) << "Failed to get a valid geoposition. Trying again later.";
+    // Don't send invalid positions to ash.
+    // On failure, we schedule another request after the current backoff delay.
+    ScheduleNextRequest(backoff_delay_);
+
+    // If another failure occurs next, our backoff delay should double.
+    backoff_delay_ *= 2;
+    return;
+  }
+
+  last_successful_geo_request_time_ = GetNow();
+
+  geoposition_ = std::make_unique<SimpleGeoposition>();
+  geoposition_->latitude = position.latitude;
+  geoposition_->longitude = position.longitude;
+  NotifyWithCurrentGeoposition(*geoposition_);
+
+  // On success, reset the backoff delay to its minimum value, and schedule
+  // another request.
+  backoff_delay_ = kMinimumDelayAfterFailure;
+  ScheduleNextRequest(kNextRequestDelayAfterSuccess);
+}
+
+base::Time GeolocationController::GetNow() const {
+  return clock_ ? clock_->Now() : base::Time::Now();
+}
+
+void GeolocationController::ScheduleNextRequest(base::TimeDelta delay) {
+  timer_->Start(FROM_HERE, delay, this,
+                &GeolocationController::RequestGeoposition);
+}
+
+void GeolocationController::NotifyWithCurrentGeoposition(
+    SimpleGeoposition position) {
+  for (Observer& observer : observers_)
+    observer.OnGeopositionChanged(position);
+}
+
+void GeolocationController::RequestGeoposition() {
+  VLOG(1) << "Requesting a new geoposition";
+  provider_.RequestGeolocation(
+      kGeolocationRequestTimeout, /*send_wifi_access_points=*/false,
+      /*send_cell_towers=*/false,
+      base::BindOnce(&GeolocationController::OnGeoposition,
+                     base::Unretained(this)));
+}
+
+base::Time GeolocationController::GetSunRiseSet(bool sunrise) const {
+  if (!geoposition_) {
+    LOG(ERROR) << "Invalid geoposition. Using default time for "
+               << (sunrise ? "sunrise." : "sunset.");
+    return sunrise ? TimeOfDay(kDefaultSunriseTimeOffsetMinutes).ToTimeToday()
+                   : TimeOfDay(kDefaultSunsetTimeOffsetMinutes).ToTimeToday();
+  }
+
+  icu::CalendarAstronomer astro(geoposition_->longitude,
+                                geoposition_->latitude);
+  // For sunset and sunrise times calculations to be correct, the time of the
+  // icu::CalendarAstronomer object should be set to a time near local noon.
+  // This avoids having the computation flopping over into an adjacent day.
+  // See the documentation of icu::CalendarAstronomer::getSunRiseSet().
+  // Note that the icu calendar works with milliseconds since epoch, and
+  // base::Time::FromDoubleT() / ToDoubleT() work with seconds since epoch.
+  const double midday_today_sec = TimeOfDay(12 * 60).ToTimeToday().ToDoubleT();
+  astro.setTime(midday_today_sec * 1000.0);
+  const double sun_rise_set_ms = astro.getSunRiseSet(sunrise);
+  return base::Time::FromDoubleT(sun_rise_set_ms / 1000.0);
+}
+
+}  // namespace ash
\ No newline at end of file
diff --git a/ash/system/geolocation/geolocation_controller.h b/ash/system/geolocation/geolocation_controller.h
new file mode 100644
index 0000000..055504c
--- /dev/null
+++ b/ash/system/geolocation/geolocation_controller.h
@@ -0,0 +1,147 @@
+// 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_SYSTEM_GEOLOCATION_GEOLOCATION_CONTROLLER_H_
+#define ASH_SYSTEM_GEOLOCATION_GEOLOCATION_CONTROLLER_H_
+
+#include <memory>
+#include <string>
+
+#include "ash/ash_export.h"
+#include "ash/components/geolocation/simple_geolocation_provider.h"
+#include "ash/components/settings/timezone_settings.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+namespace base {
+class Clock;
+}  // namespace base
+
+namespace ash {
+
+// Represents a geolocation position fix. It's "simple" because it doesn't
+// expose all the parameters of the position interface as defined by the
+// Geolocation API Specification:
+//   https://dev.w3.org/geo/api/spec-source.html#position_interface
+// The GeolocationController is only interested in valid latitude and
+// longitude. It also doesn't require any specific accuracy. The more accurate
+// the positions, the more accurate sunset and sunrise times calculations.
+// However, an IP-based geoposition is considered good enough.
+struct SimpleGeoposition {
+  bool operator==(const SimpleGeoposition& other) const {
+    return latitude == other.latitude && longitude == other.longitude;
+  }
+  double latitude;
+  double longitude;
+};
+
+// Periodically requests the IP-based geolocation and provides it to the
+// observers, `GeolocationController::Observer`. This class also observes
+// timezone changes to request a new geoposition.
+// TODO(crbug.com/1272178): `GeolocationController` should observe the sleep
+// and update next request time.
+class ASH_EXPORT GeolocationController
+    : public chromeos::system::TimezoneSettings::Observer {
+ public:
+  class Observer : public base::CheckedObserver {
+   public:
+    // Emitted when the Geoposition is updated.
+    virtual void OnGeopositionChanged(SimpleGeoposition position) {}
+
+   protected:
+    ~Observer() override = default;
+  };
+
+  explicit GeolocationController(
+      scoped_refptr<network::SharedURLLoaderFactory> factory);
+  GeolocationController(const GeolocationController&) = delete;
+  GeolocationController& operator=(const GeolocationController&) = delete;
+  ~GeolocationController() override;
+
+  const base::OneShotTimer& timer() const { return *timer_; }
+
+  base::Time last_successful_geo_request_time() const {
+    return last_successful_geo_request_time_;
+  }
+
+  const std::u16string& current_timezone_id() const {
+    return current_timezone_id_;
+  }
+
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+  // chromeos::system::TimezoneSettings::Observer:
+  void TimezoneChanged(const icu::TimeZone& timezone) override;
+
+  // Returns sunset and sunrise time calculated from `geoposition_`. If the
+  // position is not set, returns the default sunset 6 PM and sunrise 6 AM.
+  base::Time GetSunsetTime() const { return GetSunRiseSet(/*sunrise=*/false); }
+  base::Time GetSunriseTime() const { return GetSunRiseSet(/*sunrise=*/true); }
+
+  static base::TimeDelta GetNextRequestDelayAfterSuccessForTesting();
+
+  void SetTimerForTesting(std::unique_ptr<base::OneShotTimer> timer);
+
+  void SetClockForTesting(base::Clock* clock);
+
+  void SetCurrentTimezoneIdForTesting(const std::u16string& timezone_id);
+
+ protected:
+  // The callback of geolocation request via `provider_`. Once receiving a
+  // new position, it `NotifyWithCurrentGeoposition()` to broadcast the position
+  // to observers and `ScheduleNextRequest()` on the next day. If the retrieval
+  // fails, it `ScheduleNextRequest()` after a `backoff_delay_`, which is
+  // doubled for each failure.
+  void OnGeoposition(const Geoposition& position,
+                     bool server_error,
+                     const base::TimeDelta elapsed);
+
+ private:
+  // Gets now time from the `clock_` or `base::Time::Now()` if `clock_` does
+  // not exist.
+  base::Time GetNow() const;
+
+  // Calls `RequestGeoposition()` after `delay`.
+  void ScheduleNextRequest(base::TimeDelta delay);
+
+  // Broadcasts the new position obtained from the request to all observers.
+  void NotifyWithCurrentGeoposition(SimpleGeoposition position);
+
+  // Virtual so that it can be overridden by a fake implementation in unit tests
+  // that doesn't request actual geopositions.
+  virtual void RequestGeoposition();
+
+  // Note that the below computation is intentionally performed every time
+  // GetSunsetTime() or GetSunriseTime() is called rather than once whenever we
+  // receive a geoposition (which happens at least once a day). This reduces
+  // the chances of getting inaccurate values, especially around DST changes.
+  base::Time GetSunRiseSet(bool sunrise) const;
+
+  // The IP-based geolocation provider.
+  SimpleGeolocationProvider provider_;
+
+  // Delay after which a new request is retried after a failed one.
+  base::TimeDelta backoff_delay_;
+
+  std::unique_ptr<base::OneShotTimer> timer_;
+
+  // Optional Used in tests to override the time of "Now".
+  base::Clock* clock_ = nullptr;  // Not owned.
+
+  // Last successful geoposition coordinates and its timestamp.
+  base::Time last_successful_geo_request_time_;
+
+  // The ID of the current timezone in the format similar to "America/Chicago".
+  std::u16string current_timezone_id_;
+
+  base::ObserverList<Observer> observers_;
+
+  std::unique_ptr<SimpleGeoposition> geoposition_;
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_GEOLOCATION_GEOLOCATION_CONTROLLER_H_
diff --git a/ash/system/geolocation/geolocation_controller_unittest.cc b/ash/system/geolocation/geolocation_controller_unittest.cc
new file mode 100644
index 0000000..a5a3d37
--- /dev/null
+++ b/ash/system/geolocation/geolocation_controller_unittest.cc
@@ -0,0 +1,255 @@
+// 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/system/geolocation/geolocation_controller.h"
+
+#include "ash/system/time/time_of_day.h"
+#include "ash/test/ash_test_base.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/simple_test_clock.h"
+#include "base/time/clock.h"
+#include "base/timer/mock_timer.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+
+namespace ash {
+
+namespace {
+
+// Constructs a TimeZone object from the given `timezone_id`.
+std::unique_ptr<icu::TimeZone> CreateTimezone(const char* timezone_id) {
+  return base::WrapUnique(icu::TimeZone::createTimeZone(
+      icu::UnicodeString(timezone_id, -1, US_INV)));
+}
+
+std::u16string GetTimezoneId(const icu::TimeZone& timezone) {
+  return chromeos::system::TimezoneSettings::GetTimezoneID(timezone);
+}
+
+// An observer class to GeolocationController which updates sunset and sunrise
+// time.
+class GeolocationControllerObserver : public GeolocationController::Observer {
+ public:
+  GeolocationControllerObserver() = default;
+
+  GeolocationControllerObserver(const GeolocationControllerObserver&) = delete;
+  GeolocationControllerObserver& operator=(
+      const GeolocationControllerObserver&) = delete;
+
+  ~GeolocationControllerObserver() override = default;
+
+  // TODO(crbug.com/1269915): Add `sunset_` and `sunrise_` and update their
+  // values when receiving the new position.
+  void OnGeopositionChanged(SimpleGeoposition position) override {
+    position_received_num_++;
+  }
+
+  SimpleGeoposition position() const { return position_; }
+  int position_received_num() const { return position_received_num_; }
+
+ private:
+  SimpleGeoposition position_;
+
+  // The number of times a new position is received.
+  int position_received_num_ = 0;
+};
+
+// A fake implementation of GeolocationController that doesn't perform any
+// actual geoposition requests.
+class FakeGeolocationController : public GeolocationController {
+ public:
+  FakeGeolocationController(base::SimpleTestClock* test_clock,
+                            std::unique_ptr<base::MockOneShotTimer> mock_timer)
+      : GeolocationController(/*url_context_getter=*/nullptr) {
+    SetTimerForTesting(std::move(mock_timer));
+    SetClockForTesting(test_clock);
+  }
+
+  FakeGeolocationController(const FakeGeolocationController&) = delete;
+  FakeGeolocationController& operator=(const FakeGeolocationController&) =
+      delete;
+
+  ~FakeGeolocationController() override = default;
+
+  void set_position_to_send(const Geoposition& position) {
+    position_to_send_ = position;
+  }
+
+  const Geoposition& position_to_send() const { return position_to_send_; }
+
+  int geoposition_requests_num() const { return geoposition_requests_num_; }
+
+ private:
+  // GeolocationController:
+  void RequestGeoposition() override {
+    OnGeoposition(position_to_send_, /*server_error=*/false, base::TimeDelta());
+    ++geoposition_requests_num_;
+  }
+
+  // The position to send to the controller the next time OnGeoposition is
+  // invoked.
+  Geoposition position_to_send_;
+
+  // The number of new geoposition requests that have been triggered.
+  int geoposition_requests_num_ = 0;
+};
+
+// Base test fixture.
+class GeolocationControllerTest : public AshTestBase {
+ public:
+  GeolocationControllerTest() {
+    test_clock_.SetNow(base::Time::Now());
+
+    std::unique_ptr<base::MockOneShotTimer> mock_timer =
+        std::make_unique<base::MockOneShotTimer>();
+    mock_timer_ptr_ = mock_timer.get();
+    controller_ = std::make_unique<FakeGeolocationController>(
+        &test_clock_, std::move(mock_timer));
+
+    // Prepare a valid geoposition.
+    Geoposition position;
+    position.latitude = 32.0;
+    position.longitude = 31.0;
+    position.status = Geoposition::STATUS_OK;
+    position.accuracy = 10;
+    position.timestamp = base::Time::Now();
+    controller_->set_position_to_send(position);
+  }
+
+  GeolocationControllerTest(const GeolocationControllerTest&) = delete;
+  GeolocationControllerTest& operator=(const GeolocationControllerTest&) =
+      delete;
+
+  ~GeolocationControllerTest() override = default;
+
+ protected:
+  std::unique_ptr<FakeGeolocationController> controller_;
+  base::SimpleTestClock test_clock_;
+  base::MockOneShotTimer* mock_timer_ptr_;
+};
+
+// Tests adding and removing observer and make sure that only observing ones
+// receive the position updates.
+TEST_F(GeolocationControllerTest, MultipleObservers) {
+  EXPECT_EQ(0, controller_->geoposition_requests_num());
+  EXPECT_FALSE(mock_timer_ptr_->IsRunning());
+
+  // Add an observer should start the timer requesting for the first
+  // geoposition request.
+  GeolocationControllerObserver observer1;
+  controller_->AddObserver(&observer1);
+  EXPECT_TRUE(mock_timer_ptr_->IsRunning());
+  mock_timer_ptr_->Fire();
+  EXPECT_EQ(1, controller_->geoposition_requests_num());
+  EXPECT_EQ(1, observer1.position_received_num());
+
+  // Since `OnGeoposition()` handling a geoposition update always schedule
+  // the next geoposition request, the timer should keep running and
+  // update position periodically.
+  EXPECT_TRUE(mock_timer_ptr_->IsRunning());
+  mock_timer_ptr_->Fire();
+  EXPECT_EQ(2, controller_->geoposition_requests_num());
+  EXPECT_EQ(2, observer1.position_received_num());
+
+  // Adding `observer2` should not interrupt the request flow. Check that both
+  // observers receive the new position.
+  GeolocationControllerObserver observer2;
+  controller_->AddObserver(&observer2);
+  mock_timer_ptr_->Fire();
+  EXPECT_EQ(3, controller_->geoposition_requests_num());
+  EXPECT_EQ(3, observer1.position_received_num());
+  EXPECT_EQ(1, observer2.position_received_num());
+
+  // Remove `observer1` and make sure that the timer is still running.
+  // Only `observer2` should receive the new position.
+  controller_->RemoveObserver(&observer1);
+  mock_timer_ptr_->Fire();
+  EXPECT_EQ(4, controller_->geoposition_requests_num());
+  EXPECT_EQ(3, observer1.position_received_num());
+  EXPECT_EQ(2, observer2.position_received_num());
+
+  // Removing `observer2` should stop the timer. The request count should
+  // not change.
+  controller_->RemoveObserver(&observer2);
+  EXPECT_FALSE(mock_timer_ptr_->IsRunning());
+  EXPECT_EQ(4, controller_->geoposition_requests_num());
+  EXPECT_EQ(3, observer1.position_received_num());
+  EXPECT_EQ(2, observer2.position_received_num());
+}
+
+// Tests that controller only pushes valid positions.
+TEST_F(GeolocationControllerTest, InvalidPositions) {
+  EXPECT_EQ(0, controller_->geoposition_requests_num());
+  GeolocationControllerObserver observer;
+  // Update to an invalid position
+  Geoposition position = controller_->position_to_send();
+  position.status = Geoposition::STATUS_TIMEOUT;
+  controller_->set_position_to_send(position);
+  EXPECT_FALSE(mock_timer_ptr_->IsRunning());
+  controller_->AddObserver(&observer);
+  EXPECT_TRUE(mock_timer_ptr_->IsRunning());
+
+  // If the position is invalid, the controller won't push the geoposition
+  // update to its observers.
+  mock_timer_ptr_->Fire();
+  EXPECT_EQ(1, controller_->geoposition_requests_num());
+  EXPECT_EQ(0, observer.position_received_num());
+
+  // If the position is valid, the controller pushes the update to observers.
+  position.status = Geoposition::STATUS_OK;
+  controller_->set_position_to_send(position);
+  mock_timer_ptr_->Fire();
+  EXPECT_EQ(2, controller_->geoposition_requests_num());
+  EXPECT_EQ(1, observer.position_received_num());
+}
+
+// Tests that timezone changes result.
+TEST_F(GeolocationControllerTest, TimezoneChanges) {
+  EXPECT_EQ(0, controller_->geoposition_requests_num());
+  EXPECT_FALSE(mock_timer_ptr_->IsRunning());
+  controller_->SetCurrentTimezoneIdForTesting(u"America/Los_Angeles");
+
+  // Add an observer.
+  GeolocationControllerObserver observer;
+  controller_->AddObserver(&observer);
+  EXPECT_EQ(0, observer.position_received_num());
+  EXPECT_TRUE(mock_timer_ptr_->IsRunning());
+  mock_timer_ptr_->Fire();
+  EXPECT_EQ(1, controller_->geoposition_requests_num());
+  EXPECT_EQ(1, observer.position_received_num());
+  EXPECT_EQ(u"America/Los_Angeles", controller_->current_timezone_id());
+
+  // A new timezone results in new geoposition request.
+  auto timezone = CreateTimezone("Asia/Tokyo");
+
+  controller_->TimezoneChanged(*timezone);
+  mock_timer_ptr_->Fire();
+  EXPECT_EQ(2, controller_->geoposition_requests_num());
+  EXPECT_EQ(2, observer.position_received_num());
+  EXPECT_EQ(GetTimezoneId(*timezone), controller_->current_timezone_id());
+}
+
+// Tests obtaining sunset/sunrise time when there is no valid geoposition, for
+// example, due to lack of connectivity.
+TEST_F(GeolocationControllerTest, SunsetSunriseDefault) {
+  // Default sunset time at 6:00 PM as an offset from 00:00.
+  constexpr int kDefaultSunsetTimeOffsetMinutes = 18 * 60;
+  // Default sunrise time at 6:00 AM as an offset from 00:00.
+  constexpr int kDefaultSunriseTimeOffsetMinutes = 6 * 60;
+
+  // If geoposition is unset, the controller should return the default sunset
+  // and sunrise time .
+  EXPECT_EQ(controller_->GetSunsetTime(),
+            TimeOfDay(kDefaultSunsetTimeOffsetMinutes).ToTimeToday());
+  EXPECT_EQ(controller_->GetSunriseTime(),
+            TimeOfDay(kDefaultSunriseTimeOffsetMinutes).ToTimeToday());
+}
+
+// TODO(crbug.com/1269915): Add a test for `GetSunsetTime()` and
+// `GetSunriseTime()` along with updating `TimeOfDay` to support setting a
+// clock to `test_clock_`, so the time can be tested deterministically.
+
+}  // namespace
+
+}  // namespace ash
\ No newline at end of file
diff --git a/ash/system/hps/hps_configuration.cc b/ash/system/hps/hps_configuration.cc
new file mode 100644
index 0000000..fe67eb2
--- /dev/null
+++ b/ash/system/hps/hps_configuration.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/system/hps/hps_configuration.h"
+
+#include "ash/constants/ash_features.h"
+#include "base/metrics/field_trial_params.h"
+#include "chromeos/dbus/hps/hps_service.pb.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace ash {
+namespace {
+// Used for indicating which oneof field to construct for `filter_config` inside
+// FeatureConfig.
+constexpr int kFilterConfigCaseDefault = 0;
+
+// Default value for `FeatureConfig.consecutive_results_filter_config.count`.
+// Default 1 means the change will be notified if the inference result is
+// different from last one.
+constexpr int kConsecutiveResultsFilterCountDefault = 1;
+
+// Default value for
+// `FeatureConfig.consecutive_results_filter_config.threshold`. The inference
+// result is a value from [-128, 128), we use 0 as a default threshold.
+constexpr int kConsecutiveResultsFilterThresholdDefault = 0;
+
+// Default value for
+// `FeatureConfig.consecutive_results_filter_config.initial_state`.
+constexpr bool kConsecutiveResultsFilterIntialStateDefault = false;
+
+// This function constructs a FeatureConfig proto From Finch.
+// The FeatureConfig contains one type of FilterConfig that will be used for
+// enabling a Hps feature.
+// If filter_config_case is set to 0 (by default), absl::nullopt will be
+// returned; otherwise one type of FilterConfig will be returned with each
+// field getting its value from the finch params with the same name.
+// More details can be found at:
+// src/platform2/hps/daemon/filters/filter_factory.h
+absl::optional<hps::FeatureConfig> ConstructHpsFilterConfigFromFinch(
+    const base::Feature& feature) {
+  const int filter_config_case = base::GetFieldTrialParamByFeatureAsInt(
+      feature, "filter_config_case", kFilterConfigCaseDefault);
+  hps::FeatureConfig config;
+  switch (filter_config_case) {
+    case hps::FeatureConfig::kBasicFilterConfig: {
+      config.mutable_basic_filter_config();
+      return config;
+    }
+    case hps::FeatureConfig::kConsecutiveResultsFilterConfig: {
+      auto& consecutive_results_filter_config =
+          *config.mutable_consecutive_results_filter_config();
+
+      consecutive_results_filter_config.set_count(
+          base::GetFieldTrialParamByFeatureAsInt(
+              feature, "count", kConsecutiveResultsFilterCountDefault));
+      consecutive_results_filter_config.set_threshold(
+          base::GetFieldTrialParamByFeatureAsInt(
+              feature, "threshold", kConsecutiveResultsFilterThresholdDefault));
+      consecutive_results_filter_config.set_initial_state(
+          base::GetFieldTrialParamByFeatureAsBool(
+              feature, "initial_state",
+              kConsecutiveResultsFilterIntialStateDefault));
+      return config;
+    }
+    default:
+      return absl::nullopt;
+  }
+}
+}  // namespace
+
+absl::optional<hps::FeatureConfig> GetEnableHpsSenseConfig() {
+  return ConstructHpsFilterConfigFromFinch(features::kLeaveDetection);
+}
+
+absl::optional<hps::FeatureConfig> GetEnableHpsNotifyConfig() {
+  return ConstructHpsFilterConfigFromFinch(features::kSnoopingProtection);
+}
+
+}  // namespace ash
\ No newline at end of file
diff --git a/ash/system/hps/hps_configuration.h b/ash/system/hps/hps_configuration.h
new file mode 100644
index 0000000..9c048c6
--- /dev/null
+++ b/ash/system/hps/hps_configuration.h
@@ -0,0 +1,24 @@
+// 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_SYSTEM_HPS_HPS_CONFIGURATION_H_
+#define ASH_SYSTEM_HPS_HPS_CONFIGURATION_H_
+
+#include "ash/ash_export.h"
+#include "chromeos/dbus/hps/hps_service.pb.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace ash {
+
+// Gets FeatureConfig for enabling HpsSense from Finch.
+// Returns nullopt if feature is not enabled or can't be parsed correctly.
+ASH_EXPORT absl::optional<hps::FeatureConfig> GetEnableHpsSenseConfig();
+
+// Gets FeatureConfig for enabling HpsNotify from Finch.
+// Returns nullopt if feature is not enabled or can't be parsed correctly.
+ASH_EXPORT absl::optional<hps::FeatureConfig> GetEnableHpsNotifyConfig();
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_HPS_HPS_CONFIGURATION_H_
\ No newline at end of file
diff --git a/ash/system/hps/hps_configuration_unittest.cc b/ash/system/hps/hps_configuration_unittest.cc
new file mode 100644
index 0000000..a1cadb7f
--- /dev/null
+++ b/ash/system/hps/hps_configuration_unittest.cc
@@ -0,0 +1,75 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/hps/hps_configuration.h"
+
+#include "ash/constants/ash_features.h"
+#include "base/test/scoped_feature_list.h"
+#include "chromeos/dbus/hps/hps_service.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace ash {
+
+// Expect two protos to be equal if they are serialized into the same strings.
+MATCHER_P(ProtoEquals, expected_message, "") {
+  std::string expected_serialized, actual_serialized;
+  expected_message.SerializeToString(&expected_serialized);
+  arg.SerializeToString(&actual_serialized);
+  return expected_serialized == actual_serialized;
+}
+
+TEST(HpsFeatureConfigTest, ReturnNullIfTypeIsNotRecognizable) {
+  const base::FieldTrialParams params = {{"filter_config_case", "0"}};
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeaturesAndParameters(
+      {{features::kLeaveDetection, params},
+       {features::kSnoopingProtection, params}},
+      {});
+
+  EXPECT_FALSE(GetEnableHpsSenseConfig().has_value());
+  EXPECT_FALSE(GetEnableHpsNotifyConfig().has_value());
+}
+
+TEST(HpsFeatureConfigTest, VerifyBasicFilterConfig) {
+  const std::map<std::string, std::string> params = {
+      {"filter_config_case", "1"}};
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeaturesAndParameters(
+      {{features::kLeaveDetection, params},
+       {features::kSnoopingProtection, params}},
+      {});
+
+  hps::FeatureConfig expected_config;
+  expected_config.mutable_basic_filter_config();
+
+  EXPECT_THAT(GetEnableHpsSenseConfig().value(), ProtoEquals(expected_config));
+  EXPECT_THAT(GetEnableHpsNotifyConfig().value(), ProtoEquals(expected_config));
+}
+
+TEST(HpsFeatureConfigTest, VerifyConsecutiveResultsFilterConfig) {
+  const std::map<std::string, std::string> params = {
+      {"filter_config_case", "2"},
+      {"count", "3"},
+      {"threshold", "4"},
+      {"initial_state", "false"}};
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeaturesAndParameters(
+      {{features::kLeaveDetection, params},
+       {features::kSnoopingProtection, params}},
+      {});
+
+  hps::FeatureConfig expected_config;
+  auto& consecutive_results_filter_config =
+      *expected_config.mutable_consecutive_results_filter_config();
+  consecutive_results_filter_config.set_count(3);
+  consecutive_results_filter_config.set_threshold(4);
+  consecutive_results_filter_config.set_initial_state(false);
+
+  EXPECT_THAT(GetEnableHpsSenseConfig().value(), ProtoEquals(expected_config));
+  EXPECT_THAT(GetEnableHpsNotifyConfig().value(), ProtoEquals(expected_config));
+}
+
+}  // namespace ash
diff --git a/ash/system/message_center/ash_notification_view.cc b/ash/system/message_center/ash_notification_view.cc
index 6f20cb74..bc03438a 100644
--- a/ash/system/message_center/ash_notification_view.cc
+++ b/ash/system/message_center/ash_notification_view.cc
@@ -172,6 +172,28 @@
       .SetOpacity(view, 1.0f, tween_type);
 }
 
+// Fade out animation using AnimationBuilder.
+void FadeOutView(views::View* view,
+                 base::OnceClosure on_animation_ended,
+                 int delay_in_ms,
+                 int duration_in_ms,
+                 gfx::Tween::Type tween_type = gfx::Tween::LINEAR) {
+  std::pair<base::OnceClosure, base::OnceClosure> split =
+      base::SplitOnceCallback(std::move(on_animation_ended));
+
+  view->SetVisible(true);
+  views::AnimationBuilder()
+      .SetPreemptionStrategy(
+          ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
+      .OnEnded(std::move(split.first))
+      .OnAborted(std::move(split.second))
+      .Once()
+      .At(base::Milliseconds(delay_in_ms))
+      .SetDuration(base::Milliseconds(duration_in_ms))
+      .SetVisibility(view, false)
+      .SetOpacity(view, 0.0f, tween_type);
+}
+
 }  // namespace
 
 namespace ash {
@@ -411,6 +433,7 @@
   // Create layer in some views for animations.
   InitLayerForAnimations(header_row());
   InitLayerForAnimations(message_view_in_expanded_state_);
+  InitLayerForAnimations(actions_row());
 
   UpdateWithNotification(notification);
 }
@@ -419,6 +442,21 @@
 
 void AshNotificationView::ToggleExpand() {
   SetManuallyExpandedOrCollapsed(true);
+
+  if (inline_reply()->GetVisible()) {
+    // If inline reply is visible, fade it out then set expanded.
+    FadeOutView(inline_reply(),
+                base::BindOnce(
+                    [](base::WeakPtr<ash::AshNotificationView> parent,
+                       views::View* inline_reply) {
+                      if (parent) {
+                        inline_reply->layer()->SetOpacity(1.0f);
+                      }
+                    },
+                    weak_factory_.GetWeakPtr(), inline_reply()),
+                /*delay_in_ms=*/0, kInlineReplyFadeOutAnimationDurationMs);
+  }
+
   SetExpanded(!IsExpanded());
 
   PerformExpandCollapseAnimation();
@@ -731,6 +769,33 @@
   expand_button_->SetVisible(!inline_settings_visible);
 }
 
+void AshNotificationView::ActionButtonPressed(size_t index,
+                                              const ui::Event& event) {
+  NotificationViewBase::ActionButtonPressed(index, event);
+
+  // If inline reply is visible, fade out actions button and then fade in inline
+  // reply.
+  if (inline_reply()->GetVisible()) {
+    InitLayerForAnimations(action_buttons_row());
+    FadeOutView(action_buttons_row(),
+                base::BindOnce(
+                    [](base::WeakPtr<ash::AshNotificationView> parent,
+                       views::View* action_buttons_row) {
+                      if (parent) {
+                        action_buttons_row->layer()->SetOpacity(1.0f);
+                        action_buttons_row->SetVisible(false);
+                      }
+                    },
+                    weak_factory_.GetWeakPtr(), action_buttons_row()),
+                /*delay_in_ms=*/0, kActionButtonsFadeOutAnimationDurationMs);
+
+    // Delay for the action buttons to fade out, then fade in inline reply.
+    InitLayerForAnimations(inline_reply());
+    FadeInView(inline_reply(), kActionButtonsFadeOutAnimationDurationMs,
+               kInlineReplyFadeInAnimationDurationMs);
+  }
+}
+
 void AshNotificationView::UpdateMessageViewInExpandedState(
     const message_center::Notification& notification) {
   if (notification.message().empty()) {
@@ -847,6 +912,11 @@
                kMessageViewInExpandedStateFadeInAnimationDelayMs,
                kMessageViewInExpandedStateFadeInAnimationDurationMs);
   }
+
+  if (actions_row()->GetVisible()) {
+    FadeInView(actions_row(), kActionsRowFadeInAnimationDelayMs,
+               kActionsRowFadeInAnimationDurationMs);
+  }
 }
 
 }  // namespace ash
diff --git a/ash/system/message_center/ash_notification_view.h b/ash/system/message_center/ash_notification_view.h
index 40800dc..ce67cb4 100644
--- a/ash/system/message_center/ash_notification_view.h
+++ b/ash/system/message_center/ash_notification_view.h
@@ -79,6 +79,7 @@
       const std::u16string& label) override;
   gfx::Size GetIconViewSize() const override;
   void ToggleInlineSettings(const ui::Event& event) override;
+  void ActionButtonPressed(size_t index, const ui::Event& event) override;
 
  private:
   friend class AshNotificationViewTest;
@@ -179,6 +180,8 @@
   bool is_grouped_child_view_ = false;
   // Whether this view is shown in a notification popup.
   bool shown_in_popup_ = false;
+
+  base::WeakPtrFactory<AshNotificationView> weak_factory_{this};
 };
 
 }  // namespace ash
diff --git a/ash/system/message_center/message_center_constants.h b/ash/system/message_center/message_center_constants.h
index 9140d32..4d0b206 100644
--- a/ash/system/message_center/message_center_constants.h
+++ b/ash/system/message_center/message_center_constants.h
@@ -62,6 +62,11 @@
 constexpr int kMessageViewFadeInAnimationDurationMs = 100;
 constexpr int kMessageViewInExpandedStateFadeInAnimationDelayMs = 100;
 constexpr int kMessageViewInExpandedStateFadeInAnimationDurationMs = 183;
+constexpr int kActionsRowFadeInAnimationDelayMs = 50;
+constexpr int kActionsRowFadeInAnimationDurationMs = 100;
+constexpr int kActionButtonsFadeOutAnimationDurationMs = 100;
+constexpr int kInlineReplyFadeInAnimationDurationMs = 100;
+constexpr int kInlineReplyFadeOutAnimationDurationMs = 50;
 
 }  // namespace ash
 
diff --git a/ash/system/phonehub/enable_hotspot_quick_action_controller.cc b/ash/system/phonehub/enable_hotspot_quick_action_controller.cc
index 5299846..763c1140 100644
--- a/ash/system/phonehub/enable_hotspot_quick_action_controller.cc
+++ b/ash/system/phonehub/enable_hotspot_quick_action_controller.cc
@@ -31,8 +31,7 @@
 QuickActionItem* EnableHotspotQuickActionController::CreateItem() {
   DCHECK(!item_);
   item_ = new QuickActionItem(this, IDS_ASH_PHONE_HUB_ENABLE_HOTSPOT_TITLE,
-                              kPhoneHubEnableHotspotOnIcon,
-                              kPhoneHubEnableHotspotOffIcon);
+                              kPhoneHubEnableHotspotIcon);
   OnTetherStatusChanged();
   return item_;
 }
@@ -118,11 +117,11 @@
   item_->SetSubLabelColor(sub_label_color);
 
   if (state == ActionState::kNoReception) {
-    item_->SetIconTooltip(l10n_util::GetStringUTF16(state_text_id));
+    item_->SetTooltip(l10n_util::GetStringUTF16(state_text_id));
   } else {
     std::u16string tooltip_state =
         l10n_util::GetStringFUTF16(state_text_id, item_->GetItemLabel());
-    item_->SetIconTooltip(l10n_util::GetStringFUTF16(
+    item_->SetTooltip(l10n_util::GetStringFUTF16(
         IDS_ASH_PHONE_HUB_QUICK_ACTIONS_TOGGLE_TOOLTIP, item_->GetItemLabel(),
         tooltip_state));
   }
diff --git a/ash/system/phonehub/locate_phone_quick_action_controller.cc b/ash/system/phonehub/locate_phone_quick_action_controller.cc
index ab713efb..2770395 100644
--- a/ash/system/phonehub/locate_phone_quick_action_controller.cc
+++ b/ash/system/phonehub/locate_phone_quick_action_controller.cc
@@ -41,8 +41,7 @@
 QuickActionItem* LocatePhoneQuickActionController::CreateItem() {
   DCHECK(!item_);
   item_ = new QuickActionItem(this, IDS_ASH_PHONE_HUB_LOCATE_PHONE_TITLE,
-                              kPhoneHubLocatePhoneOnIcon,
-                              kPhoneHubLocatePhoneOffIcon);
+                              kPhoneHubLocatePhoneIcon);
   OnPhoneRingingStateChanged();
   return item_;
 }
@@ -122,11 +121,11 @@
   item_->SetToggled(icon_enabled);
   item_->SetSubLabel(l10n_util::GetStringUTF16(sub_label_text));
   if (state == ActionState::kNotAvailable) {
-    item_->SetIconTooltip(l10n_util::GetStringUTF16(state_text_id));
+    item_->SetTooltip(l10n_util::GetStringUTF16(state_text_id));
   } else {
     std::u16string tooltip_state =
         l10n_util::GetStringFUTF16(state_text_id, item_->GetItemLabel());
-    item_->SetIconTooltip(l10n_util::GetStringFUTF16(
+    item_->SetTooltip(l10n_util::GetStringFUTF16(
         IDS_ASH_PHONE_HUB_QUICK_ACTIONS_TOGGLE_TOOLTIP, item_->GetItemLabel(),
         tooltip_state));
   }
diff --git a/ash/system/phonehub/phone_hub_notification_controller.cc b/ash/system/phonehub/phone_hub_notification_controller.cc
index f7f1754..f52473c 100644
--- a/ash/system/phonehub/phone_hub_notification_controller.cc
+++ b/ash/system/phonehub/phone_hub_notification_controller.cc
@@ -523,7 +523,7 @@
               message_center::NotifierType::SYSTEM_COMPONENT,
               kPhoneHubInstantTetherNotificationId),
           message_center::RichNotificationData(), std::move(delegate),
-          kPhoneHubEnableHotspotOnIcon,
+          kPhoneHubEnableHotspotIcon,
           message_center::SystemNotificationWarningLevel::NORMAL);
   message_center::MessageCenter::Get()->AddNotification(
       std::move(notification));
diff --git a/ash/system/phonehub/quick_action_item.cc b/ash/system/phonehub/quick_action_item.cc
index ad1f516..b7fa503 100644
--- a/ash/system/phonehub/quick_action_item.cc
+++ b/ash/system/phonehub/quick_action_item.cc
@@ -39,9 +39,7 @@
 
 QuickActionItem::QuickActionItem(Delegate* delegate,
                                  int label_id,
-                                 const gfx::VectorIcon& icon_on,
-                                 const gfx::VectorIcon& icon_off)
-    : icon_on_(icon_on), icon_off_(icon_off) {
+                                 const gfx::VectorIcon& icon) {
   SetPreferredSize(kUnifiedFeaturePodSize);
   auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kVertical, gfx::Insets(),
@@ -56,6 +54,7 @@
           },
           delegate, this),
       true /* is_togglable */));
+  icon_button_->SetVectorIcon(icon);
 
   auto* label_view = AddChildView(std::make_unique<views::View>());
   label_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
@@ -80,11 +79,6 @@
   layer()->SetFillsBoundsOpaquely(false);
 }
 
-QuickActionItem::QuickActionItem(Delegate* delegate,
-                                 int label_id,
-                                 const gfx::VectorIcon& icon)
-    : QuickActionItem(delegate, label_id, icon, icon) {}
-
 QuickActionItem::~QuickActionItem() = default;
 
 void QuickActionItem::SetSubLabel(const std::u16string& sub_label) {
@@ -98,17 +92,12 @@
   sub_label_->SetEnabledColor(sub_label_color_);
 }
 
-void QuickActionItem::SetIcon(bool is_on) {
-  icon_button_->SetVectorIcon(is_on ? icon_on_ : icon_off_);
-}
-
-void QuickActionItem::SetIconTooltip(const std::u16string& text) {
+void QuickActionItem::SetTooltip(const std::u16string& text) {
   icon_button_->SetTooltipText(text);
 }
 
 void QuickActionItem::SetToggled(bool toggled) {
   icon_button_->SetToggled(toggled);
-  SetIcon(toggled /* is_on */);
 }
 
 bool QuickActionItem::IsToggled() const {
@@ -134,7 +123,6 @@
     icon_button_->SetTooltipText(l10n_util::GetStringFUTF16(
         IDS_ASH_PHONE_HUB_QUICK_ACTIONS_NOT_AVAILABLE_STATE_TOOLTIP,
         GetItemLabel()));
-    SetIcon(false /* is_on */);
   } else {
     label_->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
         AshColorProvider::ContentLayerType::kTextColorPrimary));
diff --git a/ash/system/phonehub/quick_action_item.h b/ash/system/phonehub/quick_action_item.h
index 5162887..86389c7 100644
--- a/ash/system/phonehub/quick_action_item.h
+++ b/ash/system/phonehub/quick_action_item.h
@@ -23,13 +23,6 @@
     virtual void OnButtonPressed(bool is_now_enabled) = 0;
   };
 
-  // |icon_on| and |icon_off| indicates the icons used in on/off state of the
-  // button.
-  QuickActionItem(Delegate* delegate,
-                  int label_id,
-                  const gfx::VectorIcon& icon_on,
-                  const gfx::VectorIcon& icon_off);
-
   // If only one icon is supplied, it will be used in both cases.
   QuickActionItem(Delegate* delegate,
                   int label_id,
@@ -45,11 +38,8 @@
   // Set the color of sub-label shown below the label.
   void SetSubLabelColor(SkColor color);
 
-  // Set the icon button to be either |icon_on_| or |icon_off_|.
-  void SetIcon(bool is_on);
-
   // Set the tooltip text of the icon button.
-  void SetIconTooltip(const std::u16string& text);
+  void SetTooltip(const std::u16string& text);
 
   // Change the toggled state. If toggled, the background color of the circle
   // will change.
@@ -73,8 +63,6 @@
  private:
   // Owned by views hierarchy.
   FeaturePodIconButton* icon_button_ = nullptr;
-  const gfx::VectorIcon& icon_on_;
-  const gfx::VectorIcon& icon_off_;
   views::Label* label_ = nullptr;
   views::Label* sub_label_ = nullptr;
 
diff --git a/ash/system/phonehub/silence_phone_quick_action_controller.cc b/ash/system/phonehub/silence_phone_quick_action_controller.cc
index fa2cc1c..5cde8a4 100644
--- a/ash/system/phonehub/silence_phone_quick_action_controller.cc
+++ b/ash/system/phonehub/silence_phone_quick_action_controller.cc
@@ -43,8 +43,7 @@
 QuickActionItem* SilencePhoneQuickActionController::CreateItem() {
   DCHECK(!item_);
   item_ = new QuickActionItem(this, IDS_ASH_PHONE_HUB_SILENCE_PHONE_TITLE,
-                              kPhoneHubSilencePhoneOnIcon,
-                              kPhoneHubSilencePhoneOffIcon);
+                              kPhoneHubSilencePhoneIcon);
   item_->icon_button()->set_button_behavior(
       FeaturePodIconButton::DisabledButtonBehavior::
           kCanDisplayDisabledToggleValue);
@@ -119,11 +118,11 @@
   item_->SetToggled(icon_enabled);
   item_->SetSubLabel(l10n_util::GetStringUTF16(sub_label_text));
   if (state == ActionState::kDisabled) {
-    item_->SetIconTooltip(l10n_util::GetStringUTF16(state_text_id));
+    item_->SetTooltip(l10n_util::GetStringUTF16(state_text_id));
   } else {
     std::u16string tooltip_state =
         l10n_util::GetStringFUTF16(state_text_id, item_->GetItemLabel());
-    item_->SetIconTooltip(l10n_util::GetStringFUTF16(
+    item_->SetTooltip(l10n_util::GetStringFUTF16(
         IDS_ASH_PHONE_HUB_QUICK_ACTIONS_TOGGLE_TOOLTIP, item_->GetItemLabel(),
         tooltip_state));
   }
diff --git a/ash/system/update/update_notification_controller.cc b/ash/system/update/update_notification_controller.cc
index 7d6670c..2350208 100644
--- a/ash/system/update/update_notification_controller.cc
+++ b/ash/system/update/update_notification_controller.cc
@@ -24,6 +24,7 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/chromeos/devicetype_utils.h"
+#include "ui/gfx/vector_icon_types.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/public/cpp/notification.h"
 
@@ -77,23 +78,9 @@
     slow_boot_file_path_exists_ = slow_boot_file_path_exists.value();
   }
 
-  const bool is_rollback = model_->rollback();
-
-  message_center::SystemNotificationWarningLevel warning_level =
-      (is_rollback || model_->relaunch_notification_state().requirement_type ==
-                          RelaunchNotificationState::kRequired)
-          ? message_center::SystemNotificationWarningLevel::WARNING
-          : message_center::SystemNotificationWarningLevel::NORMAL;
-  const gfx::VectorIcon& notification_icon =
-      is_rollback ? kSystemMenuRollbackIcon
-                  : (model_->relaunch_notification_state().requirement_type ==
-                     RelaunchNotificationState::kNone)
-                        ? kSystemMenuUpdateIcon
-                        : vector_icons::kBusinessIcon;
   std::unique_ptr<Notification> notification = CreateSystemNotification(
-      message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
-      GetNotificationTitle(), GetNotificationMessage(),
-      std::u16string() /* display_source */, GURL(),
+      message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, GetTitle(),
+      GetMessage(), std::u16string() /* display_source */, GURL(),
       message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
                                  kNotifierId),
       message_center::RichNotificationData(),
@@ -101,7 +88,7 @@
           base::BindRepeating(
               &UpdateNotificationController::HandleNotificationClick,
               weak_ptr_factory_.GetWeakPtr())),
-      notification_icon, warning_level);
+      GetIcon(), GetWarningLevel());
   notification->set_pinned(true);
 
   if (model_->relaunch_notification_state().requirement_type ==
@@ -110,9 +97,12 @@
 
   if (model_->update_required()) {
     std::vector<message_center::ButtonInfo> notification_actions;
-    if (is_rollback) {
+    if (model_->rollback()) {
       notification_actions.push_back(message_center::ButtonInfo(
           l10n_util::GetStringUTF16(IDS_ROLLBACK_NOTIFICATION_RESTART_BUTTON)));
+    } else if (model_->factory_reset_required()) {
+      notification_actions.push_back(message_center::ButtonInfo(
+          l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_RESET_TO_UPDATE)));
     } else {
       notification_actions.push_back(message_center::ButtonInfo(
           l10n_util::GetStringUTF16(IDS_UPDATE_NOTIFICATION_RESTART_BUTTON)));
@@ -135,32 +125,88 @@
   return model_->update_required() || model_->update_over_cellular_available();
 }
 
-std::u16string UpdateNotificationController::GetNotificationMessage() const {
+std::u16string UpdateNotificationController::GetTitle() const {
+  if (model_->update_type() == UpdateType::kLacros)
+    return l10n_util::GetStringUTF16(IDS_UPDATE_NOTIFICATION_TITLE_LACROS);
+
+  switch (model_->relaunch_notification_state().requirement_type) {
+    case RelaunchNotificationState::kRecommendedAndOverdue:
+      return model_->rollback() ? l10n_util::GetStringUTF16(
+                                      IDS_ROLLBACK_OVERDUE_NOTIFICATION_TITLE)
+                                : l10n_util::GetStringUTF16(
+                                      IDS_RELAUNCH_RECOMMENDED_OVERDUE_TITLE);
+
+    case RelaunchNotificationState::kRecommendedNotOverdue:
+      return model_->rollback()
+                 ? l10n_util::GetStringUTF16(IDS_ROLLBACK_NOTIFICATION_TITLE)
+                 : l10n_util::GetStringUTF16(IDS_RELAUNCH_RECOMMENDED_TITLE);
+
+    case RelaunchNotificationState::kRequired: {
+      const base::TimeDelta& rounded_offset =
+          model_->relaunch_notification_state()
+              .rounded_time_until_reboot_required;
+      if (rounded_offset.InDays() >= 2) {
+        return l10n_util::GetPluralStringFUTF16(
+            model_->rollback() ? IDS_ROLLBACK_REQUIRED_TITLE_DAYS
+                               : IDS_RELAUNCH_REQUIRED_TITLE_DAYS,
+            rounded_offset.InDays());
+      }
+      if (rounded_offset.InHours() >= 1) {
+        return l10n_util::GetPluralStringFUTF16(
+            model_->rollback() ? IDS_ROLLBACK_REQUIRED_TITLE_HOURS
+                               : IDS_RELAUNCH_REQUIRED_TITLE_HOURS,
+            rounded_offset.InHours());
+      }
+      if (rounded_offset.InMinutes() >= 1) {
+        return l10n_util::GetPluralStringFUTF16(
+            model_->rollback() ? IDS_ROLLBACK_REQUIRED_TITLE_MINUTES
+                               : IDS_RELAUNCH_REQUIRED_TITLE_MINUTES,
+            rounded_offset.InMinutes());
+      }
+      return l10n_util::GetPluralStringFUTF16(
+          model_->rollback() ? IDS_ROLLBACK_REQUIRED_TITLE_SECONDS
+                             : IDS_RELAUNCH_REQUIRED_TITLE_SECONDS,
+          rounded_offset.InSeconds());
+    }
+    case RelaunchNotificationState::kNone:
+      return model_->rollback()
+                 ? l10n_util::GetStringUTF16(IDS_ROLLBACK_NOTIFICATION_TITLE)
+                 : l10n_util::GetStringUTF16(IDS_UPDATE_NOTIFICATION_TITLE);
+  }
+}
+
+std::u16string UpdateNotificationController::GetMessage() const {
   if (model_->update_type() == UpdateType::kLacros)
     return l10n_util::GetStringUTF16(IDS_UPDATE_NOTIFICATION_MESSAGE_LACROS);
 
   const std::u16string system_app_name =
       l10n_util::GetStringUTF16(IDS_ASH_MESSAGE_CENTER_SYSTEM_APP_NAME);
-  if (model_->rollback()) {
-    return l10n_util::GetStringUTF16(IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK);
-  }
-  if (model_->factory_reset_required()) {
+  if (model_->factory_reset_required() && !model_->rollback()) {
     return l10n_util::GetStringFUTF16(IDS_UPDATE_NOTIFICATION_MESSAGE_POWERWASH,
+                                      ui::GetChromeOSDeviceName(),
                                       system_app_name);
   }
 
   absl::optional<int> body_message_id = absl::nullopt;
   switch (model_->relaunch_notification_state().requirement_type) {
     case RelaunchNotificationState::kRecommendedNotOverdue:
-      body_message_id = IDS_RELAUNCH_RECOMMENDED_BODY;
+      body_message_id = model_->rollback()
+                            ? IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK
+                            : IDS_RELAUNCH_RECOMMENDED_BODY;
       break;
     case RelaunchNotificationState::kRecommendedAndOverdue:
-      body_message_id = IDS_RELAUNCH_RECOMMENDED_OVERDUE_BODY;
+      body_message_id = model_->rollback()
+                            ? IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK_OVERDUE
+                            : IDS_RELAUNCH_RECOMMENDED_OVERDUE_BODY;
       break;
     case RelaunchNotificationState::kRequired:
-      body_message_id = IDS_RELAUNCH_REQUIRED_BODY;
+      body_message_id = model_->rollback() ? IDS_ROLLBACK_REQUIRED_BODY
+                                           : IDS_RELAUNCH_REQUIRED_BODY;
       break;
     case RelaunchNotificationState::kNone:
+      if (model_->rollback()) {
+        body_message_id = IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK;
+      }
       break;
   }
 
@@ -182,42 +228,30 @@
   return update_text;
 }
 
-std::u16string UpdateNotificationController::GetNotificationTitle() const {
-  if (model_->update_type() == UpdateType::kLacros)
-    return l10n_util::GetStringUTF16(IDS_UPDATE_NOTIFICATION_TITLE_LACROS);
+const gfx::VectorIcon& UpdateNotificationController::GetIcon() const {
+  if (model_->rollback())
+    return kSystemMenuRollbackIcon;
+  if (model_->relaunch_notification_state().requirement_type ==
+      RelaunchNotificationState::kNone)
+    return kSystemMenuUpdateIcon;
+  return vector_icons::kBusinessIcon;
+}
 
-  switch (model_->relaunch_notification_state().requirement_type) {
-    case RelaunchNotificationState::kRecommendedAndOverdue:
-      return l10n_util::GetStringUTF16(IDS_RELAUNCH_RECOMMENDED_OVERDUE_TITLE);
-
-    case RelaunchNotificationState::kRecommendedNotOverdue:
-      return l10n_util::GetStringUTF16(IDS_RELAUNCH_RECOMMENDED_TITLE);
-
-    case RelaunchNotificationState::kRequired: {
-      const base::TimeDelta& rounded_offset =
-          model_->relaunch_notification_state()
-              .rounded_time_until_reboot_required;
-      if (rounded_offset.InDays() >= 2) {
-        return l10n_util::GetPluralStringFUTF16(
-            IDS_RELAUNCH_REQUIRED_TITLE_DAYS, rounded_offset.InDays());
-      }
-      if (rounded_offset.InHours() >= 1) {
-        return l10n_util::GetPluralStringFUTF16(
-            IDS_RELAUNCH_REQUIRED_TITLE_HOURS, rounded_offset.InHours());
-      }
-      if (rounded_offset.InMinutes() >= 1) {
-        return l10n_util::GetPluralStringFUTF16(
-            IDS_RELAUNCH_REQUIRED_TITLE_MINUTES, rounded_offset.InMinutes());
-      }
-
-      return l10n_util::GetPluralStringFUTF16(
-          IDS_RELAUNCH_REQUIRED_TITLE_SECONDS, rounded_offset.InSeconds());
-    }
-    case RelaunchNotificationState::kNone:
-      return model_->rollback()
-                 ? l10n_util::GetStringUTF16(IDS_ROLLBACK_NOTIFICATION_TITLE)
-                 : l10n_util::GetStringUTF16(IDS_UPDATE_NOTIFICATION_TITLE);
+message_center::SystemNotificationWarningLevel
+UpdateNotificationController::GetWarningLevel() const {
+  if (model_->rollback() &&
+      (model_->relaunch_notification_state().requirement_type ==
+           RelaunchNotificationState::kRequired ||
+       model_->relaunch_notification_state().requirement_type ==
+           RelaunchNotificationState::kRecommendedAndOverdue)) {
+    return message_center::SystemNotificationWarningLevel::CRITICAL_WARNING;
   }
+  if (model_->rollback() ||
+      model_->relaunch_notification_state().requirement_type ==
+          RelaunchNotificationState::kRequired) {
+    return message_center::SystemNotificationWarningLevel::WARNING;
+  }
+  return message_center::SystemNotificationWarningLevel::NORMAL;
 }
 
 void UpdateNotificationController::RestartForUpdate() {
diff --git a/ash/system/update/update_notification_controller.h b/ash/system/update/update_notification_controller.h
index e788d87..04d1d8a 100644
--- a/ash/system/update/update_notification_controller.h
+++ b/ash/system/update/update_notification_controller.h
@@ -10,6 +10,13 @@
 #include "base/files/file_path.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
+namespace gfx {
+struct VectorIcon;
+}
+namespace message_center {
+enum class SystemNotificationWarningLevel;
+}
+
 namespace ash {
 
 class ShutdownConfirmationDialog;
@@ -38,8 +45,10 @@
   friend class UpdateNotificationControllerTest;
 
   bool ShouldShowUpdate() const;
-  std::u16string GetNotificationTitle() const;
-  std::u16string GetNotificationMessage() const;
+  std::u16string GetTitle() const;
+  std::u16string GetMessage() const;
+  const gfx::VectorIcon& GetIcon() const;
+  message_center::SystemNotificationWarningLevel GetWarningLevel() const;
   void HandleNotificationClick(absl::optional<int> index);
   void GenerateUpdateNotification(
       absl::optional<bool> slow_boot_file_path_exists);
diff --git a/ash/system/update/update_notification_controller_unittest.cc b/ash/system/update/update_notification_controller_unittest.cc
index 5d7299e..4c843fe 100644
--- a/ash/system/update/update_notification_controller_unittest.cc
+++ b/ash/system/update/update_notification_controller_unittest.cc
@@ -4,7 +4,9 @@
 
 #include "ash/system/update/update_notification_controller.h"
 
+#include "ash/public/cpp/notification_utils.h"
 #include "ash/public/cpp/update_types.h"
+#include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/model/enterprise_domain_model.h"
@@ -18,12 +20,15 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/branding_buildflags.h"
+#include "components/vector_icons/vector_icons.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/chromeos/devicetype_utils.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/message_center_observer.h"
 #include "ui/message_center/public/cpp/notification_delegate.h"
+#include "ui/message_center/public/cpp/notification_types.h"
 
 namespace ash {
 namespace {
@@ -86,42 +91,41 @@
   }
 
  protected:
-  bool HasNotification() {
+  message_center::Notification* GetNotification() {
     return message_center::MessageCenter::Get()->FindVisibleNotificationById(
         kNotificationId);
   }
 
+  bool HasNotification() { return GetNotification(); }
+
   std::string GetNotificationTitle() {
-    return base::UTF16ToUTF8(message_center::MessageCenter::Get()
-                                 ->FindVisibleNotificationById(kNotificationId)
-                                 ->title());
+    return base::UTF16ToUTF8(GetNotification()->title());
   }
 
   std::string GetNotificationMessage() {
-    return base::UTF16ToUTF8(message_center::MessageCenter::Get()
-                                 ->FindVisibleNotificationById(kNotificationId)
-                                 ->message());
+    return base::UTF16ToUTF8(GetNotification()->message());
   }
 
   std::string GetNotificationButton(int index) {
-    return base::UTF16ToUTF8(message_center::MessageCenter::Get()
-                                 ->FindVisibleNotificationById(kNotificationId)
-                                 ->buttons()
-                                 .at(index)
-                                 .title);
+    return base::UTF16ToUTF8(GetNotification()->buttons().at(index).title);
   }
 
   int GetNotificationButtonCount() {
-    return message_center::MessageCenter::Get()
-        ->FindVisibleNotificationById(kNotificationId)
-        ->buttons()
-        .size();
+    return GetNotification()->buttons().size();
   }
 
-  int GetNotificationPriority() {
-    return message_center::MessageCenter::Get()
-        ->FindVisibleNotificationById(kNotificationId)
-        ->priority();
+  int GetNotificationPriority() { return GetNotification()->priority(); }
+
+  absl::optional<SkColor> GetNotificationColor() {
+    return GetNotification()->accent_color();
+  }
+
+  const gfx::VectorIcon& GetNotificationIcon() {
+    return GetNotification()->vector_small_image();
+  }
+
+  bool GetNotificationNeverTimeout() {
+    return GetNotification()->never_timeout();
   }
 
   void AddSlowBootFilePath(const base::FilePath& file_path) {
@@ -144,10 +148,6 @@
 // Tests that the update icon becomes visible when an update becomes
 // available.
 TEST_F(UpdateNotificationControllerTest, VisibilityAfterUpdate) {
-  // The system starts with no update pending, so the notification isn't
-  // visible.
-  EXPECT_FALSE(HasNotification());
-
   ShowDefaultUpdateNotification();
 
   // Showing Update Notification posts a task to check for slow boot request
@@ -157,6 +157,9 @@
 
   // The notification is now visible.
   ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorNormal, *GetNotificationColor());
+  EXPECT_TRUE(strcmp(kSystemMenuUpdateIcon.name, GetNotificationIcon().name) ==
+              0);
   EXPECT_EQ("Update available", GetNotificationTitle());
   EXPECT_EQ("Learn more about the latest " +
                 base::UTF16ToUTF8(system_app_name_) + " update",
@@ -167,10 +170,6 @@
 // Tests that the update icon becomes visible when an update becomes
 // available.
 TEST_F(UpdateNotificationControllerTest, VisibilityAfterUpdateWithSlowReboot) {
-  // The system starts with no update pending, so the notification isn't
-  // visible.
-  EXPECT_FALSE(HasNotification());
-
   // Add a slow boot file.
   base::ScopedTempDir tmp_dir;
   ASSERT_TRUE(tmp_dir.CreateUniqueTempDir());
@@ -185,6 +184,9 @@
 
   // The notification is now visible.
   ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorNormal, *GetNotificationColor());
+  EXPECT_TRUE(strcmp(kSystemMenuUpdateIcon.name, GetNotificationIcon().name) ==
+              0);
   EXPECT_EQ("Update available", GetNotificationTitle());
   EXPECT_EQ("Learn more about the latest " +
                 base::UTF16ToUTF8(system_app_name_) +
@@ -216,10 +218,6 @@
 // available for downloading over cellular connection.
 TEST_F(UpdateNotificationControllerTest,
        VisibilityAfterUpdateOverCellularAvailable) {
-  // The system starts with no update pending, so the notification isn't
-  // visible.
-  EXPECT_FALSE(HasNotification());
-
   // Simulate an update available for downloading over cellular connection.
   Shell::Get()->system_tray_model()->SetUpdateOverCellularAvailableIconVisible(
       true);
@@ -231,6 +229,9 @@
 
   // The notification is now visible.
   ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorNormal, *GetNotificationColor());
+  EXPECT_TRUE(strcmp(kSystemMenuUpdateIcon.name, GetNotificationIcon().name) ==
+              0);
   EXPECT_EQ("Update available", GetNotificationTitle());
   EXPECT_EQ("Learn more about the latest " +
                 base::UTF16ToUTF8(system_app_name_) + " update",
@@ -253,10 +254,6 @@
 
 TEST_F(UpdateNotificationControllerTest,
        VisibilityAfterUpdateRequiringFactoryReset) {
-  // The system starts with no update pending, so the notification isn't
-  // visible.
-  EXPECT_FALSE(HasNotification());
-
   // Simulate an update that requires factory reset.
   Shell::Get()->system_tray_model()->ShowUpdateIcon(UpdateSeverity::kLow, true,
                                                     false, UpdateType::kSystem);
@@ -266,39 +263,20 @@
   // until everything is complete and then check if the notification is visible.
   task_environment()->RunUntilIdle();
 
-  // The notification is now visible.
-  ASSERT_TRUE(HasNotification());
-  EXPECT_EQ("Update available", GetNotificationTitle());
-  EXPECT_EQ(
-      "This update requires powerwashing your device."
-      " Learn more about the latest " +
-          base::UTF16ToUTF8(system_app_name_) + " update.",
-      GetNotificationMessage());
-  EXPECT_EQ("Restart to update", GetNotificationButton(0));
-}
-
-TEST_F(UpdateNotificationControllerTest, VisibilityAfterRollback) {
-  // The system starts with no update pending, so the notification isn't
-  // visible.
-  EXPECT_FALSE(HasNotification());
-
-  // Simulate a rollback.
-  Shell::Get()->system_tray_model()->ShowUpdateIcon(UpdateSeverity::kLow, false,
-                                                    true, UpdateType::kSystem);
-
-  // Showing Update Notification posts a task to check for slow boot request
-  // and use the result of that check to generate appropriate notification. Wait
-  // until everything is complete and then check if the notification is visible.
-  task_environment()->RunUntilIdle();
+  const std::u16string chrome_os_device_name = ui::GetChromeOSDeviceName();
 
   // The notification is now visible.
   ASSERT_TRUE(HasNotification());
-  EXPECT_EQ("Device will be rolled back", GetNotificationTitle());
-  EXPECT_EQ(
-      "Your administrator is rolling back your device. All data will"
-      " be deleted when the device is restarted.",
-      GetNotificationMessage());
-  EXPECT_EQ("Restart and reset", GetNotificationButton(0));
+  EXPECT_EQ(kSystemNotificationColorNormal, *GetNotificationColor());
+  EXPECT_TRUE(strcmp(kSystemMenuUpdateIcon.name, GetNotificationIcon().name) ==
+              0);
+  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_UPDATE_NOTIFICATION_TITLE),
+            GetNotificationTitle());
+  EXPECT_EQ(l10n_util::GetStringFUTF8(IDS_UPDATE_NOTIFICATION_MESSAGE_POWERWASH,
+                                      chrome_os_device_name, system_app_name_),
+            GetNotificationMessage());
+  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_RESET_TO_UPDATE),
+            GetNotificationButton(0));
 }
 
 TEST_F(UpdateNotificationControllerTest, NoUpdateNotification) {
@@ -307,6 +285,127 @@
   EXPECT_FALSE(HasNotification());
 }
 
+TEST_F(UpdateNotificationControllerTest, RollbackNotification) {
+  Shell::Get()->system_tray_model()->ShowUpdateIcon(
+      UpdateSeverity::kLow, /*factory_reset_required=*/true,
+      /*rollback=*/true, UpdateType::kSystem);
+
+  // Showing Update Notification posts a task to check for slow boot request
+  // and use the result of that check to generate appropriate notification. Wait
+  // until everything is complete and then check if the notification is visible.
+  task_environment()->RunUntilIdle();
+
+  const std::u16string chrome_os_device_name = ui::GetChromeOSDeviceName();
+
+  // The notification is now visible.
+  ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorWarning, *GetNotificationColor());
+  EXPECT_TRUE(
+      strcmp(kSystemMenuRollbackIcon.name, GetNotificationIcon().name) == 0);
+  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_ROLLBACK_NOTIFICATION_TITLE),
+            GetNotificationTitle());
+  EXPECT_EQ(l10n_util::GetStringFUTF8(IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK,
+                                      base::ASCIIToUTF16(kDomain),
+                                      chrome_os_device_name),
+            GetNotificationMessage());
+  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_ROLLBACK_NOTIFICATION_RESTART_BUTTON),
+            GetNotificationButton(0));
+}
+
+TEST_F(UpdateNotificationControllerTest, RollbackRecommendedNotification) {
+  Shell::Get()->system_tray_model()->ShowUpdateIcon(
+      UpdateSeverity::kLow, /*factory_reset_required=*/true,
+      /*rollback=*/true, UpdateType::kSystem);
+
+  Shell::Get()->system_tray_model()->SetRelaunchNotificationState(
+      {.requirement_type = RelaunchNotificationState::kRecommendedNotOverdue});
+
+  // Showing Update Notification posts a task to check for slow boot request
+  // and use the result of that check to generate appropriate notification. Wait
+  // until everything is complete and then check if the notification is visible.
+  task_environment()->RunUntilIdle();
+
+  const std::u16string chrome_os_device_name = ui::GetChromeOSDeviceName();
+
+  // Notification is the same as for a non-recommended rollback.
+  ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorWarning, *GetNotificationColor());
+  EXPECT_TRUE(
+      strcmp(kSystemMenuRollbackIcon.name, GetNotificationIcon().name) == 0);
+  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_ROLLBACK_NOTIFICATION_TITLE),
+            GetNotificationTitle());
+  EXPECT_EQ(l10n_util::GetStringFUTF8(IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK,
+                                      base::ASCIIToUTF16(kDomain),
+                                      chrome_os_device_name),
+            GetNotificationMessage());
+  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_ROLLBACK_NOTIFICATION_RESTART_BUTTON),
+            GetNotificationButton(0));
+}
+
+TEST_F(UpdateNotificationControllerTest,
+       RollbackRecommendedOverdueNotification) {
+  Shell::Get()->system_tray_model()->ShowUpdateIcon(
+      UpdateSeverity::kLow, /*factory_reset_required=*/true,
+      /*rollback=*/true, UpdateType::kSystem);
+
+  Shell::Get()->system_tray_model()->SetRelaunchNotificationState(
+      {.requirement_type = RelaunchNotificationState::kRecommendedAndOverdue});
+
+  // Showing Update Notification posts a task to check for slow boot request
+  // and use the result of that check to generate appropriate notification. Wait
+  // until everything is complete and then check if the notification is visible.
+  task_environment()->RunUntilIdle();
+
+  const std::u16string chrome_os_device_name = ui::GetChromeOSDeviceName();
+
+  ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorCriticalWarning, *GetNotificationColor());
+  EXPECT_TRUE(
+      strcmp(kSystemMenuRollbackIcon.name, GetNotificationIcon().name) == 0);
+  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_ROLLBACK_OVERDUE_NOTIFICATION_TITLE),
+            GetNotificationTitle());
+  EXPECT_EQ(l10n_util::GetStringFUTF8(
+                IDS_UPDATE_NOTIFICATION_MESSAGE_ROLLBACK_OVERDUE,
+                base::ASCIIToUTF16(kDomain), chrome_os_device_name),
+            GetNotificationMessage());
+  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_ROLLBACK_NOTIFICATION_RESTART_BUTTON),
+            GetNotificationButton(0));
+}
+
+TEST_F(UpdateNotificationControllerTest, RollbackRequiredNotification) {
+  Shell::Get()->system_tray_model()->ShowUpdateIcon(
+      UpdateSeverity::kLow, /*factory_reset_required=*/true,
+      /*rollback=*/true, UpdateType::kSystem);
+
+  constexpr base::TimeDelta remaining_time = base::Seconds(3);
+
+  Shell::Get()->system_tray_model()->SetRelaunchNotificationState({
+      .requirement_type = RelaunchNotificationState::kRequired,
+      .rounded_time_until_reboot_required = remaining_time,
+  });
+
+  const std::u16string chrome_os_device_name = ui::GetChromeOSDeviceName();
+
+  // Showing Update Notification posts a task to check for slow boot request
+  // and use the result of that check to generate appropriate notification. Wait
+  // until everything is complete and then check if the notification is visible.
+  task_environment()->RunUntilIdle();
+
+  ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorCriticalWarning, *GetNotificationColor());
+  EXPECT_TRUE(
+      strcmp(kSystemMenuRollbackIcon.name, GetNotificationIcon().name) == 0);
+  EXPECT_EQ(
+      l10n_util::GetPluralStringFUTF8(IDS_ROLLBACK_REQUIRED_TITLE_SECONDS, 3),
+      GetNotificationTitle());
+  EXPECT_EQ(l10n_util::GetStringFUTF8(IDS_ROLLBACK_REQUIRED_BODY,
+                                      base::ASCIIToUTF16(kDomain),
+                                      chrome_os_device_name),
+            GetNotificationMessage());
+  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_ROLLBACK_NOTIFICATION_RESTART_BUTTON),
+            GetNotificationButton(0));
+}
+
 TEST_F(UpdateNotificationControllerTest, SetUpdateNotificationRecommended) {
   ShowDefaultUpdateNotification();
 
@@ -324,6 +423,9 @@
       chrome_os_device_name);
 
   ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorNormal, *GetNotificationColor());
+  EXPECT_TRUE(strcmp(vector_icons::kBusinessIcon.name,
+                     GetNotificationIcon().name) == 0);
   EXPECT_EQ(expected_notification_title, GetNotificationTitle());
   EXPECT_EQ(expected_notification_body, GetNotificationMessage());
   EXPECT_EQ(l10n_util::GetStringUTF8(IDS_UPDATE_NOTIFICATION_RESTART_BUTTON),
@@ -348,6 +450,9 @@
       chrome_os_device_name);
 
   ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorNormal, *GetNotificationColor());
+  EXPECT_TRUE(strcmp(vector_icons::kBusinessIcon.name,
+                     GetNotificationIcon().name) == 0);
   EXPECT_EQ(expected_notification_title, GetNotificationTitle());
   EXPECT_EQ(expected_notification_body, GetNotificationMessage());
   EXPECT_EQ(l10n_util::GetStringUTF8(IDS_UPDATE_NOTIFICATION_RESTART_BUTTON),
@@ -374,6 +479,11 @@
       chrome_os_device_name);
 
   ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorWarning, *GetNotificationColor());
+  EXPECT_TRUE(strcmp(vector_icons::kBusinessIcon.name,
+                     GetNotificationIcon().name) == 0);
+  EXPECT_EQ(message_center::SYSTEM_PRIORITY, GetNotificationPriority());
+  EXPECT_EQ(true, GetNotificationNeverTimeout());
   EXPECT_EQ(expected_notification_title, GetNotificationTitle());
   EXPECT_EQ(expected_notification_body, GetNotificationMessage());
   EXPECT_EQ(l10n_util::GetStringUTF8(IDS_UPDATE_NOTIFICATION_RESTART_BUTTON),
@@ -400,6 +510,11 @@
       chrome_os_device_name);
 
   ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorWarning, *GetNotificationColor());
+  EXPECT_TRUE(strcmp(vector_icons::kBusinessIcon.name,
+                     GetNotificationIcon().name) == 0);
+  EXPECT_EQ(message_center::SYSTEM_PRIORITY, GetNotificationPriority());
+  EXPECT_EQ(true, GetNotificationNeverTimeout());
   EXPECT_EQ(expected_notification_title, GetNotificationTitle());
   EXPECT_EQ(expected_notification_body, GetNotificationMessage());
   EXPECT_EQ(l10n_util::GetStringUTF8(IDS_UPDATE_NOTIFICATION_RESTART_BUTTON),
@@ -426,6 +541,11 @@
       chrome_os_device_name);
 
   ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorWarning, *GetNotificationColor());
+  EXPECT_TRUE(strcmp(vector_icons::kBusinessIcon.name,
+                     GetNotificationIcon().name) == 0);
+  EXPECT_EQ(message_center::SYSTEM_PRIORITY, GetNotificationPriority());
+  EXPECT_EQ(true, GetNotificationNeverTimeout());
   EXPECT_EQ(expected_notification_title, GetNotificationTitle());
   EXPECT_EQ(expected_notification_body, GetNotificationMessage());
   EXPECT_EQ(l10n_util::GetStringUTF8(IDS_UPDATE_NOTIFICATION_RESTART_BUTTON),
@@ -452,6 +572,11 @@
       chrome_os_device_name);
 
   ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorWarning, *GetNotificationColor());
+  EXPECT_TRUE(strcmp(vector_icons::kBusinessIcon.name,
+                     GetNotificationIcon().name) == 0);
+  EXPECT_EQ(message_center::SYSTEM_PRIORITY, GetNotificationPriority());
+  EXPECT_EQ(true, GetNotificationNeverTimeout());
   EXPECT_EQ(expected_notification_title, GetNotificationTitle());
   EXPECT_EQ(expected_notification_body, GetNotificationMessage());
   EXPECT_EQ(l10n_util::GetStringUTF8(IDS_UPDATE_NOTIFICATION_RESTART_BUTTON),
@@ -474,6 +599,9 @@
   task_environment()->RunUntilIdle();
 
   ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorNormal, *GetNotificationColor());
+  EXPECT_TRUE(strcmp(kSystemMenuUpdateIcon.name, GetNotificationIcon().name) ==
+              0);
   EXPECT_EQ(l10n_util::GetStringUTF8(IDS_UPDATE_NOTIFICATION_TITLE),
             GetNotificationTitle());
   EXPECT_EQ(l10n_util::GetStringFUTF8(
@@ -486,10 +614,6 @@
 }
 
 TEST_F(UpdateNotificationControllerTest, VisibilityAfterLacrosUpdate) {
-  // The system starts with no update pending, so the notification isn't
-  // visible.
-  EXPECT_FALSE(HasNotification());
-
   // Simulate an update.
   AddNotificationWaiter waiter;
   Shell::Get()->system_tray_model()->ShowUpdateIcon(UpdateSeverity::kLow, false,
@@ -498,6 +622,9 @@
 
   // The notification is now visible.
   ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(kSystemNotificationColorNormal, *GetNotificationColor());
+  EXPECT_TRUE(strcmp(kSystemMenuUpdateIcon.name, GetNotificationIcon().name) ==
+              0);
   EXPECT_EQ("Lacros update available", GetNotificationTitle());
   EXPECT_EQ("Device restart is required to apply the update.",
             GetNotificationMessage());
diff --git a/ash/webui/common/resources/keyboard_diagram.html b/ash/webui/common/resources/keyboard_diagram.html
index 1357f9b..638b895 100644
--- a/ash/webui/common/resources/keyboard_diagram.html
+++ b/ash/webui/common/resources/keyboard_diagram.html
@@ -26,14 +26,6 @@
     grid-column: span 2;
   }
 
-  .left {
-    --keyboard-key-glyph-alignment: left;
-  }
-
-  .right {
-    --keyboard-key-glyph-alignment: right;
-  }
-
   #topRow {
     column-gap: var(--grid-gap);
     display: flex;
@@ -71,7 +63,7 @@
     grid-column: span 3;
   }
 
-  #searchKey,
+  #launcherKey,
   #rightShiftKey,
   #leftAltKey {
     grid-column: span 4;
@@ -279,7 +271,7 @@
     <keyboard-key main-glyph="]"></keyboard-key>
     <keyboard-key id="backslashKey" main-glyph="\\"></keyboard-key>
 
-    <keyboard-key id="searchKey" class="left" main-glyph="search"></keyboard-key>
+    <keyboard-key id="launcherKey" class="left" icon="keyboard:launcher"></keyboard-key>
     <keyboard-key main-glyph="a"></keyboard-key>
     <keyboard-key main-glyph="s"></keyboard-key>
     <keyboard-key main-glyph="d"></keyboard-key>
diff --git a/ash/webui/common/resources/keyboard_icons.html b/ash/webui/common/resources/keyboard_icons.html
index 2413e13..02b46ca 100644
--- a/ash/webui/common/resources/keyboard_icons.html
+++ b/ash/webui/common/resources/keyboard_icons.html
@@ -29,6 +29,10 @@
         <path d="M10 10L16 14V6L10 10Z"></path>
         <path d="M10 10V14L4 10L10 6V10Z"></path>
       </g>
+      <g id="launcher" viewbox="0 0 20 20">
+        <path d="M10 15C12.7614 15 15 12.7614 15 10C15 7.23858 12.7614 5 10 5C7.23858 5 5 7.23858 5 10C5 12.7614 7.23858 15 10 15Z"></path>
+        <path fill-rule="evenodd" d="M10 18.5C14.6944 18.5 18.5 14.6944 18.5 10C18.5 5.30558 14.6944 1.5 10 1.5C5.30558 1.5 1.5 5.30558 1.5 10C1.5 14.6944 5.30558 18.5 10 18.5ZM17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10Z"></path>
+      </g>
       <g id="next-track" viewbox="0 0 20 20">
         <!--
           This is actually the fast forward icon, to match the Chrome OS
diff --git a/ash/webui/common/resources/keyboard_key.html b/ash/webui/common/resources/keyboard_key.html
index 8fbad97..5396b7e6 100644
--- a/ash/webui/common/resources/keyboard_key.html
+++ b/ash/webui/common/resources/keyboard_key.html
@@ -8,7 +8,6 @@
         var(--keyboard-key-top-radii, 3px)
         var(--keyboard-key-bottom-right-radius, 3px)
         3px;
-    --glyph-alignment: var(--keyboard-key-glyph-alignment, center);
     --travel: var(--keyboard-key-travel, 3px);
     --foreground-color-unpressed: hsl(214deg 82% 51%);
     --foreground-color-pressed: hsl(213deg 23% 91%);
@@ -28,7 +27,7 @@
     color: var(--foreground-color-unpressed);
     display: flex;
     font-family: sans-serif;
-    justify-content: var(--glyph-alignment);
+    justify-content: center;
     left: 0;
     position: absolute;
     right: 0;
@@ -36,12 +35,26 @@
     transition: all 150ms ease-in-out;
   }
 
+  :host(.left) #foreground {
+    justify-content: left;
+  }
+
+  :host(.right) #foreground {
+    justify-content: right;
+  }
+
   iron-icon {
     --iron-icon-fill-color: var(--foreground-color-unpressed);
     --iron-icon-height: 100%;
     --iron-icon-width: 100%;
   }
 
+  :host(.left) iron-icon,
+  :host(.right) iron-icon {
+    --iron-icon-width: 24px;
+    padding: 0 5px;
+  }
+
   #text {
     overflow: hidden;
     text-overflow: ellipsis;
diff --git a/ash/webui/firmware_update_ui/BUILD.gn b/ash/webui/firmware_update_ui/BUILD.gn
index 4599bf8..af503aa0 100644
--- a/ash/webui/firmware_update_ui/BUILD.gn
+++ b/ash/webui/firmware_update_ui/BUILD.gn
@@ -15,6 +15,7 @@
   ]
 
   deps = [
+    "//ash/webui/firmware_update_ui/mojom",
     "//ash/webui/resources:firmware_update_app_resources",
     "//chromeos/strings/",
     "//content/public/browser",
diff --git a/ash/webui/firmware_update_ui/mojom/BUILD.gn b/ash/webui/firmware_update_ui/mojom/BUILD.gn
new file mode 100644
index 0000000..46862d7
--- /dev/null
+++ b/ash/webui/firmware_update_ui/mojom/BUILD.gn
@@ -0,0 +1,13 @@
+# 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("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom") {
+  disable_variants = true
+
+  sources = [ "firmware_update.mojom" ]
+
+  public_deps = [ "//mojo/public/mojom/base" ]
+}
diff --git a/ash/webui/firmware_update_ui/mojom/OWNERS b/ash/webui/firmware_update_ui/mojom/OWNERS
new file mode 100644
index 0000000..426c863
--- /dev/null
+++ b/ash/webui/firmware_update_ui/mojom/OWNERS
@@ -0,0 +1,5 @@
+jimmyxgong@chromium.org
+zentaro@chromium.org
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/ash/webui/firmware_update_ui/mojom/firmware_update.mojom b/ash/webui/firmware_update_ui/mojom/firmware_update.mojom
new file mode 100644
index 0000000..7a51f216
--- /dev/null
+++ b/ash/webui/firmware_update_ui/mojom/firmware_update.mojom
@@ -0,0 +1,35 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module ash.firmware_update.mojom;
+
+import "mojo/public/mojom/base/string16.mojom";
+
+// Represents the priority of an firmware update e.g. a security update may be
+// considered a critical priority.
+enum UpdatePriority {
+  kLow,
+  kMedium,
+  kHigh,
+  kCritical,
+};
+
+// Contains metadata in regards to a specific device's firmware update. Includes
+// the device to be updated and metadata of the firmware state.
+struct FirmwareUpdate {
+  // Unique identifier of the device.
+  string device_id;
+
+  // Device name, may be in an internationalized language.
+  mojo_base.mojom.String16 device_name;
+
+  // Device firmware version.
+  string device_version;
+
+  // Description text associated with the device.
+  mojo_base.mojom.String16 device_description;
+
+  // Priority of the device's firmware update.
+  UpdatePriority priority;
+};
diff --git a/ash/webui/media_app_ui/media_app_page_handler.cc b/ash/webui/media_app_ui/media_app_page_handler.cc
index f37e96ba..2b88e9fc 100644
--- a/ash/webui/media_app_ui/media_app_page_handler.cc
+++ b/ash/webui/media_app_ui/media_app_page_handler.cc
@@ -24,4 +24,10 @@
   std::move(callback).Run(std::move(error_message));
 }
 
+void MediaAppPageHandler::ToggleBrowserFullscreenMode(
+    ToggleBrowserFullscreenModeCallback callback) {
+  media_app_ui_->delegate()->ToggleBrowserFullscreenMode();
+  std::move(callback).Run();
+}
+
 }  // namespace ash
diff --git a/ash/webui/media_app_ui/media_app_page_handler.h b/ash/webui/media_app_ui/media_app_page_handler.h
index b9a24b2..c34c014 100644
--- a/ash/webui/media_app_ui/media_app_page_handler.h
+++ b/ash/webui/media_app_ui/media_app_page_handler.h
@@ -29,6 +29,8 @@
 
   // media_app_ui::mojom::PageHandler:
   void OpenFeedbackDialog(OpenFeedbackDialogCallback callback) override;
+  void ToggleBrowserFullscreenMode(
+      ToggleBrowserFullscreenModeCallback callback) override;
 
  private:
   mojo::Receiver<media_app_ui::mojom::PageHandler> receiver_;
diff --git a/ash/webui/media_app_ui/media_app_ui.mojom b/ash/webui/media_app_ui/media_app_ui.mojom
index 186be028..f06e201 100644
--- a/ash/webui/media_app_ui/media_app_ui.mojom
+++ b/ash/webui/media_app_ui/media_app_ui.mojom
@@ -16,4 +16,6 @@
 interface PageHandler {
   // Opens the chrome feedback dialog.
   OpenFeedbackDialog() => (string? error_message);
+  // Toggles "browser" fullscreen mode for the window.
+  ToggleBrowserFullscreenMode() => ();
 };
diff --git a/ash/webui/media_app_ui/media_app_ui_delegate.h b/ash/webui/media_app_ui/media_app_ui_delegate.h
index 0e7f48c7..6bd7637 100644
--- a/ash/webui/media_app_ui/media_app_ui_delegate.h
+++ b/ash/webui/media_app_ui/media_app_ui_delegate.h
@@ -21,6 +21,9 @@
   // Returns an optional error message if unable to open the dialog or nothing
   // if the dialog was determined to have opened successfully.
   virtual absl::optional<std::string> OpenFeedbackDialog() = 0;
+
+  // Toggles fullscreen mode on the Browser* hosting this MediaApp instance.
+  virtual void ToggleBrowserFullscreenMode() = 0;
 };
 
 }  // namespace ash
diff --git a/ash/webui/media_app_ui/resources/js/launch.js b/ash/webui/media_app_ui/resources/js/launch.js
index c8c72e2..c7a98ece 100644
--- a/ash/webui/media_app_ui/resources/js/launch.js
+++ b/ash/webui/media_app_ui/resources/js/launch.js
@@ -179,6 +179,10 @@
   return response;
 });
 
+guestMessagePipe.registerHandler(Message.TOGGLE_BROWSER_FULLSCREEN_MODE, () => {
+  mediaAppPageHandler.toggleBrowserFullscreenMode();
+});
+
 guestMessagePipe.registerHandler(Message.OVERWRITE_FILE, async (message) => {
   const overwrite = /** @type {!OverwriteFileMessage} */ (message);
   const originalHandle = fileHandleForToken(overwrite.token);
diff --git a/ash/webui/media_app_ui/resources/js/media_app.externs.js b/ash/webui/media_app_ui/resources/js/media_app.externs.js
index a0864592..1bc725f0 100644
--- a/ash/webui/media_app_ui/resources/js/media_app.externs.js
+++ b/ash/webui/media_app_ui/resources/js/media_app.externs.js
@@ -183,6 +183,12 @@
  */
 mediaApp.ClientApiDelegate.prototype.openFeedbackDialog = function() {};
 /**
+ * Toggles browser fullscreen mode.
+ * @type {undefined|function():!Promise<undefined>}
+ */
+mediaApp.ClientApiDelegate.prototype.toggleBrowserFullscreenMode =
+    function() {};
+/**
  * Request for the user to be prompted with a save file dialog. Once the user
  * selects a location a new file handle is created and a new AbstractFile
  * representing that file will be returned. This can be then used in a save as
diff --git a/ash/webui/media_app_ui/resources/js/message_types.js b/ash/webui/media_app_ui/resources/js/message_types.js
index 5b02e28..735d891 100644
--- a/ash/webui/media_app_ui/resources/js/message_types.js
+++ b/ash/webui/media_app_ui/resources/js/message_types.js
@@ -26,6 +26,7 @@
   REQUEST_SAVE_FILE: 'request-save-file',
   SAVE_AS: 'save-as',
   OPEN_ALLOWED_FILE: 'open-allowed-file',
+  TOGGLE_BROWSER_FULLSCREEN_MODE: 'toggle-browser-fullscreen-mode',
 };
 
 /**
diff --git a/ash/webui/media_app_ui/resources/js/receiver.js b/ash/webui/media_app_ui/resources/js/receiver.js
index f7399b4..b0a6349 100644
--- a/ash/webui/media_app_ui/resources/js/receiver.js
+++ b/ash/webui/media_app_ui/resources/js/receiver.js
@@ -282,6 +282,9 @@
         await parentMessagePipe.sendMessage(Message.OPEN_FEEDBACK_DIALOG);
     return /** @type {?string} */ (response['errorMessage']);
   },
+  async toggleBrowserFullscreenMode() {
+    await parentMessagePipe.sendMessage(Message.TOGGLE_BROWSER_FULLSCREEN_MODE);
+  },
   /**
    * @param {string} suggestedName
    * @param {string} mimeType
diff --git a/ash/webui/personalization_app/resources/BUILD.gn b/ash/webui/personalization_app/resources/BUILD.gn
index 1a5a8fad..1fc80e1 100644
--- a/ash/webui/personalization_app/resources/BUILD.gn
+++ b/ash/webui/personalization_app/resources/BUILD.gn
@@ -20,7 +20,7 @@
 
   "trusted/iframe_api.ts",
   "trusted/mojo_interface_provider.ts",
-  "trusted/personalization_actions.js",
+  "trusted/personalization_actions.ts",
   "trusted/personalization_app.js",
   "trusted/personalization_controller.js",
   "trusted/personalization_message_handler.js",
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_actions.js b/ash/webui/personalization_app/resources/trusted/personalization_actions.js
deleted file mode 100644
index 6af0cf23..0000000
--- a/ash/webui/personalization_app/resources/trusted/personalization_actions.js
+++ /dev/null
@@ -1,285 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {assert} from 'chrome://resources/js/assert.m.js';
-import {Action} from 'chrome://resources/js/cr/ui/store.js';
-import {DisplayableImage} from './personalization_reducers.js';
-
-/**
- * @fileoverview Defines the actions to change state.
- */
-
-/** @enum {string} */
-export const ActionName = {
-  BEGIN_LOAD_GOOGLE_PHOTOS_ALBUM: 'begin_load_google_photos_album',
-  BEGIN_LOAD_GOOGLE_PHOTOS_ALBUMS: 'begin_load_google_photos_albums',
-  BEGIN_LOAD_GOOGLE_PHOTOS_COUNT: 'begin_load_google_photos_count',
-  BEGIN_LOAD_GOOGLE_PHOTOS_PHOTOS: 'begin_load_google_photos_photos',
-  BEGIN_LOAD_IMAGES_FOR_COLLECTIONS: 'begin_load_images_for_collections',
-  BEGIN_LOAD_LOCAL_IMAGES: 'begin_load_local_images',
-  BEGIN_LOAD_LOCAL_IMAGE_DATA: 'begin_load_local_image_data',
-  BEGIN_LOAD_SELECTED_IMAGE: 'begin_load_selected_image',
-  BEGIN_SELECT_IMAGE: 'begin_select_image',
-  BEGIN_UPDATE_DAILY_REFRESH_IMAGE: 'begin_update_daily_refresh_image',
-  END_SELECT_IMAGE: 'end_select_image',
-  SET_COLLECTIONS: 'set_collections',
-  SET_DAILY_REFRESH_COLLECTION_ID: 'set_daily_refresh_collection_id',
-  SET_GOOGLE_PHOTOS_ALBUM: 'set_google_photos_album',
-  SET_GOOGLE_PHOTOS_ALBUMS: 'set_google_photos_albums',
-  SET_GOOGLE_PHOTOS_COUNT: 'set_google_photos_count',
-  SET_GOOGLE_PHOTOS_PHOTOS: 'set_google_photos_photos',
-  SET_IMAGES_FOR_COLLECTION: 'set_images_for_collection',
-  SET_LOCAL_IMAGES: 'set_local_images',
-  SET_LOCAL_IMAGE_DATA: 'set_local_image_data',
-  SET_SELECTED_IMAGE: 'set_selected_image',
-  SET_UPDATED_DAILY_REFRESH_IMAGE: 'set_updated_daily_refreshed_image',
-  DISMISS_ERROR: 'dismiss_error',
-  SET_FULLSCREEN_ENABLED: 'set_fullscreen_enabled',
-};
-
-/**
- * Notify that the app is loading the list of Google Photos photos for the album
- * associated with the specified id.
- * @param {string} albumId
- * @return {!Action}
- */
-export function beginLoadGooglePhotosAlbumAction(albumId) {
-  return {albumId, name: ActionName.BEGIN_LOAD_GOOGLE_PHOTOS_ALBUM};
-}
-
-/**
- * Notify that the app is loading the list of Google Photos albums.
- * @return {!Action}
- */
-export function beginLoadGooglePhotosAlbumsAction() {
-  return {name: ActionName.BEGIN_LOAD_GOOGLE_PHOTOS_ALBUMS};
-}
-
-/**
- * Notify that the app is loading the count of Google Photos photos.
- * @return {!Action}
- */
-export function beginLoadGooglePhotosCountAction() {
-  return {name: ActionName.BEGIN_LOAD_GOOGLE_PHOTOS_COUNT};
-}
-
-/**
- * Notify that the app is loading the list of Google Photos photos.
- * @return {!Action}
- */
-export function beginLoadGooglePhotosPhotosAction() {
-  return {name: ActionName.BEGIN_LOAD_GOOGLE_PHOTOS_PHOTOS};
-}
-
-/**
- * Notify that app is loading image list for the given collection.
- * @param {?Array<!WallpaperCollection>} collections
- * @return {!Action}
- */
-export function beginLoadImagesForCollectionsAction(collections) {
-  return {
-    collections,
-    name: ActionName.BEGIN_LOAD_IMAGES_FOR_COLLECTIONS,
-  };
-}
-
-/**
- * Notify that app is loading local image list.
- * @return {!Action}
- */
-export function beginLoadLocalImagesAction() {
-  return {name: ActionName.BEGIN_LOAD_LOCAL_IMAGES};
-}
-
-/**
- * Notify that app is loading thumbnail for the given local image.
- * @param {!mojoBase.mojom.FilePath} image
- * @return {!Action}
- */
-export function beginLoadLocalImageDataAction(image) {
-  return {
-    id: image.path,
-    name: ActionName.BEGIN_LOAD_LOCAL_IMAGE_DATA,
-  };
-}
-
-/**
- * Notify that a user has clicked on the refresh button.
- * @return {!Action}
- */
-export function beginUpdateDailyRefreshImageAction() {
-  return {
-    name: ActionName.BEGIN_UPDATE_DAILY_REFRESH_IMAGE,
-  };
-}
-
-/**
- * Notify that app is loading currently selected image information.
- * @return {!Action}
- */
-export function beginLoadSelectedImageAction() {
-  return {name: ActionName.BEGIN_LOAD_SELECTED_IMAGE};
-}
-
-/**
- * Notify that a user has clicked on an image to set as wallpaper.
- * @param {!DisplayableImage} image
- * @return {!Action}
- */
-export function beginSelectImageAction(image) {
-  return {name: ActionName.BEGIN_SELECT_IMAGE, image};
-}
-
-/**
- * Notify that the user-initiated action to set image has finished.
- * @param {!DisplayableImage} image
- * @param {boolean} success
- * @return {!Action}
- */
-export function endSelectImageAction(image, success) {
-  return {name: ActionName.END_SELECT_IMAGE, image, success};
-}
-
-/**
- * Set the collections. May be called with null if an error occurred.
- * @param {?Array<!WallpaperCollection>} collections
- * @return {!Action}
- */
-export function setCollectionsAction(collections) {
-  return {
-    collections,
-    name: ActionName.SET_COLLECTIONS,
-  };
-}
-
-/**
- * Set and enable daily refresh for given collectionId.
- * @param {?string} collectionId
- * @return {!Action}
- */
-export function setDailyRefreshCollectionIdAction(collectionId) {
-  return {
-    collectionId,
-    name: ActionName.SET_DAILY_REFRESH_COLLECTION_ID,
-  };
-}
-
-/**
- * Sets the list of Google Photos photos for the album associated with the
- * specified id. May be called with null on error.
- * @param {string} albumId
- * @param {?Array<undefined>} photos
- * @return {!Action}
- */
-export function setGooglePhotosAlbumAction(albumId, photos) {
-  return {albumId, photos, name: ActionName.SET_GOOGLE_PHOTOS_ALBUM};
-}
-
-/**
- * Sets the list of Google Photos albums. May be called with null on error.
- * @param {?Array<WallpaperCollection>} albums
- * @return {!Action}
- */
-export function setGooglePhotosAlbumsAction(albums) {
-  return {albums, name: ActionName.SET_GOOGLE_PHOTOS_ALBUMS};
-}
-
-/**
- * Sets the count of Google Photos photos. May be called with null on error.
- * @param {?number} count
- * @return {!Action}
- */
-export function setGooglePhotosCountAction(count) {
-  return {count, name: ActionName.SET_GOOGLE_PHOTOS_COUNT};
-}
-
-/**
- * Sets the list of Google Photos photos. May be called with null on error.
- * @param {?Array<undefined>} photos
- * @return {!Action}
- */
-export function setGooglePhotosPhotosAction(photos) {
-  return {photos, name: ActionName.SET_GOOGLE_PHOTOS_PHOTOS};
-}
-
-/**
- * Set the images for a given collection. May be called with null if an error
- * occurred.
- * @param {string} collectionId
- * @param {?Array<!WallpaperImage>} images
- * @returns
- */
-export function setImagesForCollectionAction(collectionId, images) {
-  return {
-    collectionId,
-    images,
-    name: ActionName.SET_IMAGES_FOR_COLLECTION,
-  };
-}
-
-/**
- * Set the thumbnail data for a local image.
- * @param {!mojoBase.mojom.FilePath} filePath
- * @param {string} data
- * @return {!Action}
- */
-export function setLocalImageDataAction(filePath, data) {
-  return {
-    id: filePath.path,
-    data,
-    name: ActionName.SET_LOCAL_IMAGE_DATA,
-  };
-}
-
-/**
- * Set the list of local images.
- * @param {?Array<!mojoBase.mojom.FilePath>} images
- * @return {!Action}
- */
-export function setLocalImagesAction(images) {
-  return {
-    images,
-    name: ActionName.SET_LOCAL_IMAGES,
-  };
-}
-
-/**
- * Notify that a image has been refreshed.
- * @return {!Action}
- */
-export function setUpdatedDailyRefreshImageAction() {
-  return {
-    name: ActionName.SET_UPDATED_DAILY_REFRESH_IMAGE,
-  };
-}
-
-/**
- * Returns an action to set the current image as currently selected across the
- * app. Can be called with null to represent no image currently selected or that
- * an error occurred.
- * @param {?CurrentWallpaper} image
- * @return {!Action}
- */
-export function setSelectedImageAction(image) {
-  return {
-    image,
-    name: ActionName.SET_SELECTED_IMAGE,
-  };
-}
-
-/**
- * @return {!Action}
- */
-export function dismissErrorAction() {
-  return {name: ActionName.DISMISS_ERROR};
-}
-
-/**
- * @param {boolean} enabled
- * @return {!Action}
- */
-export function setFullscreenEnabledAction(enabled) {
-  assert(typeof enabled === 'boolean');
-  return {name: ActionName.SET_FULLSCREEN_ENABLED, enabled};
-}
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_actions.ts b/ash/webui/personalization_app/resources/trusted/personalization_actions.ts
new file mode 100644
index 0000000..97844dc
--- /dev/null
+++ b/ash/webui/personalization_app/resources/trusted/personalization_actions.ts
@@ -0,0 +1,379 @@
+// 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 {assert} from 'chrome://resources/js/assert.m.js';
+import {Action} from 'chrome://resources/js/cr/ui/store.js';
+import {FilePath} from 'chrome://resources/mojo/mojo/public/mojom/base/file_path.mojom-webui.js';
+
+import {CurrentWallpaper, WallpaperCollection, WallpaperImage} from './personalization_app.mojom-webui.js';
+import {DisplayableImage} from './personalization_reducers.js';
+
+/**
+ * @fileoverview Defines the actions to change state.
+ */
+
+export enum ActionName {
+  BEGIN_LOAD_GOOGLE_PHOTOS_ALBUM = 'begin_load_google_photos_album',
+  BEGIN_LOAD_GOOGLE_PHOTOS_ALBUMS = 'begin_load_google_photos_albums',
+  BEGIN_LOAD_GOOGLE_PHOTOS_COUNT = 'begin_load_google_photos_count',
+  BEGIN_LOAD_GOOGLE_PHOTOS_PHOTOS = 'begin_load_google_photos_photos',
+  BEGIN_LOAD_IMAGES_FOR_COLLECTIONS = 'begin_load_images_for_collections',
+  BEGIN_LOAD_LOCAL_IMAGES = 'begin_load_local_images',
+  BEGIN_LOAD_LOCAL_IMAGE_DATA = 'begin_load_local_image_data',
+  BEGIN_LOAD_SELECTED_IMAGE = 'begin_load_selected_image',
+  BEGIN_SELECT_IMAGE = 'begin_select_image',
+  BEGIN_UPDATE_DAILY_REFRESH_IMAGE = 'begin_update_daily_refresh_image',
+  END_SELECT_IMAGE = 'end_select_image',
+  SET_COLLECTIONS = 'set_collections',
+  SET_DAILY_REFRESH_COLLECTION_ID = 'set_daily_refresh_collection_id',
+  SET_GOOGLE_PHOTOS_ALBUM = 'set_google_photos_album',
+  SET_GOOGLE_PHOTOS_ALBUMS = 'set_google_photos_albums',
+  SET_GOOGLE_PHOTOS_COUNT = 'set_google_photos_count',
+  SET_GOOGLE_PHOTOS_PHOTOS = 'set_google_photos_photos',
+  SET_IMAGES_FOR_COLLECTION = 'set_images_for_collection',
+  SET_LOCAL_IMAGES = 'set_local_images',
+  SET_LOCAL_IMAGE_DATA = 'set_local_image_data',
+  SET_SELECTED_IMAGE = 'set_selected_image',
+  SET_UPDATED_DAILY_REFRESH_IMAGE = 'set_updated_daily_refreshed_image',
+  DISMISS_ERROR = 'dismiss_error',
+  SET_FULLSCREEN_ENABLED = 'set_fullscreen_enabled',
+}
+
+export type BeginLoadGooglePhotosAlbumAction = Action&{
+  name: ActionName.BEGIN_LOAD_GOOGLE_PHOTOS_ALBUM;
+  albumId: string;
+};
+
+/**
+ * Notify that the app is loading the list of Google Photos photos for the album
+ * associated with the specified id.
+ */
+export function beginLoadGooglePhotosAlbumAction(albumId: string):
+    BeginLoadGooglePhotosAlbumAction {
+  return {albumId, name: ActionName.BEGIN_LOAD_GOOGLE_PHOTOS_ALBUM};
+}
+
+export type BeginLoadGooglePhotosAlbumsAction = Action&{
+  name: ActionName.BEGIN_LOAD_GOOGLE_PHOTOS_ALBUMS;
+};
+/**
+ * Notify that the app is loading the list of Google Photos albums.
+ */
+export function beginLoadGooglePhotosAlbumsAction():
+    BeginLoadGooglePhotosAlbumsAction {
+  return {name: ActionName.BEGIN_LOAD_GOOGLE_PHOTOS_ALBUMS};
+}
+
+export type BeginLoadGooglePhotsCountAction = Action&{
+  name: ActionName.BEGIN_LOAD_GOOGLE_PHOTOS_COUNT;
+};
+
+/**
+ * Notify that the app is loading the count of Google Photos photos.
+ */
+export function beginLoadGooglePhotosCountAction():
+    BeginLoadGooglePhotsCountAction {
+  return {name: ActionName.BEGIN_LOAD_GOOGLE_PHOTOS_COUNT};
+}
+
+export type BeginLoadGooglePhotosPhotosAction = Action&{
+  name: ActionName.BEGIN_LOAD_GOOGLE_PHOTOS_PHOTOS;
+};
+/**
+ * Notify that the app is loading the list of Google Photos photos.
+ */
+export function beginLoadGooglePhotosPhotosAction():
+    BeginLoadGooglePhotosPhotosAction {
+  return {name: ActionName.BEGIN_LOAD_GOOGLE_PHOTOS_PHOTOS};
+}
+
+export type BeginLoadImagesForCollectionsAction = Action&{
+  name: ActionName.BEGIN_LOAD_IMAGES_FOR_COLLECTIONS;
+  collections: WallpaperCollection[];
+};
+
+/**
+ * Notify that app is loading image list for the given collection.
+ */
+export function beginLoadImagesForCollectionsAction(
+    collections: WallpaperCollection[]): BeginLoadImagesForCollectionsAction {
+  return {
+    collections,
+    name: ActionName.BEGIN_LOAD_IMAGES_FOR_COLLECTIONS,
+  };
+}
+
+export type BeginLoadLocalImagesAction = Action&{
+  name: ActionName.BEGIN_LOAD_LOCAL_IMAGES;
+};
+/**
+ * Notify that app is loading local image list.
+ */
+export function beginLoadLocalImagesAction(): BeginLoadLocalImagesAction {
+  return {name: ActionName.BEGIN_LOAD_LOCAL_IMAGES};
+}
+
+export type BeginLoadLocalImageDataAction = Action&{
+  name: ActionName.BEGIN_LOAD_LOCAL_IMAGE_DATA;
+  id: string;
+};
+
+/**
+ * Notify that app is loading thumbnail for the given local image.
+ */
+export function beginLoadLocalImageDataAction(image: FilePath):
+    BeginLoadLocalImageDataAction {
+  return {
+    id: image.path,
+    name: ActionName.BEGIN_LOAD_LOCAL_IMAGE_DATA,
+  };
+}
+
+export type BeginUpdateDailyRefreshImageAction = Action&{
+  name: ActionName.BEGIN_UPDATE_DAILY_REFRESH_IMAGE;
+};
+
+/**
+ * Notify that a user has clicked on the refresh button.
+ */
+export function beginUpdateDailyRefreshImageAction():
+    BeginUpdateDailyRefreshImageAction {
+  return {
+    name: ActionName.BEGIN_UPDATE_DAILY_REFRESH_IMAGE,
+  };
+}
+
+export type BeginLoadSelectedImageAction = Action&{
+  name: ActionName.BEGIN_LOAD_SELECTED_IMAGE;
+};
+
+/**
+ * Notify that app is loading currently selected image information.
+ */
+export function beginLoadSelectedImageAction(): BeginLoadSelectedImageAction {
+  return {name: ActionName.BEGIN_LOAD_SELECTED_IMAGE};
+}
+
+export type BeginSelectImageAction = Action&{
+  name: ActionName.BEGIN_SELECT_IMAGE;
+  image: DisplayableImage;
+};
+
+/**
+ * Notify that a user has clicked on an image to set as wallpaper.
+ */
+export function beginSelectImageAction(image: DisplayableImage):
+    BeginSelectImageAction {
+  return {name: ActionName.BEGIN_SELECT_IMAGE, image};
+}
+
+export type EndSelectImageAction = Action&{
+  name: ActionName.END_SELECT_IMAGE;
+  image: DisplayableImage;
+  success: boolean;
+};
+
+/**
+ * Notify that the user-initiated action to set image has finished.
+ */
+export function endSelectImageAction(
+    image: DisplayableImage, success: boolean): EndSelectImageAction {
+  return {name: ActionName.END_SELECT_IMAGE, image, success};
+}
+
+export type SetCollectionsAction = Action&{
+  name: ActionName.SET_COLLECTIONS;
+  collections: WallpaperCollection[];
+};
+
+/**
+ * Set the collections. May be called with null if an error occurred.
+ */
+export function setCollectionsAction(collections: WallpaperCollection[]):
+    SetCollectionsAction {
+  return {
+    name: ActionName.SET_COLLECTIONS,
+    collections,
+  };
+}
+
+export type SetDailyRefreshCollectionIdAction = Action&{
+  name: ActionName.SET_DAILY_REFRESH_COLLECTION_ID;
+  collectionId: string|null;
+};
+
+/**
+ * Set and enable daily refresh for given collectionId.
+ */
+export function setDailyRefreshCollectionIdAction(collectionId: string|null):
+    SetDailyRefreshCollectionIdAction {
+  return {
+    collectionId,
+    name: ActionName.SET_DAILY_REFRESH_COLLECTION_ID,
+  };
+}
+
+export type SetGooglePhotosAlbumAction = Action&{
+  name: ActionName.SET_GOOGLE_PHOTOS_ALBUM;
+  albumId: string;
+  photos: unknown[];
+};
+
+/**
+ * Sets the list of Google Photos photos for the album associated with the
+ * specified id. May be called with null on error.
+ */
+export function setGooglePhotosAlbumAction(
+    albumId: string, photos: unknown[]): SetGooglePhotosAlbumAction {
+  return {albumId, photos, name: ActionName.SET_GOOGLE_PHOTOS_ALBUM};
+}
+
+export type SetGooglePhotosAlbumsAction = Action&{
+  name: ActionName.SET_GOOGLE_PHOTOS_ALBUMS;
+  albums: WallpaperCollection[]|null;
+};
+
+/**
+ * Sets the list of Google Photos albums. May be called with null on error.
+ */
+export function setGooglePhotosAlbumsAction(albums: WallpaperCollection[]|
+                                            null): SetGooglePhotosAlbumsAction {
+  return {albums, name: ActionName.SET_GOOGLE_PHOTOS_ALBUMS};
+}
+
+export type SetGooglePhotosCountAction = Action&{
+  name: ActionName.SET_GOOGLE_PHOTOS_COUNT;
+  count: number;
+};
+
+/**
+ * Sets the count of Google Photos photos. May be called with null on error.
+ */
+export function setGooglePhotosCountAction(count: number):
+    SetGooglePhotosCountAction {
+  return {count, name: ActionName.SET_GOOGLE_PHOTOS_COUNT};
+}
+
+export type SetGooglePhotosPhotosAction = Action&{
+  name: ActionName.SET_GOOGLE_PHOTOS_PHOTOS;
+  photos: unknown[]|null;
+};
+
+/**
+ * Sets the list of Google Photos photos. May be called with null on error.
+ */
+export function setGooglePhotosPhotosAction(photos: unknown[]|
+                                            null): SetGooglePhotosPhotosAction {
+  return {photos, name: ActionName.SET_GOOGLE_PHOTOS_PHOTOS};
+}
+
+export type SetImagesForCollectionAction = Action&{
+  name: ActionName.SET_IMAGES_FOR_COLLECTION;
+  collectionId: string;
+  images: WallpaperImage[];
+};
+
+/**
+ * Set the images for a given collection. May be called with null if an error
+ * occurred.
+ */
+export function setImagesForCollectionAction(
+    collectionId: string,
+    images: WallpaperImage[]): SetImagesForCollectionAction {
+  return {
+    collectionId,
+    images,
+    name: ActionName.SET_IMAGES_FOR_COLLECTION,
+  };
+}
+
+export type SetLocalImageDataAction = Action&{
+  name: ActionName.SET_LOCAL_IMAGE_DATA;
+  id: string;
+  data: string;
+};
+
+/**
+ * Set the thumbnail data for a local image.
+ */
+export function setLocalImageDataAction(
+    filePath: FilePath, data: string): SetLocalImageDataAction {
+  return {
+    id: filePath.path,
+    data,
+    name: ActionName.SET_LOCAL_IMAGE_DATA,
+  };
+}
+
+export type SetLocalImagesAction = Action&{
+  name: ActionName.SET_LOCAL_IMAGES;
+  images: FilePath[];
+};
+
+/**
+ * Set the list of local images.
+ */
+export function setLocalImagesAction(images: FilePath[]): SetLocalImagesAction {
+  return {
+    images,
+    name: ActionName.SET_LOCAL_IMAGES,
+  };
+}
+
+export type SetUpdatedDailyRefreshImageAction = Action&{
+  name: ActionName.SET_UPDATED_DAILY_REFRESH_IMAGE;
+};
+
+/**
+ * Notify that a image has been refreshed.
+ */
+export function setUpdatedDailyRefreshImageAction():
+    SetUpdatedDailyRefreshImageAction {
+  return {
+    name: ActionName.SET_UPDATED_DAILY_REFRESH_IMAGE,
+  };
+}
+
+export type SetSelectedImageAction = Action&{
+  name: ActionName.SET_SELECTED_IMAGE;
+  image: CurrentWallpaper|null;
+};
+
+/**
+ * Returns an action to set the current image as currently selected across the
+ * app. Can be called with null to represent no image currently selected or that
+ * an error occurred.
+ */
+export function setSelectedImageAction(image: CurrentWallpaper|
+                                       null): SetSelectedImageAction {
+  return {
+    image,
+    name: ActionName.SET_SELECTED_IMAGE,
+  };
+}
+
+export type DismissErrorAction = Action&{
+  name: ActionName.DISMISS_ERROR;
+};
+
+/**
+ * Dismiss the current error if there is any.
+ */
+export function dismissErrorAction(): DismissErrorAction {
+  return {name: ActionName.DISMISS_ERROR};
+}
+
+export type SetFullscreenEnabledAction = Action&{
+  name: ActionName.SET_FULLSCREEN_ENABLED;
+  enabled: boolean;
+};
+
+/**
+ * Enable/disable the fullscreen preview mode for wallpaper.
+ */
+export function setFullscreenEnabledAction(enabled: boolean):
+    SetFullscreenEnabledAction {
+  assert(typeof enabled === 'boolean');
+  return {name: ActionName.SET_FULLSCREEN_ENABLED, enabled};
+}
diff --git a/ash/webui/print_management/resources/print_job_entry.html b/ash/webui/print_management/resources/print_job_entry.html
index 8ad8235..9eb05a50 100644
--- a/ash/webui/print_management/resources/print_job_entry.html
+++ b/ash/webui/print_management/resources/print_job_entry.html
@@ -6,7 +6,7 @@
 
   .collapsed-status {
     @apply --print-management-header-font;
-    color: var(--google-blue-600);
+    color: var(--cros-color-prominent);
   }
 
   /* Override focus CSS for selectable items. */
@@ -16,7 +16,7 @@
   }
 
   .list-item:focus-within {
-    background-color: var(--google-blue-50);
+    background-color: var(--cros-highlight-color);
     outline: none;
   }
 
@@ -27,7 +27,7 @@
   }
 
   #cancelPrintJobButton {
-    --iron-icon-fill-color: rgb(95,99,104);
+    --iron-icon-fill-color: var(--cros-icon-color-secondary);
     margin-inline-start: 4px;
     padding-bottom: 2px;
   }
@@ -38,17 +38,17 @@
   }
 
   #numericalProgress {
-    color: var(--google-blue-600);
+    color: var(--cros-color-prominent);
     margin-inline-end: 16px;
   }
 
   #rowWrapper:active {
-    background-color: var(--google-blue-50);
+    background-color: var(--cros-highlight-color);
     outline: none;
   }
 
   paper-progress {
-    --paper-progress-active-color: var(--google-blue-600);
+    --paper-progress-active-color: var(--cros-slider-color-active);
     --paper-progress-container-color: rgba(var(--google-blue-600-rgb), .24);
     width: 72px;
   }
diff --git a/ash/webui/print_management/resources/print_management.html b/ash/webui/print_management/resources/print_management.html
index e37524e8..6a01237 100644
--- a/ash/webui/print_management/resources/print_management.html
+++ b/ash/webui/print_management/resources/print_management.html
@@ -11,11 +11,11 @@
   }
 
   .delete-enabled {
-    --iron-icon-fill-color: rgb(26,115,232);
+    --iron-icon-fill-color: var(--cros-icon-color-prominent);
   }
 
   .delete-disabled {
-    --iron-icon-fill-color: var(--google-grey-500);
+    --iron-icon-fill-color: var(--cros-icon-color-disabled);
   }
 
   .main-container {
@@ -37,15 +37,15 @@
   }
 
   #enterpriseIcon {
-    --iron-icon-fill-color: var(--google-grey-refresh-700);
-    --iron-icon-stroke-color: var(--google-grey-refresh-700);
+    --iron-icon-fill-color: var(--cros-icon-color-secondary);
+    --iron-icon-stroke-color: var(--cros-icon-color-secondary);
     --iron-icon-height: 13px;
     --iron-icon-width: 13px;
     margin-inline-start: 8px;
   }
 
   #headerContainer {
-    border-bottom: 1px solid rgba(0,0,0,0.14); /* 14% black */
+    border-bottom: 1px solid var(--cros-separator-color);
     display: flex;
     justify-content: space-between;
     padding-bottom: 20px;
@@ -53,8 +53,8 @@
   }
 
   #infoIcon {
-    --iron-icon-fill-color: var(--google-grey-700);
-    --iron-icon-stroke-color: var(--google-grey-700);
+    --iron-icon-fill-color: var(--cros-icon-color-secondary);
+    --iron-icon-stroke-color: var(--cros-icon-color-secondary);
     --iron-icon-height: 13px;
     --iron-icon-width: 13px;
     margin-inline-start: 8px;
@@ -68,7 +68,7 @@
   }
 
   #ongoingEmptyState {
-    color: var(--google-grey-600);
+    color: var(--cros-text-color-disabled);
     margin-inline-start: 12px;
     padding-bottom: 24px;
     padding-top: 24px;
diff --git a/ash/webui/shimless_rma/backend/BUILD.gn b/ash/webui/shimless_rma/backend/BUILD.gn
index adfb36a2..81e4e7b 100644
--- a/ash/webui/shimless_rma/backend/BUILD.gn
+++ b/ash/webui/shimless_rma/backend/BUILD.gn
@@ -8,6 +8,7 @@
 
 static_library("backend") {
   sources = [
+    "shimless_rma_delegate.h",
     "shimless_rma_service.cc",
     "shimless_rma_service.h",
     "version_updater.cc",
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_delegate.h b/ash/webui/shimless_rma/backend/shimless_rma_delegate.h
new file mode 100644
index 0000000..2d6dff8
--- /dev/null
+++ b/ash/webui/shimless_rma/backend/shimless_rma_delegate.h
@@ -0,0 +1,24 @@
+// 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_WEBUI_SHIMLESS_RMA_BACKEND_SHIMLESS_RMA_DELEGATE_H_
+#define ASH_WEBUI_SHIMLESS_RMA_BACKEND_SHIMLESS_RMA_DELEGATE_H_
+
+namespace ash {
+namespace shimless_rma {
+
+// A delegate which exposes browser functionality from //chrome to the Shimless
+// RMA UI.
+class ShimlessRmaDelegate {
+ public:
+  virtual ~ShimlessRmaDelegate() = default;
+
+  // Restarts the Chrome session.
+  virtual void RestartChrome() = 0;
+};
+
+}  // namespace shimless_rma
+}  // namespace ash
+
+#endif  // ASH_WEBUI_SHIMLESS_RMA_BACKEND_SHIMLESS_RMA_DELEGATE_H_
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service.cc b/ash/webui/shimless_rma/backend/shimless_rma_service.cc
index 453c510..f8ad969 100644
--- a/ash/webui/shimless_rma/backend/shimless_rma_service.cc
+++ b/ash/webui/shimless_rma/backend/shimless_rma_service.cc
@@ -4,7 +4,11 @@
 
 #include "ash/webui/shimless_rma/backend/shimless_rma_service.h"
 
+#include <memory>
+#include <utility>
+
 #include "ash/public/cpp/network_config_service.h"
+#include "ash/webui/shimless_rma/backend/shimless_rma_delegate.h"
 #include "ash/webui/shimless_rma/backend/version_updater.h"
 #include "ash/webui/shimless_rma/mojom/shimless_rma.mojom.h"
 #include "ash/webui/shimless_rma/mojom/shimless_rma_mojom_traits.h"
@@ -74,7 +78,9 @@
 
 }  // namespace
 
-ShimlessRmaService::ShimlessRmaService() {
+ShimlessRmaService::ShimlessRmaService(
+    std::unique_ptr<ShimlessRmaDelegate> shimless_rma_delegate)
+    : shimless_rma_delegate_(std::move(shimless_rma_delegate)) {
   chromeos::RmadClient::Get()->AddObserver(this);
   GetNetworkConfigService(
       remote_cros_network_config_.BindNewPipeAndPassReceiver());
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service.h b/ash/webui/shimless_rma/backend/shimless_rma_service.h
index 077fd370..0635526 100644
--- a/ash/webui/shimless_rma/backend/shimless_rma_service.h
+++ b/ash/webui/shimless_rma/backend/shimless_rma_service.h
@@ -5,6 +5,7 @@
 #ifndef ASH_WEBUI_SHIMLESS_RMA_BACKEND_SHIMLESS_RMA_SERVICE_H_
 #define ASH_WEBUI_SHIMLESS_RMA_BACKEND_SHIMLESS_RMA_SERVICE_H_
 
+#include <memory>
 #include <string>
 
 #include "ash/webui/shimless_rma/backend/version_updater.h"
@@ -22,10 +23,13 @@
 namespace ash {
 namespace shimless_rma {
 
+class ShimlessRmaDelegate;
+
 class ShimlessRmaService : public mojom::ShimlessRmaService,
                            public chromeos::RmadClient::Observer {
  public:
-  ShimlessRmaService();
+  ShimlessRmaService(
+      std::unique_ptr<ShimlessRmaDelegate> shimless_rma_delegate);
   ShimlessRmaService(const ShimlessRmaService&) = delete;
   ShimlessRmaService& operator=(const ShimlessRmaService&) = delete;
 
@@ -223,6 +227,9 @@
   VersionUpdater version_updater_;
   base::OnceCallback<void(const std::string& version)> check_os_callback_;
 
+  // Provides browser functionality from //chrome to the Shimless RMA UI.
+  std::unique_ptr<ShimlessRmaDelegate> shimless_rma_delegate_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<ShimlessRmaService> weak_ptr_factory_{this};
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc b/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc
index c3b661a..79bd7d6 100644
--- a/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc
+++ b/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc
@@ -9,6 +9,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/webui/shimless_rma/backend/shimless_rma_delegate.h"
 #include "base/test/bind.h"
 #include "base/test/task_environment.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -57,6 +58,17 @@
       check_state_callback;
 };
 
+// A fake impl of ShimlessRmaDelegate.
+class FakeShimlessRmaDelegate : public ShimlessRmaDelegate {
+ public:
+  FakeShimlessRmaDelegate() = default;
+
+  FakeShimlessRmaDelegate(const FakeShimlessRmaDelegate&) = delete;
+  FakeShimlessRmaDelegate& operator=(const FakeShimlessRmaDelegate&) = delete;
+
+  void RestartChrome() override {}
+};
+
 }  // namespace
 
 class ShimlessRmaServiceTest : public testing::Test {
@@ -76,7 +88,8 @@
     rmad_client_ = chromeos::RmadClient::Get();
     // ShimlessRmaService has to be created after RmadClient or there will be a
     // null ptr dereference in the service constructor.
-    shimless_rma_provider_ = std::make_unique<ShimlessRmaService>();
+    shimless_rma_provider_ = std::make_unique<ShimlessRmaService>(
+        std::make_unique<FakeShimlessRmaDelegate>());
 
     // Wait until |cros_network_config_test_helper_| has initialized.
     base::RunLoop().RunUntilIdle();
diff --git a/ash/webui/shimless_rma/shimless_rma.cc b/ash/webui/shimless_rma/shimless_rma.cc
index f9b3a67..49ccd14 100644
--- a/ash/webui/shimless_rma/shimless_rma.cc
+++ b/ash/webui/shimless_rma/shimless_rma.cc
@@ -4,12 +4,14 @@
 
 #include "ash/webui/shimless_rma/shimless_rma.h"
 
+#include <memory>
 #include <string>
 #include <utility>
 
 #include "ash/grit/ash_shimless_rma_resources.h"
 #include "ash/grit/ash_shimless_rma_resources_map.h"
 #include "ash/public/cpp/network_config_service.h"
+#include "ash/webui/shimless_rma/backend/shimless_rma_delegate.h"
 #include "ash/webui/shimless_rma/url_constants.h"
 #include "base/containers/span.h"
 #include "base/memory/ptr_util.h"
@@ -253,10 +255,12 @@
 
 }  // namespace
 
-ShimlessRMADialogUI::ShimlessRMADialogUI(content::WebUI* web_ui)
+ShimlessRMADialogUI::ShimlessRMADialogUI(
+    content::WebUI* web_ui,
+    std::unique_ptr<shimless_rma::ShimlessRmaDelegate> shimless_rma_delegate)
     : ui::MojoWebDialogUI(web_ui),
-      shimless_rma_manager_(
-          std::make_unique<shimless_rma::ShimlessRmaService>()) {
+      shimless_rma_manager_(std::make_unique<shimless_rma::ShimlessRmaService>(
+          std::move(shimless_rma_delegate))) {
   auto html_source = base::WrapUnique(
       content::WebUIDataSource::Create(kChromeUIShimlessRMAHost));
   html_source->OverrideContentSecurityPolicy(
diff --git a/ash/webui/shimless_rma/shimless_rma.h b/ash/webui/shimless_rma/shimless_rma.h
index 9ade533..3f2828b 100644
--- a/ash/webui/shimless_rma/shimless_rma.h
+++ b/ash/webui/shimless_rma/shimless_rma.h
@@ -19,10 +19,16 @@
 
 namespace ash {
 
+namespace shimless_rma {
+class ShimlessRmaDelegate;
+}  // namespace shimless_rma
+
 // The WebUI for ShimlessRMA or chrome://shimless-rma.
 class ShimlessRMADialogUI : public ui::MojoWebDialogUI {
  public:
-  explicit ShimlessRMADialogUI(content::WebUI* web_ui);
+  ShimlessRMADialogUI(
+      content::WebUI* web_ui,
+      std::unique_ptr<shimless_rma::ShimlessRmaDelegate> shimless_rma_delegate);
   ~ShimlessRMADialogUI() override;
 
   ShimlessRMADialogUI(const ShimlessRMADialogUI&) = delete;
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc
index 3f893f97..38271ca9 100644
--- a/ash/wm/desks/desks_controller.cc
+++ b/ash/wm/desks/desks_controller.cc
@@ -55,6 +55,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "components/app_restore/app_launch_info.h"
+#include "components/app_restore/full_restore_utils.h"
 #include "components/app_restore/restore_data.h"
 #include "components/app_restore/window_info.h"
 #include "components/app_restore/window_properties.h"
@@ -891,6 +892,12 @@
       continue;
     }
 
+    // Exclude window that does not asscociate with a full restore app id,
+    // silently omitting them.
+    const std::string app_id = full_restore::GetAppId(window);
+    if (app_id.empty())
+      continue;
+
     std::unique_ptr<app_restore::AppLaunchInfo> app_launch_info =
         delegate->GetAppLaunchDataForDeskTemplate(window);
     if (!app_launch_info)
@@ -898,7 +905,6 @@
 
     // We need to copy |app_launch_info->app_id| to |app_id| as the below
     // function AddAppLaunchInfo() will destroy |app_launch_info|.
-    const std::string app_id = app_launch_info->app_id;
     const int32_t window_id = window->GetProperty(app_restore::kWindowIdKey);
     restore_data->AddAppLaunchInfo(std::move(app_launch_info));
 
diff --git a/ash/wm/desks/templates/desks_templates_icon_view.cc b/ash/wm/desks/templates/desks_templates_icon_view.cc
index ca7719e..e15815d 100644
--- a/ash/wm/desks/templates/desks_templates_icon_view.cc
+++ b/ash/wm/desks/templates/desks_templates_icon_view.cc
@@ -18,6 +18,7 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_operations.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/resources/grit/ui_resources.h"
 #include "ui/views/border.h"
@@ -77,18 +78,30 @@
 
   GURL potential_url{icon_identifier_};
   auto* delegate = Shell::Get()->desks_templates_delegate();
-  if (potential_url.is_valid()) {
-    delegate->GetFaviconForUrl(
-        icon_identifier_, kIconSize,
-        base::BindOnce(&DesksTemplatesIconView::OnFaviconLoaded,
-                       weak_ptr_factory_.GetWeakPtr()),
-        &cancelable_task_tracker_);
-  } else {
+  if (!potential_url.is_valid()) {
     delegate->GetIconForAppId(
         icon_identifier_, kIconSize,
         base::BindOnce(&DesksTemplatesIconView::OnAppIconLoaded,
                        weak_ptr_factory_.GetWeakPtr()));
+    return;
   }
+
+  // First check if the valid url is the NTP. If it is, use the chrome icon
+  // instead of a favicon.
+  absl::optional<gfx::ImageSkia> chrome_icon =
+      delegate->MaybeRetrieveChromeIconForNTPUrl(icon_identifier_);
+  if (chrome_icon.has_value()) {
+    icon_view_->SetImage(gfx::ImageSkiaOperations::CreateResizedImage(
+        chrome_icon.value(), skia::ImageOperations::RESIZE_BEST,
+        gfx::Size(kIconSize, kIconSize)));
+    return;
+  }
+
+  delegate->GetFaviconForUrl(
+      icon_identifier_, kIconSize,
+      base::BindOnce(&DesksTemplatesIconView::OnFaviconLoaded,
+                     weak_ptr_factory_.GetWeakPtr()),
+      &cancelable_task_tracker_);
 }
 
 void DesksTemplatesIconView::UpdateCount(int count) {
diff --git a/ash/wm/desks/templates/desks_templates_unittest.cc b/ash/wm/desks/templates/desks_templates_unittest.cc
index 67cc0592..2ffd18c 100644
--- a/ash/wm/desks/templates/desks_templates_unittest.cc
+++ b/ash/wm/desks/templates/desks_templates_unittest.cc
@@ -42,6 +42,7 @@
 #include "base/time/time.h"
 #include "components/app_restore/app_launch_info.h"
 #include "components/app_restore/window_info.h"
+#include "components/app_restore/window_properties.h"
 #include "components/prefs/pref_service.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
@@ -463,7 +464,7 @@
 
   AddEntry(base::GUID::GenerateRandomV4(), "template_1", base::Time::Now());
 
-  auto test_window = CreateTestWindow();
+  auto test_window = CreateAppWindow();
 
   // Start overview mode. The window is visible in the overview mode.
   ToggleOverview();
@@ -487,7 +488,7 @@
 
   // Create a test window in the current desk.
   DesksController* desks_controller = DesksController::Get();
-  auto test_window_1 = CreateTestWindow();
+  auto test_window_1 = CreateAppWindow();
   ASSERT_EQ(0, desks_controller->GetActiveDeskIndex());
   EXPECT_EQ(1ul, desks_controller->active_desk()->windows().size());
 
@@ -495,7 +496,7 @@
   desks_controller->NewDesk(DesksCreationRemovalSource::kKeyboard);
   Desk* desk = desks_controller->desks().back().get();
   ActivateDesk(desk);
-  auto test_window_2 = CreateTestWindow();
+  auto test_window_2 = CreateAppWindow();
   // Check that the active desk is the second desk, and that it contains one
   // window.
   ASSERT_EQ(1, desks_controller->GetActiveDeskIndex());
@@ -639,7 +640,7 @@
   AddEntry(uuid_2, "template_2", base::Time::Now() + base::Hours(13));
 
   // This window should be hidden whenever the desk templates grid is open.
-  auto test_window = CreateTestWindow();
+  auto test_window = CreateAppWindow();
 
   OpenOverviewAndShowTemplatesGrid();
 
@@ -677,7 +678,7 @@
 // number of templates has been reached.
 TEST_F(DesksTemplatesTest, SaveDeskAsTemplateButtonDisabled) {
   // Create a test window in the current desk.
-  auto test_window = CreateTestWindow();
+  auto test_window = CreateAppWindow();
 
   aura::Window* root = Shell::GetPrimaryRootWindow();
   // Open overview and save a template.
@@ -706,7 +707,7 @@
 // grid.
 TEST_F(DesksTemplatesTest, SaveDeskAsTemplateButtonShowsDesksTemplatesGrid) {
   // There are no saved template entries and one test window initially.
-  auto test_window = CreateTestWindow();
+  auto test_window = CreateAppWindow();
   ToggleOverview();
   WaitForUI();
 
@@ -732,7 +733,7 @@
   DesksController* desks_controller = DesksController::Get();
   ASSERT_EQ(0, desks_controller->GetActiveDeskIndex());
 
-  auto test_window = CreateTestWindow();
+  auto test_window = CreateAppWindow();
 
   // Capture the current desk and open the templates grid.
   OpenOverviewAndSaveTemplate(Shell::Get()->GetPrimaryRootWindow());
@@ -959,7 +960,7 @@
 
   // Create a window and add a test entry. Otherwise the templates UI wouldn't
   // show up in clamshell mode either.
-  auto test_window_1 = CreateTestWindow();
+  auto test_window_1 = CreateAppWindow();
   AddEntry(base::GUID::GenerateRandomV4(), "template", base::Time::Now());
 
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
@@ -983,7 +984,7 @@
 TEST_F(DesksTemplatesTest, ClamshellToTabletMode) {
   // Create a window and add a test entry. Otherwise the templates UI wouldn't
   // show up.
-  auto test_window_1 = CreateTestWindow();
+  auto test_window_1 = CreateAppWindow();
   AddEntry(base::GUID::GenerateRandomV4(), "template", base::Time::Now());
 
   // Test that on entering overview, the zero state desks templates button and
@@ -1014,7 +1015,7 @@
 TEST_F(DesksTemplatesTest, ShowingTemplatesGridToTabletMode) {
   // Create a window and add a test entry. Otherwise the templates UI wouldn't
   // show up.
-  auto test_window_1 = CreateTestWindow();
+  auto test_window_1 = CreateAppWindow();
   AddEntry(base::GUID::GenerateRandomV4(), "template", base::Time::Now());
 
   OpenOverviewAndShowTemplatesGrid();
@@ -1036,7 +1037,7 @@
 }
 
 TEST_F(DesksTemplatesTest, OverviewTabbing) {
-  auto test_window = CreateTestWindow();
+  auto test_window = CreateAppWindow();
   AddEntry(base::GUID::GenerateRandomV4(), "template1", base::Time::Now());
   AddEntry(base::GUID::GenerateRandomV4(), "template2", base::Time::Now());
 
@@ -1097,12 +1098,12 @@
 // an active desk with unsupported apps.
 TEST_F(DesksTemplatesTest, UnsupportedAppsDialog) {
   // Create a crostini window.
-  auto crostini_window = CreateTestWindow();
+  auto crostini_window = CreateAppWindow();
   crostini_window->SetProperty(aura::client::kAppType,
                                static_cast<int>(AppType::CROSTINI_APP));
 
   // Create a normal window.
-  auto test_window = CreateTestWindow();
+  auto test_window = CreateAppWindow();
 
   // Open overview and click on the save template button. The unsupported apps
   // dialog should show up.
@@ -1146,7 +1147,7 @@
 
 // Tests the mouse and touch hover behavior on the template item view.
 TEST_F(DesksTemplatesTest, HoverOnTemplateItemView) {
-  auto test_window = CreateTestWindow();
+  auto test_window = CreateAppWindow();
   AddEntry(base::GUID::GenerateRandomV4(), "template1", base::Time::Now());
   AddEntry(base::GUID::GenerateRandomV4(), "template2", base::Time::Now());
 
@@ -1195,4 +1196,24 @@
   EXPECT_FALSE(hover_container_view2->GetVisible());
 }
 
+// Tests that when a supported app doesn't have any app launch info and a
+// template is saved, the unsupported apps dialog isn't shown. See
+// crbug.com/1269466.
+TEST_F(DesksTemplatesTest, DialogDoesntShowForSupportedAppsWithoutLaunchInfo) {
+  constexpr int kInvalidWindowKey = -10000;
+
+  // Create a normal window.
+  auto test_window = CreateAppWindow();
+
+  // Set its `app_restore::kWindowIdKey` to an untracked window id. This
+  // simulates a supported window not having a corresponding app launch info.
+  test_window->SetProperty(app_restore::kWindowIdKey, kInvalidWindowKey);
+
+  // Open overview and click on the save template button. The unsupported apps
+  // dialog should not show up and an entry should be saved.
+  OpenOverviewAndSaveTemplate(Shell::Get()->GetPrimaryRootWindow());
+  EXPECT_FALSE(Shell::IsSystemModalWindowOpen());
+  ASSERT_EQ(1ul, GetAllEntries().size());
+}
+
 }  // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 5ae8a23c..d0dc8f54 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -496,6 +496,8 @@
     "pending_task.h",
     "pickle.cc",
     "pickle.h",
+    "power_monitor/moving_average.cc",
+    "power_monitor/moving_average.h",
     "power_monitor/power_monitor.cc",
     "power_monitor/power_monitor.h",
     "power_monitor/power_monitor_device_source.cc",
@@ -1968,6 +1970,7 @@
         "allocator/partition_allocator/reservation_offset_table.h",
         "allocator/partition_allocator/spinning_mutex.cc",
         "allocator/partition_allocator/spinning_mutex.h",
+        "allocator/partition_allocator/starscan/logging.h",
         "allocator/partition_allocator/starscan/metadata_allocator.cc",
         "allocator/partition_allocator/starscan/metadata_allocator.h",
         "allocator/partition_allocator/starscan/pcscan.cc",
@@ -2033,6 +2036,8 @@
       "files/file_enumerator_win.cc",
       "memory/platform_shared_memory_region_win.cc",
       "power_monitor/power_monitor_device_source_win.cc",
+      "power_monitor/speed_limit_observer_win.cc",
+      "power_monitor/speed_limit_observer_win.h",
       "profiler/win32_stack_frame_unwinder.cc",
       "profiler/win32_stack_frame_unwinder.h",
       "rand_util_win.cc",
@@ -3096,6 +3101,7 @@
     "parameter_pack_unittest.cc",
     "path_service_unittest.cc",
     "pickle_unittest.cc",
+    "power_monitor/moving_average_unittest.cc",
     "power_monitor/power_monitor_device_source_unittest.cc",
     "power_monitor/power_monitor_unittest.cc",
     "process/environment_internal_unittest.cc",
diff --git a/base/allocator/partition_allocator/starscan/logging.h b/base/allocator/partition_allocator/starscan/logging.h
new file mode 100644
index 0000000..9bed8a1
--- /dev/null
+++ b/base/allocator/partition_allocator/starscan/logging.h
@@ -0,0 +1,40 @@
+// Copyright (c) 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 BASE_ALLOCATOR_PARTITION_ALLOCATOR_STARSCAN_LOGGING_H_
+#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_STARSCAN_LOGGING_H_
+
+#include "base/allocator/partition_allocator/allocation_guard.h"
+#include "base/logging.h"
+
+namespace base {
+namespace internal {
+
+// Logging requires allocations. This logger allows reentrant allocations to
+// happen within the allocator context.
+struct LoggerWithAllowedAllocations : ScopedAllowAllocations,
+                                      logging::LogMessage {
+  using logging::LogMessage::LogMessage;
+};
+
+#define PA_PCSCAN_VLOG_STREAM(verbose_level)                         \
+  ::base::internal::LoggerWithAllowedAllocations(__FILE__, __LINE__, \
+                                                 -(verbose_level))   \
+      .stream()
+
+// Logging macro that is meant to be used inside *Scan. Generally, reentrancy
+// may be an issue if the macro is called from malloc()/free(). Currently, it's
+// only called at the end of *Scan and when scheduling a new *Scan task.
+// Allocating from these paths should not be an issue, since we make sure that
+// no infinite recursion can occur (e.g. we can't schedule two *Scan tasks and
+// the inner free() call must be non-reentrant).  However, these sorts of things
+// are tricky to enforce and easy to mess up with. Since verbose *Scan logging
+// is essential for debugging, we choose to provide support for it inside *Scan.
+#define PA_PCSCAN_VLOG(verbose_level) \
+  LAZY_STREAM(PA_PCSCAN_VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_STARSCAN_LOGGING_H_
diff --git a/base/allocator/partition_allocator/starscan/pcscan_scheduling.cc b/base/allocator/partition_allocator/starscan/pcscan_scheduling.cc
index a815c46..775ad12 100644
--- a/base/allocator/partition_allocator/starscan/pcscan_scheduling.cc
+++ b/base/allocator/partition_allocator/starscan/pcscan_scheduling.cc
@@ -10,9 +10,9 @@
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_hooks.h"
 #include "base/allocator/partition_allocator/partition_lock.h"
+#include "base/allocator/partition_allocator/starscan/logging.h"
 #include "base/allocator/partition_allocator/starscan/pcscan.h"
 #include "base/bind.h"
-#include "base/logging.h"
 #include "base/time/time.h"
 
 namespace base {
@@ -123,8 +123,8 @@
         return true;
       }
 
-      VLOG(3) << "Rescheduling scan with delay: "
-              << reschedule_delay.InMillisecondsF() << " ms";
+      PA_PCSCAN_VLOG(3) << "Rescheduling scan with delay: "
+                        << reschedule_delay.InMillisecondsF() << " ms";
       // 5. If the MU requirement is not satisfied, schedule a delayed scan to
       // the time instance when MU is satisfied.
       should_reschedule = true;
@@ -191,8 +191,8 @@
       return true;
     }
 
-    VLOG(3) << "Rescheduling scan with delay: "
-            << reschedule_delay.InMillisecondsF() << " ms";
+    PA_PCSCAN_VLOG(3) << "Rescheduling scan with delay: "
+                      << reschedule_delay.InMillisecondsF() << " ms";
     // Schedule a delayed scan to the time instance when MU is satisfied.
     should_reschedule = true;
   }
@@ -207,7 +207,7 @@
   PartitionAutoLock guard(scheduler_lock_);
   // TODO(1197479): Adjust schedule to current heap sizing.
   const auto delay = earliest_next_scan_time_ - base::TimeTicks::Now();
-  VLOG(3) << "Schedule is off by " << delay.InMillisecondsF() << "ms";
+  PA_PCSCAN_VLOG(3) << "Schedule is off by " << delay.InMillisecondsF() << "ms";
   return delay >= TimeDelta() ? delay : TimeDelta();
 }
 
diff --git a/base/allocator/partition_allocator/starscan/stats_collector.cc b/base/allocator/partition_allocator/starscan/stats_collector.cc
index 1f4c57d..bdea94a 100644
--- a/base/allocator/partition_allocator/starscan/stats_collector.cc
+++ b/base/allocator/partition_allocator/starscan/stats_collector.cc
@@ -4,8 +4,8 @@
 
 #include "base/allocator/partition_allocator/starscan/stats_collector.h"
 
+#include "base/allocator/partition_allocator/starscan/logging.h"
 #include "base/allocator/partition_allocator/starscan/stats_reporter.h"
-#include "base/logging.h"
 #include "base/time/time.h"
 
 namespace base {
@@ -84,11 +84,13 @@
       static_cast<double>(survived_quarantine_size()) / quarantine_last_size_;
   reporter.ReportSurvivedQuarantineSize(survived_quarantine_size());
   reporter.ReportSurvivedQuarantinePercent(survived_rate);
-  VLOG(2) << "quarantine size: " << quarantine_last_size_ << " -> "
-          << survived_quarantine_size() << ", swept bytes: " << swept_size()
-          << ", survival rate: " << survived_rate;
+  PA_PCSCAN_VLOG(2) << "quarantine size: " << quarantine_last_size_ << " -> "
+                    << survived_quarantine_size()
+                    << ", swept bytes: " << swept_size()
+                    << ", survival rate: " << survived_rate;
   if (discarded_quarantine_size_)
-    VLOG(2) << "discarded quarantine size: " << discarded_quarantine_size_;
+    PA_PCSCAN_VLOG(2) << "discarded quarantine size: "
+                      << discarded_quarantine_size_;
 }
 
 template base::TimeDelta StatsCollector::GetTimeImpl(
diff --git a/base/bind.h b/base/bind.h
index 47a7e94..1a2937f 100644
--- a/base/bind.h
+++ b/base/bind.h
@@ -12,6 +12,7 @@
 
 #include "base/bind_internal.h"
 #include "base/compiler_specific.h"
+#include "base/memory/raw_ptr.h"
 #include "base/template_util.h"
 #include "build/build_config.h"
 
@@ -139,6 +140,11 @@
   return internal::UnretainedWrapper<T>(o);
 }
 
+template <typename T>
+inline internal::UnretainedWrapper<T> Unretained(const raw_ptr<T>& o) {
+  return internal::UnretainedWrapper<T>(o.get());
+}
+
 // RetainedRef() accepts a ref counted object and retains a reference to it.
 // When the callback is called, the object is passed as a raw pointer.
 //
diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc
index ec7433a..53d74cc7 100644
--- a/base/bind_unittest.cc
+++ b/base/bind_unittest.cc
@@ -11,6 +11,7 @@
 
 #include "base/callback.h"
 #include "base/memory/ptr_util.h"
+#include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_number_conversions.h"
@@ -1713,6 +1714,19 @@
               .Run());
 }
 
+int PingPong(int* i_ptr) {
+  return *i_ptr;
+}
+
+TEST_F(BindTest, BindAndCallbacks) {
+  int i = 123;
+  raw_ptr<int> p = &i;
+
+  auto callback = base::BindOnce(PingPong, base::Unretained(p));
+  int res = std::move(callback).Run();
+  EXPECT_EQ(123, res);
+}
+
 // Test null callbacks cause a DCHECK.
 TEST(BindDeathTest, NullCallback) {
   base::RepeatingCallback<void(int)> null_cb;
diff --git a/base/power_monitor/moving_average.cc b/base/power_monitor/moving_average.cc
new file mode 100644
index 0000000..bac4f770
--- /dev/null
+++ b/base/power_monitor/moving_average.cc
@@ -0,0 +1,64 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/moving_average.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "base/check_op.h"
+
+namespace {
+constexpr int kIntMax = std::numeric_limits<int>::max();
+constexpr int64_t kInt64Max = std::numeric_limits<int64_t>::max();
+}  // namespace
+
+namespace base {
+
+MovingAverage::MovingAverage(uint8_t window_size)
+    : window_size_(window_size), buffer_(window_size, 0) {
+  DCHECK_LE(kIntMax * window_size, kInt64Max);
+}
+
+MovingAverage::~MovingAverage() = default;
+
+void MovingAverage::AddSample(int sample) {
+  sum_ -= buffer_[index_];
+  buffer_[index_++] = sample;
+  sum_ += sample;
+  if (index_ == window_size_) {
+    full_ = true;
+    index_ = 0;
+  }
+}
+
+int MovingAverage::GetAverageRoundedDown() const {
+  if (Size() == 0)
+    return 0;
+  return sum_ / Size();
+}
+
+int MovingAverage::GetAverageRoundedToClosest() const {
+  if (Size() == 0)
+    return 0;
+  return (sum_ + Size() / 2) / Size();
+}
+
+double MovingAverage::GetUnroundedAverage() const {
+  if (Size() == 0)
+    return 0;
+  return sum_ / static_cast<double>(Size());
+}
+
+void MovingAverage::Reset() {
+  std::fill(buffer_.begin(), buffer_.end(), 0);
+  sum_ = 0;
+  index_ = 0;
+  full_ = false;
+}
+
+size_t MovingAverage::Size() const {
+  return full_ ? window_size_ : index_;
+}
+}  // namespace base
diff --git a/base/power_monitor/moving_average.h b/base/power_monitor/moving_average.h
new file mode 100644
index 0000000..a6c9cc1
--- /dev/null
+++ b/base/power_monitor/moving_average.h
@@ -0,0 +1,67 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POWER_MONITOR_MOVING_AVERAGE_H_
+#define BASE_POWER_MONITOR_MOVING_AVERAGE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// Calculates average over a small fixed size window. If there are less than
+// window size elements, calculates average of all inserted elements so far.
+// This implementation support a maximum window size of 255.
+// Ported from third_party/webrtc/rtc_base/numerics/moving_average.h.
+class BASE_EXPORT MovingAverage {
+ public:
+  // Maximum supported window size is 2^8 - 1 = 255.
+  explicit MovingAverage(uint8_t window_size);
+  ~MovingAverage();
+  // MovingAverage is neither copyable nor movable.
+  MovingAverage(const MovingAverage&) = delete;
+  MovingAverage& operator=(const MovingAverage&) = delete;
+
+  // Adds new sample. If the window is full, the oldest element is pushed out.
+  // Returns false if `sample` causes an overflow.
+  void AddSample(int sample);
+
+  // Returns rounded down average of last `window_size` elements or all
+  // elements if there are not enough of them.
+  int GetAverageRoundedDown() const;
+
+  // Same as above but rounded to the closest integer.
+  int GetAverageRoundedToClosest() const;
+
+  // Returns unrounded average over the window.
+  double GetUnroundedAverage() const;
+
+  // Resets to the initial state before any elements were added.
+  void Reset();
+
+  // Returns number of elements in the window.
+  size_t Size() const;
+
+ private:
+  // Stores `window_size` used in the constructor.
+  uint8_t window_size_ = 0;
+  // New samples are added at this index. Counts modulo `window_size`.
+  uint8_t index_ = 0;
+  // Set to true when the `buffer_` is full. i.e, all elements contain a
+  // sample added by AddSample().
+  bool full_ = false;
+  // Sum of the samples in the moving window.
+  int64_t sum_ = 0;
+  // Circular buffer for all the samples in the moving window.
+  // Size is always `window_size`
+  std::vector<int> buffer_;
+};
+
+}  // namespace base
+
+#endif  // BASE_POWER_MONITOR_MOVING_AVERAGE_H_
diff --git a/base/power_monitor/moving_average_unittest.cc b/base/power_monitor/moving_average_unittest.cc
new file mode 100644
index 0000000..7fb7d36
--- /dev/null
+++ b/base/power_monitor/moving_average_unittest.cc
@@ -0,0 +1,120 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/moving_average.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace test {
+
+// Ported from third_party/webrtc/rtc_base/numerics/moving_average_unittest.cc.
+
+TEST(MovingAverageTest, EmptyAverage) {
+  MovingAverage moving_average(1);
+  EXPECT_EQ(0u, moving_average.Size());
+  EXPECT_EQ(0, moving_average.GetAverageRoundedDown());
+}
+
+TEST(MovingAverageTest, OneElement) {
+  MovingAverage moving_average(1);
+  moving_average.AddSample(3);
+  EXPECT_EQ(1u, moving_average.Size());
+  EXPECT_EQ(3, moving_average.GetAverageRoundedDown());
+}
+
+// Verify that Size() increases monotonically when samples are added up to the
+// window size. At that point the filter is full and shall return the window
+// size as Size() until Reset() is called.
+TEST(MovingAverageTest, Size) {
+  constexpr uint8_t kWindowSize = 3;
+  MovingAverage moving_average(kWindowSize);
+  EXPECT_EQ(0u, moving_average.Size());
+  moving_average.AddSample(1);
+  EXPECT_EQ(1u, moving_average.Size());
+  moving_average.AddSample(2);
+  EXPECT_EQ(2u, moving_average.Size());
+  moving_average.AddSample(3);
+  // Three samples have beend added and the filter is full (all elements in the
+  // buffer have been given a valid value).
+  EXPECT_EQ(kWindowSize, moving_average.Size());
+  // Adding a fourth sample will shift out the first sample (1) and the filter
+  // should now contain [4,2,3] => average is 9 / 3 = 3.
+  moving_average.AddSample(4);
+  EXPECT_EQ(kWindowSize, moving_average.Size());
+  EXPECT_EQ(3, moving_average.GetAverageRoundedToClosest());
+  moving_average.Reset();
+  EXPECT_EQ(0u, moving_average.Size());
+  EXPECT_EQ(0, moving_average.GetAverageRoundedToClosest());
+}
+
+TEST(MovingAverageTest, GetAverage) {
+  MovingAverage moving_average(255);
+  moving_average.AddSample(1);
+  moving_average.AddSample(1);
+  moving_average.AddSample(3);
+  moving_average.AddSample(3);
+  EXPECT_EQ(moving_average.GetAverageRoundedDown(), 2);
+  EXPECT_EQ(moving_average.GetAverageRoundedToClosest(), 2);
+}
+
+TEST(MovingAverageTest, GetAverageRoundedDownRounds) {
+  MovingAverage moving_average(255);
+  moving_average.AddSample(1);
+  moving_average.AddSample(2);
+  moving_average.AddSample(2);
+  moving_average.AddSample(2);
+  EXPECT_EQ(moving_average.GetAverageRoundedDown(), 1);
+}
+
+TEST(MovingAverageTest, GetAverageRoundedToClosestRounds) {
+  MovingAverage moving_average(255);
+  moving_average.AddSample(1);
+  moving_average.AddSample(2);
+  moving_average.AddSample(2);
+  moving_average.AddSample(2);
+  EXPECT_EQ(moving_average.GetAverageRoundedToClosest(), 2);
+}
+
+TEST(MovingAverageTest, Reset) {
+  MovingAverage moving_average(5);
+  moving_average.AddSample(1);
+  EXPECT_EQ(1, moving_average.GetAverageRoundedDown());
+  EXPECT_EQ(1, moving_average.GetAverageRoundedToClosest());
+
+  moving_average.Reset();
+
+  EXPECT_EQ(0, moving_average.GetAverageRoundedDown());
+  moving_average.AddSample(10);
+  EXPECT_EQ(10, moving_average.GetAverageRoundedDown());
+  EXPECT_EQ(10, moving_average.GetAverageRoundedToClosest());
+}
+
+TEST(MovingAverageTest, ManySamples) {
+  MovingAverage moving_average(10);
+  for (int i = 1; i < 11; i++) {
+    moving_average.AddSample(i);
+  }
+  EXPECT_EQ(moving_average.GetAverageRoundedDown(), 5);
+  EXPECT_EQ(moving_average.GetAverageRoundedToClosest(), 6);
+  for (int i = 1; i < 2001; i++) {
+    moving_average.AddSample(i);
+  }
+  EXPECT_EQ(moving_average.GetAverageRoundedDown(), 1995);
+  EXPECT_EQ(moving_average.GetAverageRoundedToClosest(), 1996);
+}
+
+TEST(MovingAverageTest, VerifyNoOverflow) {
+  constexpr int kMaxInt = std::numeric_limits<int>::max();
+  MovingAverage moving_average(255);
+  for (int i = 0; i < 255; i++) {
+    moving_average.AddSample(kMaxInt);
+  }
+  EXPECT_EQ(moving_average.GetAverageRoundedDown(), kMaxInt);
+  EXPECT_EQ(moving_average.GetAverageRoundedToClosest(), kMaxInt);
+  EXPECT_EQ(moving_average.GetUnroundedAverage(), kMaxInt);
+}
+
+}  // namespace test
+}  // namespace base
diff --git a/base/power_monitor/power_monitor.cc b/base/power_monitor/power_monitor.cc
index 81d31be..52b153a 100644
--- a/base/power_monitor/power_monitor.cc
+++ b/base/power_monitor/power_monitor.cc
@@ -27,7 +27,7 @@
       PowerMonitor::Source()->GetCurrentThermalState());
 
   PowerMonitor::PowerMonitor::NotifySpeedLimitChange(
-      PowerMonitor::Source()->GetCurrentSpeedLimit());
+      PowerMonitor::Source()->GetInitialSpeedLimit());
 }
 
 bool PowerMonitor::IsInitialized() {
diff --git a/base/power_monitor/power_monitor_device_source.cc b/base/power_monitor/power_monitor_device_source.cc
index 108376b..3a11df6 100644
--- a/base/power_monitor/power_monitor_device_source.cc
+++ b/base/power_monitor/power_monitor_device_source.cc
@@ -7,13 +7,13 @@
 namespace base {
 
 PowerMonitorDeviceSource::PowerMonitorDeviceSource() {
-#if defined(OS_APPLE)
+#if defined(OS_APPLE) || defined(OS_WIN)
   PlatformInit();
 #endif
 }
 
 PowerMonitorDeviceSource::~PowerMonitorDeviceSource() {
-#if defined(OS_APPLE)
+#if defined(OS_APPLE) || defined(OS_WIN)
   PlatformDestroy();
 #endif
 }
diff --git a/base/power_monitor/power_monitor_device_source.h b/base/power_monitor/power_monitor_device_source.h
index a99641d..653dbcc 100644
--- a/base/power_monitor/power_monitor_device_source.h
+++ b/base/power_monitor/power_monitor_device_source.h
@@ -16,7 +16,10 @@
 
 #if defined(OS_WIN)
 #include <windows.h>
-#endif  // !OS_WIN
+
+#include "base/power_monitor/speed_limit_observer_win.h"
+#include "base/threading/sequence_bound.h"
+#endif  // OS_WIN
 
 #if defined(OS_MAC)
 #include <IOKit/IOTypes.h>
@@ -24,7 +27,7 @@
 #include "base/mac/scoped_cftyperef.h"
 #include "base/mac/scoped_ionotificationportref.h"
 #include "base/power_monitor/thermal_state_observer_mac.h"
-#endif
+#endif  // OS_MAC
 
 #if defined(OS_IOS)
 #include <objc/runtime.h>
@@ -84,10 +87,10 @@
   };
 #endif  // OS_WIN
 
-#if defined(OS_APPLE)
+#if defined(OS_APPLE) || defined(OS_WIN)
   void PlatformInit();
   void PlatformDestroy();
-#endif  // OS_APPLE
+#endif  // OS_APPLE || OS_WIN
 
 #if defined(OS_MAC)
   // Callback from IORegisterForSystemPower(). |refcon| is the |this| pointer.
@@ -106,10 +109,15 @@
   int GetRemainingBatteryCapacity() override;
 #endif  // defined(OS_ANDROID)
 
+#if defined(OS_WIN)
+  // PowerMonitorSource:
+  int GetInitialSpeedLimit() override;
+#endif  // OS_WIN
+
 #if defined(OS_MAC)
   // PowerMonitorSource:
   PowerThermalObserver::DeviceThermalState GetCurrentThermalState() override;
-  int GetCurrentSpeedLimit() override;
+  int GetInitialSpeedLimit() override;
 
   // Reference to the system IOPMrootDomain port.
   io_connect_t power_manager_port_ = IO_OBJECT_NULL;
@@ -134,6 +142,10 @@
 
 #if defined(OS_WIN)
   PowerMessageWindow power_message_window_;
+  // |speed_limit_observer_| is owned by the main/UI thread but the
+  // SpeedLimitObserverWin is bound to a different sequence.
+  std::unique_ptr<base::SequenceBound<SpeedLimitObserverWin>>
+      speed_limit_observer_;
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/base/power_monitor/power_monitor_device_source_mac.mm b/base/power_monitor/power_monitor_device_source_mac.mm
index 608f721..5aa8eac 100644
--- a/base/power_monitor/power_monitor_device_source_mac.mm
+++ b/base/power_monitor/power_monitor_device_source_mac.mm
@@ -72,7 +72,7 @@
   return thermal_state_observer_->GetCurrentThermalState();
 }
 
-int PowerMonitorDeviceSource::GetCurrentSpeedLimit() {
+int PowerMonitorDeviceSource::GetInitialSpeedLimit() {
   return thermal_state_observer_->GetCurrentSpeedLimit();
 }
 
diff --git a/base/power_monitor/power_monitor_device_source_win.cc b/base/power_monitor/power_monitor_device_source_win.cc
index 3c8d25d..0ccb567 100644
--- a/base/power_monitor/power_monitor_device_source_win.cc
+++ b/base/power_monitor/power_monitor_device_source_win.cc
@@ -11,6 +11,8 @@
 #include "base/power_monitor/power_monitor_source.h"
 #include "base/strings/string_util.h"
 #include "base/task/current_thread.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/thread_pool.h"
 #include "base/win/wrapped_window_proc.h"
 
 namespace base {
@@ -56,6 +58,24 @@
 
 }  // namespace
 
+void PowerMonitorDeviceSource::PlatformInit() {
+  // Only for testing.
+  if (!CurrentUIThread::IsSet()) {
+    return;
+  }
+  speed_limit_observer_ =
+      std::make_unique<base::SequenceBound<SpeedLimitObserverWin>>(
+          base::ThreadPool::CreateSequencedTaskRunner({}),
+          BindRepeating(&PowerMonitorSource::ProcessSpeedLimitEvent));
+}
+
+void PowerMonitorDeviceSource::PlatformDestroy() {
+  // Because |speed_limit_observer_| is sequence bound, the actual destruction
+  // happens asynchronously on its task runner. Until this has completed it is
+  // still possible for PowerMonitorSource::ProcessSpeedLimitEvent to be called.
+  speed_limit_observer_.reset();
+}
+
 // Function to query the system to see if it is currently running on
 // battery power.  Returns true if running on battery.
 bool PowerMonitorDeviceSource::IsOnBatteryPower() {
@@ -67,6 +87,12 @@
   return (status.ACLineStatus == 0);
 }
 
+int PowerMonitorDeviceSource::GetInitialSpeedLimit() {
+  // Returns the maximum value once at start. Subsequent actual values will be
+  // provided asynchronously via callbacks instead.
+  return PowerThermalObserver::kSpeedLimitMax;
+}
+
 PowerMonitorDeviceSource::PowerMessageWindow::PowerMessageWindow()
     : instance_(NULL), message_hwnd_(NULL) {
   if (!CurrentUIThread::IsSet()) {
diff --git a/base/power_monitor/power_monitor_source.cc b/base/power_monitor/power_monitor_source.cc
index c53a9bf2..6a70ccc 100644
--- a/base/power_monitor/power_monitor_source.cc
+++ b/base/power_monitor/power_monitor_source.cc
@@ -18,7 +18,7 @@
   return PowerThermalObserver::DeviceThermalState::kUnknown;
 }
 
-int PowerMonitorSource::GetCurrentSpeedLimit() {
+int PowerMonitorSource::GetInitialSpeedLimit() {
   return PowerThermalObserver::kSpeedLimitMax;
 }
 
diff --git a/base/power_monitor/power_monitor_source.h b/base/power_monitor/power_monitor_source.h
index 0a94abb9..5c24e18 100644
--- a/base/power_monitor/power_monitor_source.h
+++ b/base/power_monitor/power_monitor_source.h
@@ -34,9 +34,12 @@
   // Otherwise, returns kUnknown.
   virtual PowerThermalObserver::DeviceThermalState GetCurrentThermalState();
 
-  // Reads the current operating system CPU speed limit, if available on the
+  // Reads the initial operating system CPU speed limit, if available on the
   // platform. Otherwise returns PowerThermalObserver::kSpeedLimitMax.
-  virtual int GetCurrentSpeedLimit();
+  // Only called on the main thead in PowerMonitor::Initialize().
+  // The actual speed limit value will be updated asynchronosulsy via the
+  // ProcessSpeedLimitEvent() if/when the value changes.
+  virtual int GetInitialSpeedLimit();
 
   // Update the result of thermal state.
   virtual void SetCurrentThermalState(
diff --git a/base/power_monitor/speed_limit_observer_win.cc b/base/power_monitor/speed_limit_observer_win.cc
new file mode 100644
index 0000000..139f7e8
--- /dev/null
+++ b/base/power_monitor/speed_limit_observer_win.cc
@@ -0,0 +1,188 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/speed_limit_observer_win.h"
+
+// windows.h must be included before powerbase.h
+#include <windows.h>    // NOLINT(build/include_order)
+#include <powerbase.h>  // NOLINT(build/include_order)
+#include <winternl.h>   // NOLINT(build/include_order)
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/system/sys_info.h"
+
+namespace {
+
+// From ntdef.f
+#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
+
+// We poll for new speed-limit values once every second.
+constexpr base::TimeDelta kSampleInterval = base::Seconds(1);
+
+// Size of moving-average filter which is used to smooth out variations in
+// speed-limit estimates.
+constexpr size_t kMovingAverageWindowSize = 10;
+
+// From
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa373184(v=vs.85).aspx.
+// Note that this structure definition was accidentally omitted from WinNT.h.
+typedef struct _PROCESSOR_POWER_INFORMATION {
+  ULONG Number;
+  ULONG MaxMhz;
+  ULONG CurrentMhz;
+  ULONG MhzLimit;
+  ULONG MaxIdleState;
+  ULONG CurrentIdleState;
+} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
+
+// From
+// https://docs.microsoft.com/en-us/windows/win32/power/system-power-information-str.
+// Note that this structure definition was accidentally omitted from WinNT.h.
+typedef struct _SYSTEM_POWER_INFORMATION {
+  ULONG MaxIdlenessAllowed;
+  ULONG Idleness;
+  ULONG TimeRemaining;
+  UCHAR CoolingMode;
+} SYSTEM_POWER_INFORMATION, *PSYSTEM_POWER_INFORMATION;
+
+// Returns information about the idleness of the system.
+bool GetCPUIdleness(int* idleness_percent) {
+  auto info = std::make_unique<SYSTEM_POWER_INFORMATION>();
+  if (!NT_SUCCESS(CallNtPowerInformation(SystemPowerInformation, nullptr, 0,
+                                         info.get(),
+                                         sizeof(SYSTEM_POWER_INFORMATION)))) {
+    *idleness_percent = 0;
+    return false;
+  }
+  // The current idle level, expressed as a percentage.
+  *idleness_percent = static_cast<int>(info->Idleness);
+  return true;
+}
+
+}  // namespace
+
+namespace base {
+
+SpeedLimitObserverWin::SpeedLimitObserverWin(
+    SpeedLimitUpdateCallback speed_limit_update_callback)
+    : callback_(std::move(speed_limit_update_callback)),
+      num_cpus_(SysInfo::NumberOfProcessors()),
+      moving_average_(kMovingAverageWindowSize) {
+  DVLOG(1) << __func__ << "(num_CPUs=" << num_cpus() << ")";
+  timer_.Start(FROM_HERE, kSampleInterval, this,
+               &SpeedLimitObserverWin::OnTimerTick);
+}
+
+SpeedLimitObserverWin::~SpeedLimitObserverWin() {
+  timer_.Stop();
+}
+
+int SpeedLimitObserverWin::GetCurrentSpeedLimit() {
+  const int kSpeedLimitMax = PowerThermalObserver::kSpeedLimitMax;
+
+  int idleness_percent = 0;
+  if (!GetCPUIdleness(&idleness_percent)) {
+    DLOG(WARNING) << "GetCPUIdleness failed";
+    return kSpeedLimitMax;
+  }
+
+  // Get the latest estimated throttling level (value between 0.0 and 1.0).
+  float throttling_level = EstimateThrottlingLevel();
+
+  // Ignore the value if the global idleness is above 90% or throttling value
+  // is very small. This approach avoids false alarms and removes noise from the
+  // measurements.
+  if (idleness_percent > 90 || throttling_level < 0.1f) {
+    moving_average_.Reset();
+    return kSpeedLimitMax;
+  }
+
+  // The speed limit metric is a value between 0 and 100 [%] where 100 means
+  // "full speed". The corresponding UMA metric is CPU_Speed_Limit.
+  float speed_limit_factor = 1.0f - throttling_level;
+  int speed_limit =
+      static_cast<int>(std::ceil(kSpeedLimitMax * speed_limit_factor));
+
+  // The previous speed-limit value was below 100 but the new value is now back
+  // at max again. To make this state more "stable or sticky" we reset the MA
+  // filter and return kSpeedLimitMax. As a result, single drops in speedlimit
+  // values will not result in a value less than 100 since the MA filter must
+  // be full before we start to produce any output.
+  if (speed_limit_ < kSpeedLimitMax && speed_limit == kSpeedLimitMax) {
+    moving_average_.Reset();
+    return kSpeedLimitMax;
+  }
+
+  // Add the latest speeed-limit value [0,100] to the MA filter and return its
+  // output after ensuring that the filter is full. We do this to avoid initial
+  // false alarms at startup and after calling Reset() on the filter.
+  moving_average_.AddSample(speed_limit);
+  if (moving_average_.Size() < kMovingAverageWindowSize) {
+    return kSpeedLimitMax;
+  }
+  return moving_average_.GetAverageRoundedDown();
+}
+
+void SpeedLimitObserverWin::OnTimerTick() {
+  // Get the latest (filtered) speed-limit estimate and trigger a new callback
+  // if the new value is different from the last.
+  const int speed_limit = GetCurrentSpeedLimit();
+  if (speed_limit != speed_limit_) {
+    speed_limit_ = speed_limit;
+    callback_.Run(speed_limit_);
+  }
+}
+
+float SpeedLimitObserverWin::EstimateThrottlingLevel() {
+  float throttling_level = 0.f;
+
+  // Populate the PROCESSOR_POWER_INFORMATION structures for all logical CPUs
+  // using the CallNtPowerInformation API.
+  std::vector<PROCESSOR_POWER_INFORMATION> info(num_cpus());
+  if (!NT_SUCCESS(CallNtPowerInformation(
+          ProcessorInformation, nullptr, 0, &info[0],
+          sizeof(PROCESSOR_POWER_INFORMATION) * num_cpus()))) {
+    return throttling_level;
+  }
+
+  // Estimate the level of throttling by measuring how many CPUs that are not
+  // in idle state and how "far away" they are from the most idle state. Local
+  // tests have shown that `MaxIdleState` is typically 2 or 3 and
+  // `CurrentIdleState` switches to 2 or 1 when some sort of trottling starts
+  // to take place. `CurrentIdleState` equal to 0 can happen on devices where
+  // `MaxIdleState` equals 1 but it seems hard to provoke when `MaxIdleState`
+  // is larger than 1.
+  // The Intel Extreme Tuning Utility application has been used to monitor when
+  // any type of throttling (thermal, power-limit, PMAX etc) starts.
+  int num_non_idle_cpus = 0;
+  float load_fraction_total = 0.0;
+  for (int i = 0; i < num_cpus(); ++i) {
+    // Amount of "non-idleness" is the distance from the max idle state.
+    const int idle_diff = info[i].MaxIdleState - info[i].CurrentIdleState;
+    // Derive a value between 0.0 and 1.0 where 1.0 corresponds to max load on
+    // CPU#i.
+    // Example: MaxIdleState=2, CurrentIdleState=1 => (2 - 1) / 2 = 0.5.
+    // Example: MaxIdleState=2, CurrentIdleState=2 => (2 - 2) / 2 = 1.0.
+    // Example: MaxIdleState=3, CurrentIdleState=1 => (3 - 1) / 3 = 0.6666.
+    // Example: MaxIdleState=3, CurrentIdleState=2 => (3 - 2) / 3 = 0.3333.
+    const float load_fraction =
+        static_cast<float>(idle_diff) / info[i].MaxIdleState;
+    // Accumulate the total load for all CPUs.
+    load_fraction_total += load_fraction;
+    // Used for a sanity check only.
+    num_non_idle_cpus += (info[i].CurrentIdleState < info[i].MaxIdleState);
+  }
+  DCHECK_LE(load_fraction_total, static_cast<float>(num_non_idle_cpus))
+      << " load_fraction_total: " << load_fraction_total
+      << " num_non_idle_cpus:" << num_non_idle_cpus;
+  throttling_level = (load_fraction_total / num_cpus());
+  return throttling_level;
+}
+
+}  // namespace base
diff --git a/base/power_monitor/speed_limit_observer_win.h b/base/power_monitor/speed_limit_observer_win.h
new file mode 100644
index 0000000..3e95b33
--- /dev/null
+++ b/base/power_monitor/speed_limit_observer_win.h
@@ -0,0 +1,65 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POWER_MONITOR_SPEED_LIMIT_OBSERVER_WIN_H_
+#define BASE_POWER_MONITOR_SPEED_LIMIT_OBSERVER_WIN_H_
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/power_monitor/moving_average.h"
+#include "base/power_monitor/power_observer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+
+namespace base {
+
+// This class is used to listen for speed-limit changes and route new values to
+// PowerMonitorSource when they are changed. The speed-limit value represents
+// how well the CPU is running, where 100 means that it is running at normal
+// speed (not throttled) and 0 means that it is so severely throttled (thermal
+// throttling, power throttling, or other) that it is not running at all.
+// A value under 70 indicates noticeable throttling, and a value under 40
+// indicates severe throttling. Well designed systems with sufficient power
+// and cooling should be able to run with no throttling, but some systems
+// (laptops in particular) may be throttled, especially in hot environments or
+// when running on battery. On a well designed computer this metric should stay
+// at 100, only going lower if there is insufficient cooling or power.
+class BASE_EXPORT SpeedLimitObserverWin final {
+ public:
+  typedef base::RepeatingCallback<void(int)> SpeedLimitUpdateCallback;
+
+  explicit SpeedLimitObserverWin(
+      SpeedLimitUpdateCallback speed_limit_update_callback);
+  ~SpeedLimitObserverWin();
+
+ private:
+  int GetCurrentSpeedLimit();
+  void OnTimerTick();
+  float EstimateThrottlingLevel();
+
+  int num_cpus() const { return num_cpus_; }
+
+  const SpeedLimitUpdateCallback callback_;
+
+  // Periodically calls OnTimerTick() where a new speed-limit metric is
+  // calculated. The timer is cancelled once this object is destroyed.
+  base::RepeatingTimer timer_;
+  // Number of logical cores in the existing physical processor.
+  // Example: a processor with 6 cores which supports hyperthreading has 12
+  // logical cores, hence `num_cpus_` equals 12 in this case.
+  const int num_cpus_;
+  // A simple MA filter of size 10 is used to smooth out the speed-limit
+  // value and to remove noise from short spikes in CPU load. The existing
+  // sample rate is one sample per seconds but the existing choice is rather
+  // ad-hoc and not based on any deeper analysis into exact frequency
+  // characteristics of the underlying process.
+  MovingAverage moving_average_;
+  // Max speed-limit value is 100 (%) and it is also used in cases where the
+  // native Windows API(s) fail.
+  int speed_limit_ = PowerThermalObserver::kSpeedLimitMax;
+};
+
+}  // namespace base
+
+#endif  // BASE_POWER_MONITOR_SPEED_LIMIT_OBSERVER_WIN_H_
diff --git a/base/system/sys_info.h b/base/system/sys_info.h
index b662b44..26ac933a 100644
--- a/base/system/sys_info.h
+++ b/base/system/sys_info.h
@@ -24,6 +24,7 @@
 FORWARD_DECLARE_TEST(SystemMetricsTest, ParseMeminfo);
 }
 
+class CommandLine;
 class FilePath;
 struct SystemMemoryInfoKB;
 
@@ -68,6 +69,21 @@
   // on failure.
   static int64_t AmountOfTotalDiskSpace(const FilePath& path);
 
+#if defined(OS_CHROMEOS)
+  // On ChromeOS, spaced is the central source-of-truth for disk space
+  // information. Spaced takes into account the available extents on the
+  // underlying thinpool to make sure that thinly provisioned filesystems
+  // return only the available physical extents as the free space.
+  //
+  // Return the available disk space in bytes on the volume containing |path|,
+  // or -1 on failure.
+  static int64_t GetFreeDiskSpaceFromSpaced(const FilePath& path);
+
+  // Return the total disk space in bytes on the volume containing |path|, or -1
+  // on failure.
+  static int64_t GetTotalDiskSpaceFromSpaced(const FilePath& path);
+#endif
+
 #if defined(OS_FUCHSIA)
   // Sets the total amount of disk space to report under the specified |path|.
   // If |bytes| is -ve then any existing entry for |path| is removed.
@@ -169,6 +185,14 @@
   // Undoes the function above.
   static void ResetChromeOSVersionInfoForTest();
 
+  // Overrides the command runner for running commands. Overrides cannot be
+  // nested. Users must call SetChromeOSGetAppOutputForTest(nullptr) to revert
+  // the test function.
+  using GetAppOutputCallback =
+      RepeatingCallback<bool(const CommandLine&, std::string*)>;
+
+  static void SetChromeOSGetAppOutputForTest(GetAppOutputCallback* callback);
+
   // Returns the kernel version of the host operating system.
   static std::string KernelVersion();
 
diff --git a/base/system/sys_info_chromeos.cc b/base/system/sys_info_chromeos.cc
index 188552e..5c1cfa87 100644
--- a/base/system/sys_info_chromeos.cc
+++ b/base/system/sys_info_chromeos.cc
@@ -8,6 +8,8 @@
 #include <stdint.h>
 #include <sys/utsname.h>
 
+#include "base/callback.h"
+#include "base/command_line.h"
 #include "base/cxx17_backports.h"
 #include "base/environment.h"
 #include "base/files/file.h"
@@ -15,6 +17,7 @@
 #include "base/files/file_util.h"
 #include "base/no_destructor.h"
 #include "base/notreached.h"
+#include "base/process/launch.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
@@ -46,6 +49,10 @@
 const char kLsbReleaseSourceEnv[] = "env";
 const char kLsbReleaseSourceFile[] = "file";
 
+const char kSpacedCliPath[] = "/usr/sbin/spaced_cli";
+const char kSpacedGetFreeDiskSpaceAction[] = "get_free_disk_space";
+const char kSpacedGetTotalDiskSpaceAction[] = "get_total_disk_space";
+
 class ChromeOSVersionInfo {
  public:
   ChromeOSVersionInfo() {
@@ -168,6 +175,28 @@
   return *version_info;
 }
 
+SysInfo::GetAppOutputCallback* g_chromeos_get_app_output_for_test = nullptr;
+
+int64_t GetInfoFromSpaced(StringPiece action, const base::FilePath& path) {
+  CommandLine command((base::FilePath(kSpacedCliPath)));
+  command.AppendSwitchPath(action, path);
+
+  std::string output;
+  bool ret;
+  if (g_chromeos_get_app_output_for_test) {
+    ret = g_chromeos_get_app_output_for_test->Run(command, &output);
+  } else {
+    ret = GetAppOutput(command, &output);
+  }
+
+  int64_t result;
+  if (!ret || !StringToInt64(output, &result) || result < 0) {
+    return -1;
+  }
+
+  return result;
+}
+
 }  // namespace
 
 // static
@@ -249,6 +278,11 @@
 }
 
 // static
+void SysInfo::SetChromeOSGetAppOutputForTest(GetAppOutputCallback* callback) {
+  g_chromeos_get_app_output_for_test = callback;
+}
+
+// static
 void SysInfo::CrashIfChromeOSNonTestImage() {
   if (!IsRunningOnChromeOS())
     return;
@@ -265,4 +299,14 @@
   CHECK_NE(track.find(kTestImageRelease), std::string::npos);
 }
 
+// static
+int64_t SysInfo::GetFreeDiskSpaceFromSpaced(const base::FilePath& path) {
+  return GetInfoFromSpaced(kSpacedGetFreeDiskSpaceAction, path);
+}
+
+// static
+int64_t SysInfo::GetTotalDiskSpaceFromSpaced(const base::FilePath& path) {
+  return GetInfoFromSpaced(kSpacedGetTotalDiskSpaceAction, path);
+}
+
 }  // namespace base
diff --git a/base/system/sys_info_posix.cc b/base/system/sys_info_posix.cc
index 672c72f..3507eb9 100644
--- a/base/system/sys_info_posix.cc
+++ b/base/system/sys_info_posix.cc
@@ -158,10 +158,16 @@
 int64_t SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::MAY_BLOCK);
+#if defined(OS_CHROMEOS)
+  int64_t ret = GetFreeDiskSpaceFromSpaced(path);
+  if (ret != -1)
+    return ret;
+#endif
 
   int64_t available;
   if (!GetDiskSpaceInfo(path, &available, nullptr))
     return -1;
+
   return available;
 }
 
@@ -170,9 +176,16 @@
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::MAY_BLOCK);
 
+#if defined(OS_CHROMEOS)
+  int64_t ret = GetTotalDiskSpaceFromSpaced(path);
+  if (ret != -1)
+    return ret;
+#endif
+
   int64_t total;
   if (!GetDiskSpaceInfo(path, nullptr, &total))
     return -1;
+
   return total;
 }
 
diff --git a/base/system/sys_info_unittest.cc b/base/system/sys_info_unittest.cc
index 7ca1c13f..a9cddb0 100644
--- a/base/system/sys_info_unittest.cc
+++ b/base/system/sys_info_unittest.cc
@@ -422,6 +422,54 @@
   EXPECT_EQ(was_running, SysInfo::IsRunningOnChromeOS());
 }
 
+SysInfo::GetAppOutputCallback MockGetAppOutputTestCallback(
+    const std::string& mock_output,
+    bool mock_ret) {
+  return BindRepeating(
+      [](const std::string& expected_output, bool return_value,
+         const CommandLine& cl, std::string* out) -> bool {
+        *out = expected_output;
+        return return_value;
+      },
+      mock_output, mock_ret);
+}
+
+TEST_F(SysInfoTest, SpacedValidQuery) {
+  FilePath dummy_path("/a/b/c");
+  auto mock_get_app_output = MockGetAppOutputTestCallback("1234", true);
+  SysInfo::SetChromeOSGetAppOutputForTest(&mock_get_app_output);
+  EXPECT_EQ(SysInfo::GetTotalDiskSpaceFromSpaced(dummy_path), 1234);
+  EXPECT_EQ(SysInfo::GetFreeDiskSpaceFromSpaced(dummy_path), 1234);
+  SysInfo::SetChromeOSGetAppOutputForTest(nullptr);
+}
+
+TEST_F(SysInfoTest, SpacedInternalFailure) {
+  FilePath dummy_path("/a/b/c");
+  auto mock_get_app_output = MockGetAppOutputTestCallback("-1", true);
+  SysInfo::SetChromeOSGetAppOutputForTest(&mock_get_app_output);
+  EXPECT_EQ(SysInfo::GetTotalDiskSpaceFromSpaced(dummy_path), -1);
+  EXPECT_EQ(SysInfo::GetFreeDiskSpaceFromSpaced(dummy_path), -1);
+  SysInfo::SetChromeOSGetAppOutputForTest(nullptr);
+}
+
+TEST_F(SysInfoTest, SpacedFailedInvocation) {
+  FilePath dummy_path("/a/b/c");
+  auto mock_get_app_output = MockGetAppOutputTestCallback("5", false);
+  SysInfo::SetChromeOSGetAppOutputForTest(&mock_get_app_output);
+  EXPECT_EQ(SysInfo::GetTotalDiskSpaceFromSpaced(dummy_path), -1);
+  EXPECT_EQ(SysInfo::GetFreeDiskSpaceFromSpaced(dummy_path), -1);
+  SysInfo::SetChromeOSGetAppOutputForTest(nullptr);
+}
+
+TEST_F(SysInfoTest, SpacedInvalidOutput) {
+  FilePath dummy_path("/a/b/c");
+  auto mock_get_app_output = MockGetAppOutputTestCallback("foo", true);
+  SysInfo::SetChromeOSGetAppOutputForTest(&mock_get_app_output);
+  EXPECT_EQ(SysInfo::GetTotalDiskSpaceFromSpaced(dummy_path), -1);
+  EXPECT_EQ(SysInfo::GetFreeDiskSpaceFromSpaced(dummy_path), -1);
+  SysInfo::SetChromeOSGetAppOutputForTest(nullptr);
+}
+
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
 
 }  // namespace base
diff --git a/base/test/task_environment.cc b/base/test/task_environment.cc
index 1d08bd8..0f20f6b4 100644
--- a/base/test/task_environment.cc
+++ b/base/test/task_environment.cc
@@ -463,15 +463,27 @@
 
 TaskEnvironment::~TaskEnvironment() {
   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DestroyTaskEnvironment();
+}
 
-  // If we've been moved then bail out.
+void TaskEnvironment::DestroyTaskEnvironment() {
+  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+
+  // If we've been moved or already destroyed (i.e. subclass invoked
+  // DestroyTaskEnvironment() before ~TaskEnvironment()) then bail out.
   if (!owns_instance_)
     return;
+  owns_instance_.reset();
+
   for (auto& observer : GetDestructionObservers())
     observer.WillDestroyCurrentTaskEnvironment();
+
   DestroyThreadPool();
   task_queue_ = nullptr;
-  NotifyDestructionObserversAndReleaseSequenceManager();
+  // SequenceManagerImpl must outlive ThreadPoolInstance() (DestroyThreadPool()
+  // above) as TaskEnvironment::MockTimeDomain can invoke its
+  // SequenceManagerImpl* from worker threads.
+  sequence_manager_.reset();
 }
 
 void TaskEnvironment::DestroyThreadPool() {
@@ -479,6 +491,7 @@
 
   if (threading_mode_ == ThreadingMode::MAIN_THREAD_ONLY)
     return;
+  DCHECK(ThreadPoolInstance::Get());
 
   // Ideally this would RunLoop().RunUntilIdle() here to catch any errors or
   // infinite post loop in the remaining work but this isn't possible right now
@@ -516,16 +529,6 @@
   CompleteInitialization();
 }
 
-void TaskEnvironment::NotifyDestructionObserversAndReleaseSequenceManager() {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
-
-  // A derived classes may call this method early.
-  if (!sequence_manager_)
-    return;
-
-  sequence_manager_.reset();
-}
-
 scoped_refptr<base::SingleThreadTaskRunner>
 TaskEnvironment::GetMainThreadTaskRunner() {
   DCHECK(task_runner_);
diff --git a/base/test/task_environment.h b/base/test/task_environment.h
index e29bf6a..bf29692 100644
--- a/base/test/task_environment.h
+++ b/base/test/task_environment.h
@@ -363,8 +363,10 @@
   void DeferredInitFromSubclass(
       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
-  // Derived classes may need to control when the sequence manager goes away.
-  void NotifyDestructionObserversAndReleaseSequenceManager();
+  // Derived classes may need to control when the task environment goes away
+  // (e.g. ~FooTaskEnvironment() may want to effectively trigger
+  // ~TaskEnvironment() before its members are destroyed).
+  void DestroyTaskEnvironment();
 
  private:
   class MockTimeDomain;
diff --git a/base/threading/sequence_bound.h b/base/threading/sequence_bound.h
index a39b882..156972df 100644
--- a/base/threading/sequence_bound.h
+++ b/base/threading/sequence_bound.h
@@ -38,7 +38,7 @@
   }
 
   template <typename T>
-  static inline auto Unretained(T* ptr) {
+  static inline auto Unretained(T ptr) {
     return base::Unretained(ptr);
   }
 
diff --git a/base/win/shortcut_unittest.cc b/base/win/shortcut_unittest.cc
index a6775baa7..c6dbf47f 100644
--- a/base/win/shortcut_unittest.cc
+++ b/base/win/shortcut_unittest.cc
@@ -188,7 +188,14 @@
   ValidateShortcut(link_file_, link_properties_);
 }
 
-TEST_F(ShortcutTest, UpdateShortcutVerifyProperties) {
+// TODO(crbug.com/1271993): Flaky on Win7 x86.
+#if defined(OS_WIN) && defined(ARCH_CPU_X86)
+#define MAYBE_UpdateShortcutVerifyProperties \
+  DISABLED_UpdateShortcutVerifyProperties
+#else
+#define MAYBE_UpdateShortcutVerifyProperties UpdateShortcutVerifyProperties
+#endif
+TEST_F(ShortcutTest, MAYBE_UpdateShortcutVerifyProperties) {
   ASSERT_TRUE(CreateOrUpdateShortcutLink(link_file_, link_properties_,
                                          SHORTCUT_CREATE_ALWAYS));
 
@@ -225,8 +232,12 @@
   EXPECT_STREQ(kFileContents2, read_contents);
 }
 
-// Flaky test: crbug.com/1270603.
-TEST_F(ShortcutTest, DISABLED_UpdateShortcutMakeDualMode) {
+TEST_F(ShortcutTest, UpdateShortcutMakeDualMode) {
+  // This test is extremely flaky on Win7, so disable.
+  // TODO(crbug.com/1264563): Investigate why it's so flaky on Win7 bots.
+  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
+    GTEST_SKIP() << "Skipping test for win7";
+
   ASSERT_TRUE(CreateOrUpdateShortcutLink(link_file_, link_properties_,
                                          SHORTCUT_CREATE_ALWAYS));
 
diff --git a/base/win/windows_types.h b/base/win/windows_types.h
index 773fd6c3..c126f7e 100644
--- a/base/win/windows_types.h
+++ b/base/win/windows_types.h
@@ -131,6 +131,10 @@
 typedef struct _WIN32_FIND_DATAW WIN32_FIND_DATAW;
 typedef WIN32_FIND_DATAW WIN32_FIND_DATA;
 
+typedef UINT_PTR SOCKET;
+typedef struct _PROCESS_INFORMATION PROCESS_INFORMATION;
+typedef struct _SECURITY_CAPABILITIES SECURITY_CAPABILITIES;
+
 // Declare Chrome versions of some Windows structures. These are needed for
 // when we need a concrete type but don't want to pull in Windows.h. We can't
 // declare the Windows types so we declare our types and cast to the Windows
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn
index ed94a16a0..3927f096 100644
--- a/build/config/BUILD.gn
+++ b/build/config/BUILD.gn
@@ -75,9 +75,6 @@
     # setting use_ozone globally.
     defines += [ "USE_OZONE=1" ]
   }
-  if (use_x11) {
-    defines += [ "USE_X11=1" ]
-  }
   if (is_asan || is_hwasan || is_lsan || is_tsan || is_msan) {
     defines += [ "MEMORY_TOOL_REPLACES_ALLOCATOR" ]
   }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index cce154c..b56ce308 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-7.20211119.1.1
+7.20211121.3.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index cce154c..b56ce308 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-7.20211119.1.1
+7.20211121.3.1
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn
index 0034c8abd..cde8170 100644
--- a/build/toolchain/win/BUILD.gn
+++ b/build/toolchain/win/BUILD.gn
@@ -345,7 +345,7 @@
         }
 
         tool("rust_macro") {
-          rust_outfile = "{{target_out_dir}}/lib{{crate_name}}.dll"
+          rust_outfile = "{{target_out_dir}}/{{crate_name}}.dll"
           depfile = "{{crate_name}}.d"
           command = "${rust_prefix}/rustc $rustc_common_args --emit=dep-info={{target_out_dir}}/$depfile,link -o $rust_outfile"
           description = "RUST $rust_outfile"
diff --git a/cc/layers/heads_up_display_layer.cc b/cc/layers/heads_up_display_layer.cc
index a9c4e6a..41fd7b4 100644
--- a/cc/layers/heads_up_display_layer.cc
+++ b/cc/layers/heads_up_display_layer.cc
@@ -34,30 +34,36 @@
     const gfx::Size& device_viewport,
     float device_scale_factor) {
   DCHECK(IsMutationAllowed());
-  gfx::Size device_viewport_in_layout_pixels =
-      gfx::Size(device_viewport.width() / device_scale_factor,
-                device_viewport.height() / device_scale_factor);
+  float multiplier = 1.f / (device_scale_factor *
+                            layer_tree_host()->painted_device_scale_factor());
+  gfx::Size device_viewport_in_dips =
+      gfx::ScaleToFlooredSize(device_viewport, multiplier);
 
-  gfx::Size bounds;
+  gfx::Size bounds_in_dips;
 
   // If the HUD is not displaying full-viewport rects (e.g., it is showing the
   // Frame Rendering Stats), use a fixed size.
   constexpr int kDefaultHUDSize = 256;
-  bounds.SetSize(kDefaultHUDSize, kDefaultHUDSize);
+  bounds_in_dips.SetSize(kDefaultHUDSize, kDefaultHUDSize);
 
   if (layer_tree_host()->GetDebugState().ShowDebugRects()) {
-    bounds = device_viewport_in_layout_pixels;
+    bounds_in_dips = device_viewport_in_dips;
   } else if (layer_tree_host()->GetDebugState().show_web_vital_metrics ||
              layer_tree_host()->GetDebugState().show_smoothness_metrics) {
     // If the HUD is used to display performance metrics (which is on the right
     // hand side_, make sure the bounds has the correct width, with a fixed
     // height.
-    bounds.set_width(device_viewport_in_layout_pixels.width());
+    bounds_in_dips.set_width(device_viewport_in_dips.width());
     // Increase HUD layer height to make sure all the metrics are showing.
-    bounds.set_height(kDefaultHUDSize * 2);
+    bounds_in_dips.set_height(kDefaultHUDSize * 2);
   }
 
-  SetBounds(bounds);
+  // DIPs are layout coordinates if painted dsf is 1. If it's not 1, then layout
+  // coordinates are DIPs * painted dsf.
+  auto bounds_in_layout_space = gfx::ScaleToCeiledSize(
+      bounds_in_dips, layer_tree_host()->painted_device_scale_factor());
+
+  SetBounds(bounds_in_layout_space);
 }
 
 bool HeadsUpDisplayLayer::HasDrawableContent() const {
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index 53f25af..4b506ed2 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -632,7 +632,10 @@
   TRACE_EVENT0("cc", "DrawHudContents");
   canvas->clear(SkColorSetARGB(0, 0, 0, 0));
   canvas->save();
-  canvas->scale(internal_contents_scale_, internal_contents_scale_);
+  canvas->scale(internal_contents_scale_);
+  // Our output should be in layout space, but all of the draw commands here are
+  // in dips. Scale the canvas to account for this difference.
+  canvas->scale(layer_tree_impl()->painted_device_scale_factor());
 
   if (debug_state.ShowDebugRects()) {
     DrawDebugRects(canvas, layer_tree_impl()->debug_rect_history());
@@ -662,13 +665,13 @@
 
   // For the web vital and smoothness HUD on the top right corner, if the width
   // of the screen is smaller than the default width of the HUD, scale it down.
-  if (bounds().width() < metrics_sizes.kWidth) {
-    double scale_to_bounds = static_cast<double>(bounds().width()) /
+  if (bounds_width_in_dips() < metrics_sizes.kWidth) {
+    double scale_to_bounds = static_cast<double>(bounds_width_in_dips()) /
                              static_cast<double>(metrics_sizes.kWidth);
     canvas->scale(scale_to_bounds, scale_to_bounds);
   }
   SkRect metrics_area = SkRect::MakeXYWH(
-      std::max<SkScalar>(0, bounds().width() - metrics_sizes.kWidth), 0,
+      std::max<SkScalar>(0, bounds_width_in_dips() - metrics_sizes.kWidth), 0,
       metrics_sizes.kWidth, 0);
   if (debug_state.show_web_vital_metrics) {
     metrics_area = DrawWebVitalMetrics(
diff --git a/cc/layers/heads_up_display_layer_impl.h b/cc/layers/heads_up_display_layer_impl.h
index 211915e..9b52341 100644
--- a/cc/layers/heads_up_display_layer_impl.h
+++ b/cc/layers/heads_up_display_layer_impl.h
@@ -17,6 +17,7 @@
 #include "cc/resources/memory_history.h"
 #include "cc/resources/resource_pool.h"
 #include "cc/trees/debug_rect_history.h"
+#include "cc/trees/layer_tree_impl.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 
 class SkTypeface;
@@ -163,6 +164,12 @@
                                int top,
                                int width) const;
 
+  int bounds_width_in_dips() const {
+    // bounds() is specified in layout coordinates, which is painted dsf away
+    // from DIPs.
+    return bounds().width() / layer_tree_impl()->painted_device_scale_factor();
+  }
+
   ResourcePool::InUsePoolResource in_flight_resource_;
   std::unique_ptr<ResourcePool> pool_;
   viz::DrawQuad* current_quad_ = nullptr;
diff --git a/cc/layers/heads_up_display_unittest.cc b/cc/layers/heads_up_display_unittest.cc
index 20b6f21..3eed236 100644
--- a/cc/layers/heads_up_display_unittest.cc
+++ b/cc/layers/heads_up_display_unittest.cc
@@ -97,6 +97,29 @@
 
 SINGLE_AND_MULTI_THREAD_TEST_F(HeadsUpDisplaySizeWithFPS);
 
+class HeadsUpDisplaySizeWithFPSAndZoomForDSF : public LayerTreeTest {
+ public:
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->use_painted_device_scale_factor = true;
+    settings->initial_debug_state.show_fps_counter = true;
+  }
+
+  void SetupTree() override {
+    SetInitialDeviceScaleFactor(3.f);
+    LayerTreeTest::SetupTree();
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void DidCommit() override {
+    ASSERT_TRUE(layer_tree_host()->hud_layer());
+    EXPECT_EQ(gfx::Size(768, 768), layer_tree_host()->hud_layer()->bounds());
+    EndTest();
+  }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(HeadsUpDisplaySizeWithFPSAndZoomForDSF);
+
 class HeadsUpDisplaySizeWithMetrics : public LayerTreeTest {
  public:
   void InitializeSettings(LayerTreeSettings* settings) override {
diff --git a/cc/paint/paint_canvas.h b/cc/paint/paint_canvas.h
index a3e7cd5..5f99d01 100644
--- a/cc/paint/paint_canvas.h
+++ b/cc/paint/paint_canvas.h
@@ -79,6 +79,7 @@
   virtual void restoreToCount(int save_count) = 0;
   virtual void translate(SkScalar dx, SkScalar dy) = 0;
   virtual void scale(SkScalar sx, SkScalar sy) = 0;
+  void scale(SkScalar s) { scale(s, s); }
   virtual void rotate(SkScalar degrees) = 0;
   // TODO(aaronhk): crbug.com/1153330 deprecate these in favor of the SkM44
   // versions.
diff --git a/cc/tiles/picture_layer_tiling.cc b/cc/tiles/picture_layer_tiling.cc
index 58f0f0c..8090d64a 100644
--- a/cc/tiles/picture_layer_tiling.cc
+++ b/cc/tiles/picture_layer_tiling.cc
@@ -509,7 +509,7 @@
     // unexpectedly. Unfortunately, there isn't much we can do at this point, so
     // we just do the correctness checks if both y and x offsets are
     // 'reasonable', meaning they are less than the specified value.
-    static constexpr int kReasonableOffsetForDcheck = 500'000'000;
+    static constexpr int kReasonableOffsetForDcheck = 100'000'000;
     if (!new_row && current_geometry_rect_.x() <= kReasonableOffsetForDcheck &&
         current_geometry_rect_.y() <= kReasonableOffsetForDcheck) {
       DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x());
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index e523ff3..2fce4b3 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -516,6 +516,9 @@
   float device_scale_factor() const {
     return pending_commit_state()->device_scale_factor;
   }
+  float painted_device_scale_factor() const {
+    return pending_commit_state()->painted_device_scale_factor;
+  }
 
   void SetRecordingScaleFactor(float recording_scale_factor);
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 122794d..e891d7f 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=98
 MINOR=0
-BUILD=4715
+BUILD=4723
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index d4daf37..09a13f2 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -383,6 +383,7 @@
     "//chrome/browser/password_check:public_java",
     "//chrome/browser/password_entry_edit:public_java",
     "//chrome/browser/password_manager/android:java",
+    "//chrome/browser/password_manager/android:settings_interface_java",
     "//chrome/browser/performance_hints/android:java",
     "//chrome/browser/policy/android:java",
     "//chrome/browser/power_bookmarks:proto_java",
@@ -419,6 +420,7 @@
     "//chrome/browser/ui/android/native_page:java",
     "//chrome/browser/ui/android/night_mode:java",
     "//chrome/browser/ui/android/omnibox:java",
+    "//chrome/browser/ui/android/page_info:java",
     "//chrome/browser/ui/android/quickactionsearchwidget:java",
     "//chrome/browser/ui/android/searchactivityutils:java",
     "//chrome/browser/ui/android/signin:java",
@@ -1118,6 +1120,7 @@
     "//third_party/android_deps:dagger_java",
     "//third_party/android_deps:espresso_java",
     "//third_party/android_deps:guava_android_java",
+    "//third_party/android_deps:material_design_java",
     "//third_party/android_deps:protobuf_lite_runtime_java",
     "//third_party/android_support_test_runner:rules_java",
     "//third_party/android_support_test_runner:runner_java",
@@ -1403,6 +1406,7 @@
     "//chrome/browser/ui/android/night_mode:javatests",
     "//chrome/browser/ui/android/night_mode:night_mode_java_test_support",
     "//chrome/browser/ui/android/omnibox:java",
+    "//chrome/browser/ui/android/page_info:java",
     "//chrome/browser/ui/android/quickactionsearchwidget:java",
     "//chrome/browser/ui/android/quickactionsearchwidget:javatests",
     "//chrome/browser/ui/android/searchactivityutils:java",
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index 191fb84..fc382c7 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -95,8 +95,6 @@
   "java/res/drawable-hdpi/tabswitcher_border_frame_decoration.9.png",
   "java/res/drawable-hdpi/tabswitcher_border_frame_inner_shadow.9.png",
   "java/res/drawable-hdpi/tabswitcher_border_frame_shadow.9.png",
-  "java/res/drawable-hdpi/toolbar_shadow_focused.png",
-  "java/res/drawable-hdpi/toolbar_shadow_normal.png",
   "java/res/drawable-hdpi/troy_card.png",
   "java/res/drawable-hdpi/unionpay_card.png",
   "java/res/drawable-hdpi/verify_checkmark.png",
@@ -191,8 +189,6 @@
   "java/res/drawable-mdpi/tabswitcher_border_frame_decoration.9.png",
   "java/res/drawable-mdpi/tabswitcher_border_frame_inner_shadow.9.png",
   "java/res/drawable-mdpi/tabswitcher_border_frame_shadow.9.png",
-  "java/res/drawable-mdpi/toolbar_shadow_focused.png",
-  "java/res/drawable-mdpi/toolbar_shadow_normal.png",
   "java/res/drawable-mdpi/troy_card.png",
   "java/res/drawable-mdpi/unionpay_card.png",
   "java/res/drawable-mdpi/verify_checkmark.png",
@@ -203,7 +199,6 @@
   "java/res/drawable-sw600dp-xhdpi/google_logo.png",
   "java/res/drawable-sw600dp-xxhdpi/google_logo.png",
   "java/res/drawable-sw600dp-xxxhdpi/google_logo.png",
-  "java/res/drawable-sw600dp/toolbar_shadow.xml",
   "java/res/drawable-sw600dp/window_background.xml",
   "java/res/drawable-v21/button_borderless_compat.xml",
   "java/res/drawable-v21/text_cursor_lowend.xml",
@@ -288,8 +283,6 @@
   "java/res/drawable-xhdpi/tabswitcher_border_frame_decoration.9.png",
   "java/res/drawable-xhdpi/tabswitcher_border_frame_inner_shadow.9.png",
   "java/res/drawable-xhdpi/tabswitcher_border_frame_shadow.9.png",
-  "java/res/drawable-xhdpi/toolbar_shadow_focused.png",
-  "java/res/drawable-xhdpi/toolbar_shadow_normal.png",
   "java/res/drawable-xhdpi/troy_card.png",
   "java/res/drawable-xhdpi/unionpay_card.png",
   "java/res/drawable-xhdpi/verify_checkmark.png",
@@ -367,8 +360,6 @@
   "java/res/drawable-xxhdpi/tabswitcher_border_frame_decoration.9.png",
   "java/res/drawable-xxhdpi/tabswitcher_border_frame_inner_shadow.9.png",
   "java/res/drawable-xxhdpi/tabswitcher_border_frame_shadow.9.png",
-  "java/res/drawable-xxhdpi/toolbar_shadow_focused.png",
-  "java/res/drawable-xxhdpi/toolbar_shadow_normal.png",
   "java/res/drawable-xxhdpi/troy_card.png",
   "java/res/drawable-xxhdpi/unionpay_card.png",
   "java/res/drawable-xxhdpi/verify_checkmark.png",
@@ -443,8 +434,6 @@
   "java/res/drawable-xxxhdpi/tabswitcher_border_frame_decoration.9.png",
   "java/res/drawable-xxxhdpi/tabswitcher_border_frame_inner_shadow.9.png",
   "java/res/drawable-xxxhdpi/tabswitcher_border_frame_shadow.9.png",
-  "java/res/drawable-xxxhdpi/toolbar_shadow_focused.png",
-  "java/res/drawable-xxxhdpi/toolbar_shadow_normal.png",
   "java/res/drawable-xxxhdpi/troy_card.png",
   "java/res/drawable-xxxhdpi/unionpay_card.png",
   "java/res/drawable-xxxhdpi/verify_checkmark.png",
@@ -548,7 +537,6 @@
   "java/res/drawable/thumbnail_gradient_top_left.xml",
   "java/res/drawable/thumbnail_gradient_top_right.xml",
   "java/res/drawable/tile_view_hairline_border_background.xml",
-  "java/res/drawable/toolbar_shadow.xml",
   "java/res/drawable/visa_card.xml",
   "java/res/layout-sw360dp/preference_spinner_single_line.xml",
   "java/res/layout-sw600dp/find_toolbar.xml",
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java
index 3342937..d5d9059 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java
@@ -21,6 +21,7 @@
 import org.chromium.chrome.browser.autofill_assistant.user_data.additional_sections.AssistantTextInputSection.TextInputFactory;
 import org.chromium.chrome.browser.autofill_assistant.user_data.additional_sections.AssistantTextInputType;
 import org.chromium.chrome.browser.payments.AutofillAddress;
+import org.chromium.chrome.browser.payments.AutofillAddress.CompletenessCheckType;
 import org.chromium.chrome.browser.payments.AutofillContact;
 import org.chromium.chrome.browser.payments.AutofillPaymentInstrument;
 import org.chromium.chrome.browser.payments.ContactEditor;
@@ -671,7 +672,7 @@
         if (profile == null) {
             return null;
         }
-        return new AutofillAddress(context, profile);
+        return new AutofillAddress(context, profile, CompletenessCheckType.IGNORE_PHONE);
     }
 
     @CalledByNative
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantPaymentMethodSection.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantPaymentMethodSection.java
index 09e3f98..94c3205 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantPaymentMethodSection.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantPaymentMethodSection.java
@@ -22,6 +22,7 @@
 import org.chromium.chrome.browser.autofill.settings.CardEditor;
 import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataModel.PaymentInstrumentModel;
 import org.chromium.chrome.browser.payments.AutofillAddress;
+import org.chromium.chrome.browser.payments.AutofillAddress.CompletenessCheckType;
 import org.chromium.chrome.browser.payments.AutofillPaymentInstrument;
 
 import java.util.List;
@@ -53,7 +54,8 @@
         for (PaymentInstrumentModel item : getItems()) {
             AutofillProfile profile = item.mOption.getBillingProfile();
             if (profile != null) {
-                addAutocompleteInformationToEditor(new AutofillAddress(mContext, profile));
+                addAutocompleteInformationToEditor(
+                        new AutofillAddress(mContext, profile, CompletenessCheckType.IGNORE_PHONE));
             }
         }
     }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataTestHelper.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataTestHelper.java
index a377b291..4b107c0 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataTestHelper.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataTestHelper.java
@@ -270,8 +270,8 @@
         return new PersonalDataManager.AutofillProfile(/* guid= */ "", "https://www.example.com",
                 /* honorificPrefix= */ "", fullName, "Acme Inc.", "123 Main", "California",
                 "Los Angeles",
-                /* dependentLocality= */ "", postcode, /* sortingCode= */ "", "UZ", "555 123-4567",
-                email, /* languageCode= */ "");
+                /* dependentLocality= */ "", postcode, /* sortingCode= */ "", "UZ",
+                /* phoneNumber= */ "", email, /* languageCode= */ "");
     }
 
     /**
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantInterruptIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantInterruptIntegrationTest.java
index bd00f11..75ad2c31 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantInterruptIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantInterruptIntegrationTest.java
@@ -39,12 +39,15 @@
 import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantTestService.ScriptsReturnMode;
 import org.chromium.chrome.browser.autofill_assistant.proto.ActionProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.AutofillFormatProto;
+import org.chromium.chrome.browser.autofill_assistant.proto.BooleanNotProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.CallbackProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ChipProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ChipType;
 import org.chromium.chrome.browser.autofill_assistant.proto.ComputeValueProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ConfigureUiStateProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ConfigureUiStateProto.OverlayBehavior;
+import org.chromium.chrome.browser.autofill_assistant.proto.ElementAreaProto;
+import org.chromium.chrome.browser.autofill_assistant.proto.ElementAreaProto.Rectangle;
 import org.chromium.chrome.browser.autofill_assistant.proto.ElementConditionProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ElementConditionsProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.EndActionProto;
@@ -61,7 +64,10 @@
 import org.chromium.chrome.browser.autofill_assistant.proto.ScriptPreconditionProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.SelectorProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.SetUserActionsProto;
+import org.chromium.chrome.browser.autofill_assistant.proto.ShowCastProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ShowGenericUiProto;
+import org.chromium.chrome.browser.autofill_assistant.proto.ShowGenericUiProto.PeriodicElementChecks;
+import org.chromium.chrome.browser.autofill_assistant.proto.ShowGenericUiProto.PeriodicElementChecks.ElementCheck;
 import org.chromium.chrome.browser.autofill_assistant.proto.StringList;
 import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto.PresentationProto;
@@ -651,4 +657,167 @@
         onView(withText("Continue")).perform(click());
         waitUntilViewMatchesCondition(withText("End"), isDisplayingAtLeast(90));
     }
+
+    @Test
+    @MediumTest
+    public void testStateRestoredAfterInterrupt() throws Exception {
+        ArrayList<AutofillAssistantTestScript> scripts = new ArrayList<>();
+        SelectorProto touch_area_one = toCssSelector("#touch_area_one");
+        SelectorProto touch_area_four = toCssSelector("#touch_area_four");
+        SelectorProto touch_area_three = toCssSelector("#touch_area_three");
+
+        ArrayList<ActionProto> list = new ArrayList<>();
+        list.add(ActionProto.newBuilder()
+                         .setShowCast(
+                                 ShowCastProto.newBuilder()
+                                         .setElementToPresent(touch_area_one)
+                                         .setTouchableElementArea(
+                                                 ElementAreaProto.newBuilder().addTouchable(
+                                                         Rectangle.newBuilder()
+                                                                 .addElements(touch_area_one)
+                                                                 .addElements(touch_area_four)
+                                                                 .addElements(touch_area_three))))
+                         .build());
+
+        List<InteractionProto> interactions = new ArrayList<>();
+        interactions.add(
+                InteractionProto.newBuilder()
+                        .addTriggerEvent(EventProto.newBuilder().setOnValueChanged(
+                                OnModelValueChangedEventProto.newBuilder().setModelIdentifier(
+                                        "chips")))
+                        .addCallbacks(CallbackProto.newBuilder().setSetUserActions(
+                                SetUserActionsProto.newBuilder().setUserActions(
+                                        ValueReferenceProto.newBuilder().setModelIdentifier(
+                                                "chips"))))
+                        .build());
+        // When element three disappears, the ShowGenericUiAction ends.
+        CallbackProto notCallback =
+                CallbackProto.newBuilder()
+                        .setComputeValue(
+                                ComputeValueProto.newBuilder()
+                                        .setBooleanNot(BooleanNotProto.newBuilder().setValue(
+                                                ValueReferenceProto.newBuilder().setModelIdentifier(
+                                                        "touch_area_three_present")))
+                                        .setResultModelIdentifier("end_action"))
+                        .build();
+        interactions.add(
+                InteractionProto.newBuilder()
+                        .addTriggerEvent(EventProto.newBuilder().setOnValueChanged(
+                                OnModelValueChangedEventProto.newBuilder().setModelIdentifier(
+                                        "touch_area_three_present")))
+                        .addCallbacks(notCallback)
+                        .build());
+        interactions.add(
+                InteractionProto.newBuilder()
+                        .addTriggerEvent(EventProto.newBuilder().setOnValueChanged(
+                                OnModelValueChangedEventProto.newBuilder().setModelIdentifier(
+                                        "end_action")))
+                        .addCallbacks(CallbackProto.newBuilder()
+                                              .setEndAction(EndActionProto.newBuilder().setStatus(
+                                                      ProcessedActionStatusProto.ACTION_APPLIED))
+                                              .setConditionModelIdentifier("end_action"))
+                        .build());
+
+        List<ModelProto.ModelValue> modelValues = new ArrayList<>();
+        modelValues.add(
+                ModelProto.ModelValue.newBuilder()
+                        .setIdentifier("chips")
+                        .setValue(ValueProto.newBuilder().setUserActions(
+                                UserActionList.newBuilder().addValues(
+                                        UserActionProto.newBuilder()
+                                                .setChip(ChipProto.newBuilder()
+                                                                 .setText("Done")
+                                                                 .setType(ChipType.NORMAL_ACTION))
+                                                .setIdentifier("done_chip"))))
+                        .build());
+
+        ElementCheck touch_area_three_present =
+                ElementCheck.newBuilder()
+                        .setModelIdentifier("touch_area_three_present")
+                        .setElementCondition(
+                                ElementConditionProto.newBuilder().setMatch(touch_area_three))
+                        .build();
+
+        GenericUserInterfaceProto genericUserInterface =
+                GenericUserInterfaceProto.newBuilder()
+                        .setRootView(
+                                ViewProto.newBuilder()
+                                        .setTextView(TextViewProto.newBuilder().setText("Text"))
+                                        .setIdentifier("textView"))
+                        .setInteractions(
+                                InteractionsProto.newBuilder().addAllInteractions(interactions))
+                        .setModel(ModelProto.newBuilder().addAllValues(modelValues))
+                        .build();
+        list.add(
+                ActionProto.newBuilder()
+                        .setShowGenericUi(
+                                ShowGenericUiProto.newBuilder()
+                                        .setAllowInterrupt(true)
+                                        .setGenericUserInterface(genericUserInterface)
+                                        .setPeriodicElementChecks(
+                                                PeriodicElementChecks.newBuilder().addElementChecks(
+                                                        touch_area_three_present)))
+                        .build());
+        list.add(ActionProto.newBuilder()
+                         .setPrompt(PromptProto.newBuilder().addChoices(
+                                 PromptProto.Choice.newBuilder().setChip(
+                                         ChipProto.newBuilder().setText("End"))))
+                         .build());
+
+        AutofillAssistantTestScript script = new AutofillAssistantTestScript(
+                SupportedScriptProto.newBuilder()
+                        .setPath(MAIN_SCRIPT_PATH)
+                        .setPresentation(PresentationProto.newBuilder().setAutostart(true))
+                        .build(),
+                list);
+        scripts.add(script);
+
+        ArrayList<ActionProto> interruptActionList = new ArrayList<>();
+        addClickSteps(touch_area_one, interruptActionList);
+
+        // The interrupt triggers when touch_area_one is present but touch_area_four is gone, so
+        // that we can trigger it manually.
+        ScriptPreconditionProto interruptPrecondition =
+                ScriptPreconditionProto.newBuilder()
+                        .setElementCondition(ElementConditionProto.newBuilder().setAllOf(
+                                ElementConditionsProto.newBuilder()
+                                        .addConditions(ElementConditionProto.newBuilder().setNoneOf(
+                                                ElementConditionsProto.newBuilder().addConditions(
+                                                        ElementConditionProto.newBuilder().setMatch(
+                                                                touch_area_four))))
+                                        .addConditions(ElementConditionProto.newBuilder().setMatch(
+                                                touch_area_one))))
+                        .build();
+
+        AutofillAssistantTestScript interruptScript = new AutofillAssistantTestScript(
+                SupportedScriptProto.newBuilder()
+                        .setPath(INTERRUPT_SCRIPT_PATH)
+                        .setPresentation(
+                                PresentationProto.newBuilder().setInterrupt(true).setPrecondition(
+                                        interruptPrecondition))
+                        .build(),
+                interruptActionList);
+        scripts.add(interruptScript);
+
+        AutofillAssistantTestService testService =
+                new AutofillAssistantTestService(scripts, ScriptsReturnMode.ALL_AT_ONCE);
+        startAutofillAssistant(mTestRule.getActivity(), testService);
+
+        waitUntilViewMatchesCondition(withText("Text"), isDisplayingAtLeast(90));
+
+        // Tapping touch_area_four will make it disappear, which triggers the interrupt.
+        tapElement(mTestRule, "touch_area_four");
+        waitUntil(() -> !checkElementExists(mTestRule.getWebContents(), "touch_area_four"));
+
+        // The interrupt should click on touch_area_one, making it disappear.
+        waitUntil(() -> !checkElementExists(mTestRule.getWebContents(), "touch_area_one"));
+
+        // Once the interrupt is done, the UI should appear again.
+        waitUntilViewMatchesCondition(withText("Text"), isDisplayingAtLeast(90));
+
+        // If the state has been correctly set to PROMPT again, we should have the touchable window
+        // in the overlay again. In that case, tapping this element will end the action.
+        tapElement(mTestRule, "touch_area_three");
+        waitUntilViewMatchesCondition(withText("End"), isDisplayingAtLeast(90));
+    }
 }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
index 3cd0081..331cd0b 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
@@ -907,7 +907,6 @@
         onView(withContentDescription("City*")).perform(scrollTo(), typeText("Mountain View"));
         onView(withContentDescription("State*")).perform(scrollTo(), typeText("California"));
         onView(withContentDescription("ZIP code*")).perform(scrollTo(), typeText("1234"));
-        onView(withContentDescription("Phone*")).perform(scrollTo(), typeText("8008080808"));
         onView(withText("Done")).perform(scrollTo(), click());
         waitUntilViewMatchesCondition(withText("Continue"), isCompletelyDisplayed());
         // Wait for the address to appear in the UI. From this point on it should be available in
@@ -976,7 +975,6 @@
         onView(withContentDescription("City*")).perform(scrollTo(), typeText("Mountain View"));
         onView(withContentDescription("State*")).perform(scrollTo(), typeText("Invalid"));
         onView(withContentDescription("ZIP code*")).perform(scrollTo(), typeText("1234"));
-        onView(withContentDescription("Phone*")).perform(scrollTo(), typeText("8008080808"));
         Espresso.closeSoftKeyboard();
         onView(withId(org.chromium.chrome.R.id.editor_dialog_done_button))
                 .perform(scrollTo(), click());
@@ -1095,7 +1093,6 @@
         onView(withContentDescription("City*")).perform(scrollTo(), typeText("Mountain View"));
         onView(withContentDescription("State*")).perform(scrollTo(), typeText("CA"));
         onView(withContentDescription("ZIP code*")).perform(scrollTo(), typeText("94043"));
-        onView(withContentDescription("Phone*")).perform(scrollTo(), typeText("8008080808"));
         Espresso.closeSoftKeyboard();
         onView(withText("Done")).perform(scrollTo(), click());
         waitUntilViewMatchesCondition(withText("Billing address*"), isDisplayed());
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java
index 787f1ff..89b0896d 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java
@@ -67,6 +67,11 @@
     public static final long ZOOMING_DURATION = 300;
     private static final int BACKGROUND_FADING_DURATION_MS = 150;
 
+    private static final String TRACE_SHOW_TAB_SWITCHER = "StartSurfaceLayout.Show.TabSwitcher";
+    private static final String TRACE_HIDE_TAB_SWITCHER = "StartSurfaceLayout.Hide.TabSwitcher";
+    private static final String TRACE_SHOW_START_SURFACE = "StartSurfaceLayout.Show.StartSurface";
+    private static final String TRACE_HIDE_START_SURFACE = "StartSurfaceLayout.Hide.StartSurface";
+
     // The transition animation from a tab to the tab switcher.
     private AnimatorSet mTabToSwitcherAnimation;
     private boolean mIsAnimating;
@@ -208,68 +213,84 @@
 
     @Override
     public void show(long time, boolean animate) {
-        try (TraceEvent e = TraceEvent.scoped("StartSurfaceLayout.Show")) {
-            super.show(time, animate);
-
-            // When shown on StartSurface jank is tracked under
-            // JankScenario.START_SURFACE_TAB_SWITCHER and it's started/stopped on
-            // StartSurfaceMediator.
-            if (!StartSurfaceConfiguration.isStartSurfaceFlagEnabled()) {
-                mJankTracker.startTrackingScenario(JankScenario.TAB_SWITCHER);
-            }
-
-            // Lazy initialization if needed.
-            mStartSurface.initialize();
-
-            // Keep the current tab in mLayoutTabs even if we are not going to show the shrinking
-            // animation so that thumbnail taking is not blocked.
-            LayoutTab sourceLayoutTab = createLayoutTab(mTabModelSelector.getCurrentTabId(),
-                    mTabModelSelector.isIncognitoSelected(), NO_CLOSE_BUTTON, NO_TITLE);
-            sourceLayoutTab.setDecorationAlpha(0);
-
-            mLayoutTabs = new LayoutTab[] {sourceLayoutTab};
-
-            boolean quick;
-            boolean isShowingStartSurfaceHomepage = isShowingStartSurfaceHomepage();
-            // If start surface homepage is showing, carousel or single tab switcher is used.
-            // Otherwise grid tab switcher is used.
-            if (isShowingStartSurfaceHomepage) {
-                quick = getCarouselOrSingleTabListDelegate().prepareOverview();
-            } else {
-                quick = getGridTabListDelegate().prepareOverview();
-            }
-
-            // Skip shrinking animation when there is no tab in current tab model. If it's showing
-            // start surface, we don't show the shrink tab animation.
-            boolean isCurrentTabModelEmpty = mTabModelSelector.getCurrentModel().getCount() == 0;
-            boolean showShrinkingAnimation = animate
-                    && TabUiFeatureUtilities.isTabToGtsAnimationEnabled() && !isCurrentTabModelEmpty
-                    && !isShowingStartSurfaceHomepage;
-
-            boolean skipSlowZooming = TabUiFeatureUtilities.SKIP_SLOW_ZOOMING.getValue();
-            Log.d(TAG, "SkipSlowZooming = " + skipSlowZooming);
-            if (skipSlowZooming) {
-                showShrinkingAnimation &= quick;
-            }
-            if (TabUiFeatureUtilities.isLaunchPolishEnabled()) {
-                // Intentionally disable the shrinking animation when accessibility is enabled.
-                // During the shrinking animation, since the ComponsitorViewHolder is not focusable,
-                // I think we are in a temporary no "valid" focus target state, so the focus shifts
-                // to the omnibox and triggers an accessibility announcement of the URL and a
-                // keyboard hiding event. Disable the animation to avoid this temporary state.
-                showShrinkingAnimation &= !ChromeAccessibilityUtil.get().isAccessibilityEnabled();
-            }
-
-            if (!showShrinkingAnimation) {
-                mController.showOverview(animate);
-                return;
-            }
-
-            shrinkTab(animate,
-                    () -> getGridTabListDelegate().getThumbnailLocationOfCurrentTab(false));
+        boolean isShowingStartSurfaceHomepage = isShowingStartSurfaceHomepage();
+        if (isShowingStartSurfaceHomepage) {
+            showStartSurface(time, animate);
+        } else {
+            showTabSwitcher(time, animate);
         }
     }
 
+    private void showStartSurface(long time, boolean animate) {
+        try (TraceEvent e = TraceEvent.scoped(TRACE_SHOW_START_SURFACE)) {
+            show(time, animate, true /*isShowingStartSurfaceHomepage*/);
+        }
+    }
+    private void showTabSwitcher(long time, boolean animate) {
+        try (TraceEvent e = TraceEvent.scoped(TRACE_SHOW_TAB_SWITCHER)) {
+            show(time, animate, false /*isShowingStartSurfaceHomepage*/);
+        }
+    }
+
+    private void show(long time, boolean animate, boolean isShowingStartSurfaceHomepage) {
+        super.show(time, animate);
+
+        // When shown on StartSurface jank is tracked under
+        // JankScenario.START_SURFACE_TAB_SWITCHER and it's started/stopped on
+        // StartSurfaceMediator.
+        if (!StartSurfaceConfiguration.isStartSurfaceFlagEnabled()) {
+            mJankTracker.startTrackingScenario(JankScenario.TAB_SWITCHER);
+        }
+
+        // Lazy initialization if needed.
+        mStartSurface.initialize();
+
+        // Keep the current tab in mLayoutTabs even if we are not going to show the shrinking
+        // animation so that thumbnail taking is not blocked.
+        LayoutTab sourceLayoutTab = createLayoutTab(mTabModelSelector.getCurrentTabId(),
+                mTabModelSelector.isIncognitoSelected(), NO_CLOSE_BUTTON, NO_TITLE);
+        sourceLayoutTab.setDecorationAlpha(0);
+
+        mLayoutTabs = new LayoutTab[] {sourceLayoutTab};
+
+        boolean quick;
+        // If start surface homepage is showing, carousel or single tab switcher is used.
+        // Otherwise grid tab switcher is used.
+        if (isShowingStartSurfaceHomepage) {
+            quick = getCarouselOrSingleTabListDelegate().prepareOverview();
+        } else {
+            quick = getGridTabListDelegate().prepareOverview();
+        }
+
+        // Skip shrinking animation when there is no tab in current tab model. If it's showing
+        // start surface, we don't show the shrink tab animation.
+        boolean isCurrentTabModelEmpty = mTabModelSelector.getCurrentModel().getCount() == 0;
+        boolean showShrinkingAnimation = animate
+                && TabUiFeatureUtilities.isTabToGtsAnimationEnabled() && !isCurrentTabModelEmpty
+                && !isShowingStartSurfaceHomepage;
+
+        boolean skipSlowZooming = TabUiFeatureUtilities.SKIP_SLOW_ZOOMING.getValue();
+        Log.d(TAG, "SkipSlowZooming = " + skipSlowZooming);
+        if (skipSlowZooming) {
+            showShrinkingAnimation &= quick;
+        }
+        if (TabUiFeatureUtilities.isLaunchPolishEnabled()) {
+            // Intentionally disable the shrinking animation when accessibility is enabled.
+            // During the shrinking animation, since the ComponsitorViewHolder is not focusable,
+            // I think we are in a temporary no "valid" focus target state, so the focus shifts
+            // to the omnibox and triggers an accessibility announcement of the URL and a
+            // keyboard hiding event. Disable the animation to avoid this temporary state.
+            showShrinkingAnimation &= !ChromeAccessibilityUtil.get().isAccessibilityEnabled();
+        }
+
+        if (!showShrinkingAnimation) {
+            mController.showOverview(animate);
+            return;
+        }
+
+        shrinkTab(animate, () -> getGridTabListDelegate().getThumbnailLocationOfCurrentTab(false));
+    }
+
     @Override
     protected void updateLayout(long time, long dt) {
         ensureSceneLayerCreated();
@@ -283,39 +304,57 @@
 
     @Override
     public void startHiding(int nextId, boolean hintAtTabSelection) {
-        try (TraceEvent e = TraceEvent.scoped("StartSurfaceLayout.StartHiding")) {
-            super.startHiding(nextId, hintAtTabSelection);
-
-            int sourceTabId = nextId;
-            if (sourceTabId == Tab.INVALID_TAB_ID) {
-                sourceTabId = mTabModelSelector.getCurrentTabId();
-            }
-
-            LayoutTab sourceLayoutTab = createLayoutTab(sourceTabId,
-                    mTabModelSelector.isIncognitoSelected(), NO_CLOSE_BUTTON, NO_TITLE);
-            sourceLayoutTab.setDecorationAlpha(0);
-
-            List<LayoutTab> layoutTabs = new ArrayList<>();
-            layoutTabs.add(sourceLayoutTab);
-
-            if (sourceTabId != mTabModelSelector.getCurrentTabId()) {
-                // Keep the original tab in mLayoutTabs to unblock thumbnail taking at the end of
-                // the animation.
-                LayoutTab originalTab = createLayoutTab(mTabModelSelector.getCurrentTabId(),
-                        mTabModelSelector.isIncognitoSelected(), NO_CLOSE_BUTTON, NO_TITLE);
-                originalTab.setScale(0);
-                originalTab.setDecorationAlpha(0);
-                layoutTabs.add(originalTab);
-            }
-            mLayoutTabs = layoutTabs.toArray(new LayoutTab[0]);
-
-            updateCacheVisibleIds(new LinkedList<>(Arrays.asList(sourceTabId)));
-
-            mIsAnimating = true;
-            mController.hideOverview(!TabUiFeatureUtilities.isTabToGtsAnimationEnabled());
+        int startSurfaceState = mController.getStartSurfaceState();
+        if (startSurfaceState == StartSurfaceState.SHOWN_HOMEPAGE) {
+            startHidingStartSurface(nextId, hintAtTabSelection);
+        } else {
+            startHidingTabSwitcher(nextId, hintAtTabSelection);
         }
     }
 
+    private void startHidingStartSurface(int nextId, boolean hintAtTabSelection) {
+        try (TraceEvent e = TraceEvent.scoped(TRACE_HIDE_START_SURFACE)) {
+            startHidingImpl(nextId, hintAtTabSelection);
+        }
+    }
+    private void startHidingTabSwitcher(int nextId, boolean hintAtTabSelection) {
+        try (TraceEvent e = TraceEvent.scoped(TRACE_HIDE_TAB_SWITCHER)) {
+            startHidingImpl(nextId, hintAtTabSelection);
+        }
+    }
+
+    private void startHidingImpl(int nextId, boolean hintAtTabSelection) {
+        super.startHiding(nextId, hintAtTabSelection);
+
+        int sourceTabId = nextId;
+        if (sourceTabId == Tab.INVALID_TAB_ID) {
+            sourceTabId = mTabModelSelector.getCurrentTabId();
+        }
+
+        LayoutTab sourceLayoutTab = createLayoutTab(
+                sourceTabId, mTabModelSelector.isIncognitoSelected(), NO_CLOSE_BUTTON, NO_TITLE);
+        sourceLayoutTab.setDecorationAlpha(0);
+
+        List<LayoutTab> layoutTabs = new ArrayList<>();
+        layoutTabs.add(sourceLayoutTab);
+
+        if (sourceTabId != mTabModelSelector.getCurrentTabId()) {
+            // Keep the original tab in mLayoutTabs to unblock thumbnail taking at the end of
+            // the animation.
+            LayoutTab originalTab = createLayoutTab(mTabModelSelector.getCurrentTabId(),
+                    mTabModelSelector.isIncognitoSelected(), NO_CLOSE_BUTTON, NO_TITLE);
+            originalTab.setScale(0);
+            originalTab.setDecorationAlpha(0);
+            layoutTabs.add(originalTab);
+        }
+        mLayoutTabs = layoutTabs.toArray(new LayoutTab[0]);
+
+        updateCacheVisibleIds(new LinkedList<>(Arrays.asList(sourceTabId)));
+
+        mIsAnimating = true;
+        mController.hideOverview(!TabUiFeatureUtilities.isTabToGtsAnimationEnabled());
+    }
+
     @Override
     public void doneHiding() {
         try (TraceEvent e = TraceEvent.scoped("StartSurfaceLayout.DoneHiding")) {
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
index 9daaa539..11f4f06 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
@@ -505,8 +505,7 @@
     // clang-format off
     @EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID,
             ChromeFeatureList.TAB_SWITCHER_ON_RETURN + "<Study",
-            ChromeFeatureList.START_SURFACE_ANDROID + "<Study",
-            ChromeFeatureList.THEME_REFACTOR_ANDROID})
+            ChromeFeatureList.START_SURFACE_ANDROID + "<Study"})
     @CommandLineFlags.Add({ChromeSwitches.DISABLE_NATIVE_INITIALIZATION,
             "force-fieldtrials=Study/Group",
             IMMEDIATE_RETURN_PARAMS + "/start_surface_variation/single"})
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn
index 67725f6..3eadc2f 100644
--- a/chrome/android/features/tab_ui/BUILD.gn
+++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -28,7 +28,6 @@
     "java/res/anim/iph_touch_point_animation.xml",
     "java/res/anim/iph_touch_point_background_alpha_animation.xml",
     "java/res/anim/iph_touch_point_background_animation.xml",
-    "java/res/color/dark_text_color_list.xml",
     "java/res/drawable-v21/fake_search_box_bg_incognito.xml",
     "java/res/drawable/chevron_right.xml",
     "java/res/drawable/fake_search_box_text_box_bg_incognito.xml",
diff --git a/chrome/android/features/tab_ui/java/res/color/dark_text_color_list.xml b/chrome/android/features/tab_ui/java/res/color/dark_text_color_list.xml
deleted file mode 100644
index fa06562..0000000
--- a/chrome/android/features/tab_ui/java/res/color/dark_text_color_list.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:alpha="@dimen/default_disabled_alpha"
-        android:color="@color/default_text_color_dark" android:state_enabled="false"/>
-    <item android:color="@color/default_text_color_dark" />
-</selector>
\ No newline at end of file
diff --git a/chrome/android/features/tab_ui/java/res/layout/selectable_tab_list_card_item.xml b/chrome/android/features/tab_ui/java/res/layout/selectable_tab_list_card_item.xml
index a8bd2dd0..af8b0023 100644
--- a/chrome/android/features/tab_ui/java/res/layout/selectable_tab_list_card_item.xml
+++ b/chrome/android/features/tab_ui/java/res/layout/selectable_tab_list_card_item.xml
@@ -8,13 +8,6 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content">
 
-    <org.chromium.ui.widget.ChromeImageView
-        android:id="@+id/selected_view_below_lollipop"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@drawable/selected_tab_background"
-        android:visibility="gone"/>
-
     <!-- TODO(crbug.com/1023557): Rename SelectableTabGridView to SelectableTabView. -->
     <org.chromium.chrome.browser.tasks.tab_management.SelectableTabGridView
         android:id="@+id/content_view"
diff --git a/chrome/android/features/tab_ui/java/res/layout/tab_grid_card_item.xml b/chrome/android/features/tab_ui/java/res/layout/tab_grid_card_item.xml
index f6b54b2..fa09e4b 100644
--- a/chrome/android/features/tab_ui/java/res/layout/tab_grid_card_item.xml
+++ b/chrome/android/features/tab_ui/java/res/layout/tab_grid_card_item.xml
@@ -13,13 +13,6 @@
         android:background="?attr/tabGridBackground"
         android:layout_margin="?attr/tabGridMargin"
         android:visibility="gone"/>
-    <org.chromium.ui.widget.ChromeImageView
-        android:id="@+id/selected_view_below_lollipop"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@drawable/selected_tab_background"
-        android:layout_margin="6dp"
-        android:visibility="gone"/>
     <FrameLayout
         android:id="@+id/content_view"
         android:layout_width="match_parent"
diff --git a/chrome/android/features/tab_ui/java/res/layout/tab_list_card_item.xml b/chrome/android/features/tab_ui/java/res/layout/tab_list_card_item.xml
index 8613745a..a4a57cb 100644
--- a/chrome/android/features/tab_ui/java/res/layout/tab_list_card_item.xml
+++ b/chrome/android/features/tab_ui/java/res/layout/tab_list_card_item.xml
@@ -3,12 +3,6 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <org.chromium.ui.widget.ChromeImageView
-        android:id="@+id/selected_view_below_lollipop"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@drawable/selected_tab_background"
-        android:visibility="gone"/>
 
     <LinearLayout
         android:id="@+id/content_view"
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 5d9e5f13..f535bc4 100644
--- a/chrome/android/features/tab_ui/java/res/values/colors.xml
+++ b/chrome/android/features/tab_ui/java/res/values/colors.xml
@@ -5,44 +5,18 @@
 
 <resources xmlns:tools="http://schemas.android.com/tools">
     <!-- Tab Switcher colors. -->
-    <color name="tab_grid_card_view_tint_color">@color/legacy_bg_color_elev_4</color>
-    <color name="tab_grid_card_view_tint_color_incognito">@color/default_bg_color_dark_elev_4</color>
-
-    <color name="tab_grid_card_title_text_color">@color/default_text_color_list</color>
-    <color name="tab_grid_card_title_text_color_incognito">@color/default_text_color_light_list</color>
-
-    <color name="tab_group_number_text_color">@color/default_text_color_list</color>
-    <color name="tab_group_number_text_color_incognito">@color/default_text_color_light</color>
-
-    <color name="tab_grid_card_action_button_tint_color">@color/default_icon_color_baseline</color>
-    <color name="tab_grid_card_action_button_tint_color_incognito">@color/default_icon_color_light</color>
-
     <color name="tab_grid_card_divider_tint_color_incognito">@color/divider_line_bg_color_light</color>
 
     <color name="tab_grid_card_thumbnail_placeholder_color">@color/default_bg_color_secondary</color>
     <color name="tab_grid_card_thumbnail_placeholder_color_incognito">@color/default_bg_color_dark_elev_3</color>
 
-    <color name="tab_grid_card_selected_color">@color/default_control_color_active</color>
-    <color name="tab_grid_card_selected_color_incognito">@color/default_control_color_active_dark</color>
-
     <!-- Tab Group related colors. -->
-    <color name="tab_list_mini_card_default_background_color">@color/default_bg_color_secondary</color>
-    <color name="tab_list_mini_card_default_background_color_incognito">@color/default_bg_color_secondary_dark</color>
-
     <color name="tab_grid_dialog_background_color">@color/legacy_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_accent1_baseline</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>
     <color name="favicon_background_color_incognito">@color/black_alpha_38</color>
 
     <color name="hovered_tab_grid_card_background_color">@color/default_bg_color_secondary</color>
-    <color name="hovered_tab_grid_card_background_color_incognito">@color/default_bg_color_secondary_dark</color>
 
     <color name="new_tab_tile_plus_color">@color/default_icon_color_secondary</color>
     <color name="new_tab_tile_plus_color_incognito">@color/default_icon_color_secondary_light</color>
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 1fd75ca..397bff2 100644
--- a/chrome/android/features/tab_ui/java/res/values/dimens.xml
+++ b/chrome/android/features/tab_ui/java/res/values/dimens.xml
@@ -9,7 +9,6 @@
     <dimen name="tab_list_selected_margin">7dp</dimen>
     <dimen name="tab_list_card_padding">8dp</dimen>
     <dimen name="tab_list_card_radius">4dp</dimen>
-    <dimen name="tab_list_card_title_height">32dp</dimen>
     <dimen name="tab_grid_price_card_radius">4dp</dimen>
     <dimen name="tab_list_mini_card_radius">4dp</dimen>
     <dimen name="tab_list_mini_card_frame_size">1dp</dimen>
@@ -59,7 +58,6 @@
     <dimen name="tab_grid_card_thumbnail_corner_radius_top">4dp</dimen>
     <dimen name="tab_grid_card_thumbnail_corner_radius_bottom">12dp</dimen>
     <dimen name="tab_grid_card_thumbnail_margin">4dp</dimen>
-    <dimen name="tab_list_card_margin">2dp</dimen>
     <dimen name="tab_list_card_action_button_size">48dp</dimen>
     <dimen name="tab_list_card_action_button_margin">4dp</dimen>
     <dimen name="tab_list_card_title_fading_length">24dp</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 42f4227..bfc83d99 100644
--- a/chrome/android/features/tab_ui/java/res/values/styles.xml
+++ b/chrome/android/features/tab_ui/java/res/values/styles.xml
@@ -13,7 +13,6 @@
         <item name="colorControlHighlight">@color/filled_button_bg_color</item>
     </style>
 
-    <integer name="view_visible">0</integer> <!-- This is VISIBLE -->
     <integer name="view_gone">2</integer> <!-- This is GONE -->
 
     <!-- Theme overlay for theme refactor 2021 -->
@@ -65,35 +64,11 @@
         <item name="android:fadingEdgeLength">@dimen/tab_grid_card_title_fading_length</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>
-        <item name="tabGridBackground">@drawable/dialog_bg_tinted</item>
-        <item name="tabGridMargin">@dimen/tab_list_card_margin</item>
-
-        <item name="tabGridFaviconStyle">@style/TabGridCardTopFaviconStyle</item>
-        <item name="tabGridActionButtonStyle">@style/TabGridCardActionButtonStyle</item>
-        <item name="tabGridThumbnailStyle">@style/TabGridCardThumbnailStyle</item>
-        <item name="tabGridTitleStyle">@style/TabGridCardTitleStyle</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="">
         <item name="tabGridDividerVisible">@integer/view_gone</item>
         <item name="tabGridHeaderHeight">@dimen/tab_grid_card_header_height</item>
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ClosableTabGridView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ClosableTabGridView.java
index 96a5c55..b12ce6e 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ClosableTabGridView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ClosableTabGridView.java
@@ -11,7 +11,6 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.os.Build;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.ImageView;
@@ -74,14 +73,12 @@
     /**
      * Play the zoom-in and zoom-out animations for tab grid card.
      * @param status      The target animation status in {@link AnimationStatus}.
-     * @param isSelected  Whether the scaling card is selected or not.
      */
-    void scaleTabGridCardView(@AnimationStatus int status, boolean isSelected) {
+    void scaleTabGridCardView(@AnimationStatus int status) {
         assert status < AnimationStatus.NUM_ENTRIES;
 
         final View backgroundView = fastFindViewById(R.id.background_view);
         final View contentView = fastFindViewById(R.id.content_view);
-        final View selectedViewBelowLollipop = fastFindViewById(R.id.selected_view_below_lollipop);
         boolean isZoomIn = status == AnimationStatus.SELECTED_CARD_ZOOM_IN
                 || status == AnimationStatus.HOVERED_CARD_ZOOM_IN;
         boolean isHovered = status == AnimationStatus.HOVERED_CARD_ZOOM_IN
@@ -102,11 +99,6 @@
             public void onAnimationEnd(Animator animation) {
                 if (!isZoomIn) {
                     backgroundView.setVisibility(View.GONE);
-                    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1
-                            && !TabUiThemeProvider.themeRefactorEnabled()) {
-                        selectedViewBelowLollipop.setVisibility(
-                                isSelected ? View.VISIBLE : View.GONE);
-                    }
                 }
                 mIsAnimating = false;
             }
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 99b3136..df4baf7 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
@@ -185,11 +185,6 @@
                     new Rect(0, 0, thumbnail.getWidth(), thumbnail.getHeight()),
                     mThumbnailRects.get(index), mThumbnailBasePaint);
             thumbnail.recycle();
-
-            if (!TabUiThemeProvider.themeRefactorEnabled()) {
-                mCanvas.drawRoundRect(
-                        mThumbnailRects.get(index), mRadius, mRadius, mThumbnailFramePaint);
-            }
         }
 
         private void drawFaviconDrawableOnCanvasWithFrame(Drawable favicon, int index) {
@@ -278,7 +273,7 @@
                 resource.getDimension(R.dimen.tab_grid_thumbnail_favicon_background_down_shift),
                 resource.getColor(R.color.modern_grey_800_alpha_38));
 
-        initializedThumbnailRects(context, expectedThumbnailAspectRatio);
+        initializedThumbnailRects(context);
 
         // Initialize Rects for favicons and favicon frame.
         final float halfFaviconFrameSize =
@@ -341,39 +336,26 @@
     }
 
     /**
-     * Initialize rects used for thumbnails. Depending on whether thene refacotr is enabled, the
-     * padding around the thumbnail is different.
+     * Initialize rects used for thumbnails.
      */
-    private void initializedThumbnailRects(Context context, float expectedThumbnailAspectRatio) {
-        boolean themeRefactorEnabled = TabUiThemeProvider.themeRefactorEnabled();
-
+    private void initializedThumbnailRects(Context context) {
         float thumbnailHorizontalPadding =
                 TabUiThemeProvider.getTabMiniThumbnailPaddingDimension(context);
-        float thumbnailVerticalPadding = themeRefactorEnabled
-                ? thumbnailHorizontalPadding
-                : thumbnailHorizontalPadding / expectedThumbnailAspectRatio;
-        float multiThumbnailHorizontalPadding =
-                themeRefactorEnabled ? 0 : thumbnailHorizontalPadding;
-        float multiThumbnailVerticalPadding = themeRefactorEnabled ? 0 : thumbnailVerticalPadding;
+        float thumbnailVerticalPadding = thumbnailHorizontalPadding;
 
         float centerX = mThumbnailWidth * 0.5f;
         float centerY = mThumbnailHeight * 0.5f;
         float halfThumbnailHorizontalPadding = thumbnailHorizontalPadding / 2;
         float halfThumbnailVerticalPadding = thumbnailVerticalPadding / 2;
 
-        mThumbnailRects.add(new RectF(multiThumbnailHorizontalPadding,
-                multiThumbnailVerticalPadding, centerX - halfThumbnailHorizontalPadding,
+        mThumbnailRects.add(new RectF(0, 0, centerX - halfThumbnailHorizontalPadding,
                 centerY - halfThumbnailVerticalPadding));
-        mThumbnailRects.add(new RectF(centerX + halfThumbnailHorizontalPadding,
-                multiThumbnailVerticalPadding, mThumbnailWidth - multiThumbnailHorizontalPadding,
+        mThumbnailRects.add(new RectF(centerX + halfThumbnailHorizontalPadding, 0, mThumbnailWidth,
                 centerY - halfThumbnailVerticalPadding));
-        mThumbnailRects.add(new RectF(multiThumbnailHorizontalPadding,
-                centerY + halfThumbnailVerticalPadding, centerX - halfThumbnailHorizontalPadding,
-                mThumbnailHeight - multiThumbnailVerticalPadding));
+        mThumbnailRects.add(new RectF(0, centerY + halfThumbnailVerticalPadding,
+                centerX - halfThumbnailHorizontalPadding, mThumbnailHeight));
         mThumbnailRects.add(new RectF(centerX + halfThumbnailHorizontalPadding,
-                centerY + halfThumbnailVerticalPadding,
-                mThumbnailWidth - multiThumbnailHorizontalPadding,
-                mThumbnailHeight - multiThumbnailVerticalPadding));
+                centerY + halfThumbnailVerticalPadding, mThumbnailWidth, mThumbnailHeight));
     }
 
     @Override
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridThumbnailView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridThumbnailView.java
index dfda4ef..778b4596 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridThumbnailView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridThumbnailView.java
@@ -55,11 +55,6 @@
      * @param isSelected Whether the thumbnail is on a selected tab.
      */
     void setColorThumbnailPlaceHolder(boolean isIncognito, boolean isSelected) {
-        if (!TabUiThemeProvider.themeRefactorEnabled()) {
-            setImageResource(TabUiThemeProvider.getThumbnailPlaceHolderColorResource(isIncognito));
-            return;
-        }
-
         ColorDrawable placeHolder =
                 new ColorDrawable(TabUiThemeProvider.getMiniThumbnailPlaceHolderColor(
                         getContext(), isIncognito, isSelected));
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java
index cdb102d..3ea7d83 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java
@@ -7,22 +7,16 @@
 import static org.chromium.chrome.browser.tasks.tab_management.TabListModel.CardProperties.CARD_ALPHA;
 
 import android.content.res.ColorStateList;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
-import android.os.Build;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.annotation.ColorInt;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
-import androidx.core.content.res.ResourcesCompat;
 import androidx.core.graphics.drawable.DrawableCompat;
 import androidx.core.view.ViewCompat;
 import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
@@ -110,33 +104,10 @@
             tabTitleView.setContentDescription(
                     view.getResources().getString(R.string.accessibility_tabstrip_tab, title));
         } else if (TabProperties.IS_SELECTED == propertyKey) {
-            if (TabUiThemeProvider.themeRefactorEnabled()) {
-                updateColor(view, model.get(TabProperties.IS_INCOGNITO),
-                        model.get(TabProperties.IS_SELECTED));
-                updateThumbnail(view, model);
-                updateFavicon(view, model);
-            } else {
-                int selectedTabBackground =
-                        model.get(TabProperties.SELECTED_TAB_BACKGROUND_DRAWABLE_ID);
-                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
-                    if (model.get(TabProperties.IS_SELECTED)) {
-                        view.fastFindViewById(R.id.selected_view_below_lollipop)
-                                .setBackgroundResource(selectedTabBackground);
-                        view.fastFindViewById(R.id.selected_view_below_lollipop)
-                                .setVisibility(View.VISIBLE);
-                    } else {
-                        view.fastFindViewById(R.id.selected_view_below_lollipop)
-                                .setVisibility(View.GONE);
-                    }
-                } else {
-                    Resources res = view.getResources();
-                    Resources.Theme theme = view.getContext().getTheme();
-                    Drawable drawable = new InsetDrawable(
-                            ResourcesCompat.getDrawable(res, selectedTabBackground, theme),
-                            (int) res.getDimension(R.dimen.tab_list_selected_inset));
-                    view.setForeground(model.get(TabProperties.IS_SELECTED) ? drawable : null);
-                }
-            }
+            updateColor(view, model.get(TabProperties.IS_INCOGNITO),
+                    model.get(TabProperties.IS_SELECTED));
+            updateThumbnail(view, model);
+            updateFavicon(view, model);
             if (TabUiFeatureUtilities.ENABLE_SEARCH_CHIP.getValue()) {
                 ChipView pageInfoButton = (ChipView) view.fastFindViewById(R.id.page_info_button);
                 pageInfoButton.getPrimaryTextView().setTextAlignment(
@@ -203,10 +174,8 @@
             TabListMediator.IphProvider provider = model.get(TabProperties.IPH_PROVIDER);
             if (provider != null) provider.showIPH(view.fastFindViewById(R.id.tab_thumbnail));
         } else if (TabProperties.CARD_ANIMATION_STATUS == propertyKey) {
-            boolean isSelected = model.get(TabProperties.IS_SELECTED);
             ((ClosableTabGridView) view)
-                    .scaleTabGridCardView(
-                            model.get(TabProperties.CARD_ANIMATION_STATUS), isSelected);
+                    .scaleTabGridCardView(model.get(TabProperties.CARD_ANIMATION_STATUS));
         } else if (TabProperties.IS_INCOGNITO == propertyKey) {
             updateColor(view, model.get(TabProperties.IS_INCOGNITO),
                     model.get(TabProperties.IS_SELECTED));
@@ -397,16 +366,9 @@
                 (ChromeImageView) rootView.fastFindViewById(R.id.background_view);
 
         cardView.getBackground().mutate();
-        int backgroundColor = TabUiThemeProvider.getCardViewBackgroundColor(
+        final @ColorInt int backgroundColor = TabUiThemeProvider.getCardViewBackgroundColor(
                 cardView.getContext(), isIncognito, isSelected);
-        if (TabUiThemeProvider.themeRefactorEnabled()) {
-            // ViewCompat#setBackgroundTintList does not work for the drawable background when
-            // themeRefactorEnabled. See https://crbug.com/1232590.
-            cardView.getBackground().setColorFilter(
-                    new PorterDuffColorFilter(backgroundColor, PorterDuff.Mode.SRC_IN));
-        } else {
-            ViewCompat.setBackgroundTintList(cardView, ColorStateList.valueOf(backgroundColor));
-        }
+        ViewCompat.setBackgroundTintList(cardView, ColorStateList.valueOf(backgroundColor));
 
         dividerView.setBackgroundColor(
                 TabUiThemeProvider.getDividerColor(dividerView.getContext(), isIncognito));
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java
index 8385fc9e..5c231a8a 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java
@@ -37,7 +37,6 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import org.chromium.base.Log;
-import org.chromium.chrome.browser.flags.CachedFeatureFlags;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.tab_ui.R;
@@ -223,18 +222,12 @@
         if (mShadowImageView == null) {
             Context context = getContext();
             mShadowImageView = new ImageView(context);
-            boolean themeRefactorEnabled =
-                    CachedFeatureFlags.isEnabled(ChromeFeatureList.THEME_REFACTOR_ANDROID);
-            Drawable drawable =
-                    context.getDrawable(themeRefactorEnabled ? R.drawable.toolbar_hairline
-                                                             : R.drawable.modern_toolbar_shadow);
+            Drawable drawable = context.getDrawable(R.drawable.toolbar_hairline);
             mShadowImageView.setImageDrawable(drawable);
             mShadowImageView.setScaleType(ImageView.ScaleType.FIT_XY);
             mShadowImageView.setTag(SHADOW_VIEW_TAG);
             Resources res = context.getResources();
-            int shadowHeight =
-                    res.getDimensionPixelSize(themeRefactorEnabled ? R.dimen.toolbar_hairline_height
-                                                                   : R.dimen.toolbar_shadow_height);
+            int shadowHeight = res.getDimensionPixelSize(R.dimen.toolbar_hairline_height);
             if (getParent() instanceof FrameLayout) {
                 // Add shadow for grid tab switcher.
                 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewBinder.java
index 1b482a8..a72a7e4 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewBinder.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewBinder.java
@@ -7,7 +7,6 @@
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.InsetDrawable;
-import android.os.Build;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
@@ -52,24 +51,12 @@
         } else if (TabProperties.IS_SELECTED == propertyKey) {
             int selectedTabBackground =
                     model.get(TabProperties.SELECTED_TAB_BACKGROUND_DRAWABLE_ID);
-            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
-                if (model.get(TabProperties.IS_SELECTED)) {
-                    fastView.findViewById(R.id.selected_view_below_lollipop)
-                            .setBackgroundResource(selectedTabBackground);
-                    fastView.findViewById(R.id.selected_view_below_lollipop)
-                            .setVisibility(View.VISIBLE);
-                } else {
-                    fastView.findViewById(R.id.selected_view_below_lollipop)
-                            .setVisibility(View.GONE);
-                }
-            } else {
-                Resources res = view.getResources();
-                Resources.Theme theme = view.getContext().getTheme();
-                Drawable drawable = new InsetDrawable(
-                        ResourcesCompat.getDrawable(res, selectedTabBackground, theme),
-                        (int) res.getDimension(R.dimen.tab_list_selected_inset_low_end));
-                view.setForeground(model.get(TabProperties.IS_SELECTED) ? drawable : null);
-            }
+            Resources res = view.getResources();
+            Resources.Theme theme = view.getContext().getTheme();
+            Drawable drawable = new InsetDrawable(
+                    ResourcesCompat.getDrawable(res, selectedTabBackground, theme),
+                    (int) res.getDimension(R.dimen.tab_list_selected_inset_low_end));
+            view.setForeground(model.get(TabProperties.IS_SELECTED) ? drawable : null);
         } else if (TabProperties.TAB_SELECTED_LISTENER == propertyKey) {
             if (model.get(TabProperties.TAB_SELECTED_LISTENER) == null) {
                 view.setOnClickListener(null);
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 003735d63..d79604d 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
@@ -20,8 +20,6 @@
 import com.google.android.material.elevation.ElevationOverlayProvider;
 
 import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.browser.flags.CachedFeatureFlags;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.components.browser_ui.styles.SemanticColorUtils;
 
@@ -41,15 +39,6 @@
     @ColorInt
     public static int getCardViewBackgroundColor(
             Context context, boolean isIncognito, boolean isSelected) {
-        if (!themeRefactorEnabled()) {
-            // Use #getColorStateList to take advantage of reading resource with attributes.
-            return AppCompatResources
-                    .getColorStateList(context,
-                            isIncognito ? R.color.tab_grid_card_view_tint_color_incognito
-                                        : R.color.tab_grid_card_view_tint_color)
-                    .getDefaultColor();
-        }
-
         if (isIncognito) {
             // Incognito does not use dynamic colors, so it can use colors from resources.
             @ColorRes
@@ -79,13 +68,6 @@
     @ColorInt
     public static int getTabGroupNumberTextColor(
             Context context, boolean isIncognito, boolean isSelected) {
-        if (!themeRefactorEnabled()) {
-            return AppCompatResources
-                    .getColorStateList(context,
-                            isIncognito ? R.color.tab_group_number_text_color_incognito
-                                        : R.color.tab_group_number_text_color)
-                    .getDefaultColor();
-        }
         if (isIncognito) {
             @ColorRes
             int colorRes = isSelected ? R.color.incognito_tab_tile_number_selected_color
@@ -106,14 +88,6 @@
      */
     @ColorInt
     public static int getTitleTextColor(Context context, boolean isIncognito, boolean isSelected) {
-        if (!themeRefactorEnabled()) {
-            return AppCompatResources
-                    .getColorStateList(context,
-                            isIncognito ? R.color.tab_grid_card_title_text_color_incognito
-                                        : R.color.tab_grid_card_title_text_color)
-                    .getDefaultColor();
-        }
-
         if (isIncognito) {
             @ColorRes
             int colorRes = isSelected ? R.color.incognito_tab_title_selected_color
@@ -136,12 +110,6 @@
      */
     public static ColorStateList getActionButtonTintList(
             Context context, boolean isIncognito, boolean isSelected) {
-        if (!themeRefactorEnabled()) {
-            return AppCompatResources.getColorStateList(context,
-                    isIncognito ? R.color.tab_grid_card_action_button_tint_color_incognito
-                                : R.color.tab_grid_card_action_button_tint_color);
-        }
-
         if (isIncognito) {
             @ColorRes
             int colorRes = isSelected ? R.color.incognito_tab_action_button_selected_color
@@ -167,18 +135,6 @@
      */
     public static ColorStateList getToggleActionButtonBackgroundTintList(
             Context context, boolean isIncognito, boolean isSelected) {
-        if (!themeRefactorEnabled()) {
-            @ColorRes
-            int colorRes;
-            if (isSelected) {
-                colorRes = isIncognito ? R.color.tab_grid_card_selected_color_incognito
-                                       : R.color.tab_grid_card_selected_color;
-            } else {
-                colorRes = isIncognito ? R.color.default_icon_color_light
-                                       : R.color.default_icon_color_baseline;
-            }
-            return AppCompatResources.getColorStateList(context, colorRes);
-        }
         return getActionButtonTintList(context, isIncognito, isSelected);
     }
 
@@ -192,11 +148,6 @@
      */
     public static ColorStateList getToggleActionButtonCheckedDrawableTintList(
             Context context, boolean isIncognito) {
-        if (!themeRefactorEnabled()) {
-            return AppCompatResources.getColorStateList(context,
-                    isIncognito ? R.color.default_icon_color_dark
-                                : R.color.default_icon_color_inverse);
-        }
         if (isIncognito) {
             return AppCompatResources.getColorStateList(
                     context, R.color.incognito_tab_bg_selected_color);
@@ -255,12 +206,6 @@
     @ColorInt
     public static int getMiniThumbnailPlaceHolderColor(
             Context context, boolean isIncognito, boolean isSelected) {
-        if (!themeRefactorEnabled()) {
-            return ApiCompatibilityUtils.getColor(context.getResources(),
-                    isIncognito ? R.color.tab_list_mini_card_default_background_color_incognito
-                                : R.color.tab_list_mini_card_default_background_color);
-        }
-
         if (isIncognito) {
             @ColorRes
             int colorRes = isSelected ? R.color.incognito_tab_thumbnail_placeholder_selected_color
@@ -333,11 +278,6 @@
     @ColorInt
     public static int getChromeOwnedFaviconTintColor(
             Context context, boolean isIncognito, boolean isTabSelected) {
-        if (!themeRefactorEnabled()) {
-            return ApiCompatibilityUtils.getColor(context.getResources(),
-                    isIncognito ? R.color.default_icon_color_light
-                                : R.color.default_icon_color_baseline);
-        }
         return getTitleTextColor(context, isIncognito, isTabSelected);
     }
 
@@ -352,12 +292,6 @@
      */
     public static ColorStateList getHoveredCardBackgroundTintList(
             Context context, boolean isIncognito, boolean isSelected) {
-        if (!themeRefactorEnabled()) {
-            return AppCompatResources.getColorStateList(context,
-                    isIncognito ? R.color.hovered_tab_grid_card_background_color_incognito
-                                : R.color.hovered_tab_grid_card_background_color);
-        }
-
         if (isIncognito) {
             @ColorRes
             int colorRes = isSelected ? R.color.incognito_tab_group_hovered_bg_selected_color
@@ -395,12 +329,6 @@
      */
     @ColorInt
     public static int getTabGridDialogBackgroundColor(Context context, boolean isIncognito) {
-        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);
@@ -412,19 +340,6 @@
     @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
@@ -438,18 +353,6 @@
     @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
@@ -521,17 +424,11 @@
      */
     @ColorInt
     public static int getTabSelectionToolbarBackground(Context context, boolean isIncognito) {
-        if (!themeRefactorEnabled()) {
+        if (isIncognito) {
             return ApiCompatibilityUtils.getColor(context.getResources(),
-                    isIncognito ? R.color.default_control_color_active_dark
-                                : R.color.default_control_color_active);
+                    R.color.incognito_tab_selection_editor_toolbar_bg_color);
         } else {
-            if (isIncognito) {
-                return ApiCompatibilityUtils.getColor(context.getResources(),
-                        R.color.incognito_tab_selection_editor_toolbar_bg_color);
-            } else {
-                return MaterialColors.getColor(context, R.attr.colorSurface, TAG);
-            }
+            return MaterialColors.getColor(context, R.attr.colorSurface, TAG);
         }
     }
 
@@ -545,12 +442,6 @@
      */
     public static ColorStateList getTabSelectionToolbarIconTintList(
             Context context, boolean isIncognito) {
-        if (!themeRefactorEnabled()) {
-            return AppCompatResources.getColorStateList(context,
-                    isIncognito ? R.color.dark_text_color_list
-                                : R.color.default_text_color_inverse_list);
-        }
-
         return AppCompatResources.getColorStateList(context,
                 isIncognito ? R.color.default_text_color_light_list
                             : R.color.default_text_color_list);
@@ -609,9 +500,7 @@
      * @return The padding space around favicon.
      */
     public static float getTabCardTopFaviconPadding(Context context) {
-        return context.getResources().getDimension(themeRefactorEnabled()
-                        ? R.dimen.tab_grid_card_favicon_padding
-                        : R.dimen.tab_list_card_padding);
+        return context.getResources().getDimension(R.dimen.tab_grid_card_favicon_padding);
     }
 
     /**
@@ -620,9 +509,7 @@
      * @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_between_card_padding
-                        : R.dimen.tab_list_card_padding);
+        return context.getResources().getDimension(R.dimen.tab_grid_card_between_card_padding);
     }
 
     /**
@@ -631,9 +518,7 @@
      * @return The padding between between mini thumbnails in float number.
      */
     public static float getTabMiniThumbnailPaddingDimension(Context context) {
-        return context.getResources().getDimension(themeRefactorEnabled()
-                        ? R.dimen.tab_grid_card_thumbnail_margin
-                        : R.dimen.tab_list_card_padding);
+        return context.getResources().getDimension(R.dimen.tab_grid_card_thumbnail_margin);
     }
 
     /**
@@ -644,10 +529,6 @@
      * @return The margin between tab cards in float number.
      */
     public static float getTabGridCardMarginForDialogAnimation(Context context) {
-        if (!themeRefactorEnabled()) {
-            return context.getResources().getDimension(R.dimen.tab_list_card_padding);
-        }
-
         int[] attrs = {R.attr.tabGridMargin};
 
         TypedArray ta = context.obtainStyledAttributes(getThemeOverlayStyleResourceId(), attrs);
@@ -665,13 +546,7 @@
      */
     @StyleRes
     public static int getThemeOverlayStyleResourceId() {
-        return themeRefactorEnabled() ? R.style.ThemeRefactorOverlay_Enabled_TabUi
-                                      : R.style.ThemeRefactorOverlay_Disabled_TabUi;
-    }
-
-    /** Return if theme refactor is enabled. **/
-    static boolean themeRefactorEnabled() {
-        return CachedFeatureFlags.isEnabled(ChromeFeatureList.THEME_REFACTOR_ANDROID);
+        return R.style.ThemeRefactorOverlay_Enabled_TabUi;
     }
 
     /**
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 c356fc63..8fb36c6 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
@@ -23,6 +23,8 @@
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.test.filters.SmallTest;
 
+import com.google.android.material.color.MaterialColors;
+
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
@@ -48,7 +50,9 @@
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 public class TabGridPanelViewBinderTest extends DummyUiActivityTestCase {
+    private static final String TAG = "TGPVBT";
     private static final int CONTENT_TOP_MARGIN = 56;
+
     private PropertyModel mModel;
     private PropertyModelChangeProcessor mMCP;
     private TabGroupUiToolbarView mToolbarView;
@@ -290,10 +294,9 @@
     @SmallTest
     @UiThreadTest
     public void testSetDialogBackgroundColor() {
-        int normalColor =
-                ContextCompat.getColor(getActivity(), R.color.tab_grid_dialog_background_color);
+        int normalColor = MaterialColors.getColor(getActivity(), R.attr.colorSurface, TAG);
         int incognitoColor = ContextCompat.getColor(
-                getActivity(), R.color.tab_grid_dialog_background_color_incognito);
+                getActivity(), R.color.incognito_tab_grid_dialog_background_color);
         // Default setup is in normal mode.
         Assert.assertEquals(normalColor, mTabGridDialogView.getBackgroundColorForTesting());
 
@@ -306,10 +309,9 @@
     @SmallTest
     @UiThreadTest
     public void testSetUngroupbarBackgroundColor() {
-        int normalColor =
-                ContextCompat.getColor(getActivity(), R.color.tab_grid_dialog_background_color);
+        int normalColor = MaterialColors.getColor(getActivity(), R.attr.colorSurface, TAG);
         int incognitoColor = ContextCompat.getColor(
-                getActivity(), R.color.tab_grid_dialog_background_color_incognito);
+                getActivity(), R.color.incognito_tab_grid_dialog_background_color);
         // Default setup is in normal mode.
         Assert.assertEquals(
                 normalColor, mTabGridDialogView.getUngroupBarBackgroundColorForTesting());
@@ -324,29 +326,27 @@
     @SmallTest
     @UiThreadTest
     public void testSetUngroupbarHoveredBackgroundColor() {
-        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);
+        int normalColor = MaterialColors.getColor(getActivity(), R.attr.colorPrimary, TAG);
+        int incognitoColor = ContextCompat.getColor(
+                getActivity(), R.color.incognito_tab_grid_dialog_ungroup_bar_bg_hovered_color);
         // Default setup is in normal mode.
         Assert.assertEquals(
-                normalColorId, mTabGridDialogView.getUngroupBarHoveredBackgroundColorForTesting());
+                normalColor, mTabGridDialogView.getUngroupBarHoveredBackgroundColorForTesting());
 
-        mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR,
-                incognitoColorId);
+        mModel.set(
+                TabGridPanelProperties.DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR, incognitoColor);
 
-        Assert.assertEquals(incognitoColorId,
-                mTabGridDialogView.getUngroupBarHoveredBackgroundColorForTesting());
+        Assert.assertEquals(
+                incognitoColor, mTabGridDialogView.getUngroupBarHoveredBackgroundColorForTesting());
     }
 
     @Test
     @SmallTest
     @UiThreadTest
     public void testSetUngroupbarTextColor() {
-        int normalColor = ContextCompat.getColor(
-                getActivity(), R.color.tab_grid_dialog_ungroup_button_text_color);
+        int normalColor = MaterialColors.getColor(getActivity(), R.attr.colorPrimary, TAG);
         int incognitoColor = ContextCompat.getColor(
-                getActivity(), R.color.tab_grid_dialog_ungroup_button_text_color_incognito);
+                getActivity(), R.color.incognito_tab_grid_dialog_ungroup_bar_text_color);
         // Default setup is in normal mode.
         Assert.assertEquals(normalColor, mTabGridDialogView.getUngroupBarTextColorForTesting());
 
@@ -359,12 +359,9 @@
     @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 normalColor = MaterialColors.getColor(getActivity(), R.attr.colorOnPrimary, TAG);
         int incognitoColor = ContextCompat.getColor(
-                getActivity(), R.color.tab_grid_dialog_ungroup_button_text_color_incognito);
+                getActivity(), R.color.incognito_tab_grid_dialog_ungroup_bar_text_hovered_color);
         // Default setup is in normal mode.
         Assert.assertEquals(
                 normalColor, mTabGridDialogView.getUngroupBarHoveredTextColorForTesting());
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
index 0c2e6c1..fddb9c1 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
@@ -11,7 +11,6 @@
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -22,7 +21,6 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
@@ -302,18 +300,10 @@
     }
 
     private void testGridSelected(ViewGroup holder, PropertyModel model) {
-        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
-            model.set(TabProperties.IS_SELECTED, true);
-            Assert.assertNotNull(holder.getForeground());
-            model.set(TabProperties.IS_SELECTED, false);
-            Assert.assertNull(holder.getForeground());
-        } else {
-            model.set(TabProperties.IS_SELECTED, true);
-            View selectedView = holder.findViewById(R.id.selected_view_below_lollipop);
-            Assert.assertEquals(View.VISIBLE, selectedView.getVisibility());
-            model.set(TabProperties.IS_SELECTED, false);
-            Assert.assertEquals(View.GONE, selectedView.getVisibility());
-        }
+        model.set(TabProperties.IS_SELECTED, true);
+        Assert.assertTrue(TabSelectionEditorTestingRobot.isTabViewSelected(holder));
+        model.set(TabProperties.IS_SELECTED, false);
+        Assert.assertFalse(TabSelectionEditorTestingRobot.isTabViewSelected(holder));
     }
 
     private void testSelectableTabClickToSelect(
@@ -384,13 +374,7 @@
                 () -> !((ClosableTabGridView) mTabGridView).getIsAnimatingForTesting());
 
         Assert.assertEquals(View.GONE, backgroundView.getVisibility());
-        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
-            View selectedView = mTabGridView.findViewById(R.id.selected_view_below_lollipop);
-            Assert.assertEquals(View.VISIBLE, selectedView.getVisibility());
-        } else {
-            Drawable selectedDrawable = mTabGridView.getForeground();
-            Assert.assertNotNull(selectedDrawable);
-        }
+        Assert.assertTrue(TabSelectionEditorTestingRobot.isTabViewSelected(mTabGridView));
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             mGridModel.set(TabProperties.IS_SELECTED, false);
@@ -400,14 +384,7 @@
         CriteriaHelper.pollUiThread(
                 () -> !((ClosableTabGridView) mTabGridView).getIsAnimatingForTesting());
         Assert.assertEquals(View.GONE, backgroundView.getVisibility());
-
-        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
-            View selectedView = mTabGridView.findViewById(R.id.selected_view_below_lollipop);
-            Assert.assertEquals(View.GONE, selectedView.getVisibility());
-        } else {
-            Drawable selectedDrawable = mTabGridView.getForeground();
-            Assert.assertNull(selectedDrawable);
-        }
+        Assert.assertFalse(TabSelectionEditorTestingRobot.isTabViewSelected(mTabGridView));
     }
 
     @Test
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTestingRobot.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTestingRobot.java
index a5ec052..d87f6c99 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTestingRobot.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTestingRobot.java
@@ -27,9 +27,11 @@
 import static org.chromium.chrome.browser.tasks.tab_management.RecyclerViewMatcherUtils.atPositionWithViewHolder;
 import static org.chromium.chrome.browser.tasks.tab_management.RecyclerViewMatcherUtils.withItemType;
 
-import android.os.Build;
 import android.view.View;
+import android.view.ViewGroup;
 
+import androidx.annotation.ColorInt;
+import androidx.core.view.ViewCompat;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.test.espresso.NoMatchingRootException;
 import androidx.test.espresso.NoMatchingViewException;
@@ -67,7 +69,7 @@
                 mSelectableTabGridView = selectableTabGridView;
 
                 return mSelectableTabGridView.isChecked() && actionButtonSelected()
-                        && highlightIndicatorIsVisible();
+                        && isTabViewSelected(mSelectableTabGridView);
             }
 
             @Override
@@ -83,22 +85,47 @@
                                    .getBackground()
                                    .getLevel();
             }
-
-            private boolean highlightIndicatorIsVisible() {
-                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
-                    return mSelectableTabGridView
-                                   .findViewById(org.chromium.chrome.tab_ui.R.id
-                                                         .selected_view_below_lollipop)
-                                   .getVisibility()
-                            == View.VISIBLE;
-                } else {
-                    return mSelectableTabGridView.getForeground() != null;
-                }
-            }
         };
     }
 
     /**
+     * Infers whether the tab is currently selected, by making assumptions about what the view state
+     * should look like. This method is fairly fragile to changes in implementation.
+     * @param holder The root of the tab {@link View} objects.
+     * @return Whether the tab is currently selected.
+     */
+    public static boolean isTabViewSelected(ViewGroup holder) {
+        // Tab list was not migrated to use new color scheme/logic. Instead having a foreground
+        // Drawable means it is selected.
+        if (holder.getId() == org.chromium.chrome.tab_ui.R.id.selectable_tab_list_card_item) {
+            return holder.getForeground() != null;
+        }
+
+        View cardView = holder.findViewById(org.chromium.chrome.tab_ui.R.id.card_view);
+        final @ColorInt int actualColor =
+                ViewCompat.getBackgroundTintList(cardView).getDefaultColor();
+
+        final @ColorInt int incogSelected = TabUiThemeProvider.getCardViewBackgroundColor(
+                holder.getContext(), /*isIncognito*/ true, /*isSelected*/ true);
+        final @ColorInt int normalSelected = TabUiThemeProvider.getCardViewBackgroundColor(
+                holder.getContext(), /*isIncognito*/ false, /*isSelected*/ true);
+        final @ColorInt int incogNotSelected = TabUiThemeProvider.getCardViewBackgroundColor(
+                holder.getContext(), /*isIncognito*/ true, /*isSelected*/ false);
+        final @ColorInt int normalNotSelected = TabUiThemeProvider.getCardViewBackgroundColor(
+                holder.getContext(), /*isIncognito*/ false, /*isSelected*/ false);
+
+        // This approach only works when there is no overlap between selected and unselected colors.
+        // If this assertion stops holding true, we could try requiring incognito information to be
+        // passed into this method.
+        Assert.assertNotEquals(incogSelected, incogNotSelected);
+        Assert.assertNotEquals(incogSelected, normalNotSelected);
+        Assert.assertNotEquals(normalSelected, incogNotSelected);
+        Assert.assertNotEquals(normalSelected, normalNotSelected);
+
+        return actualColor == incogSelected || actualColor == normalSelected;
+    }
+
+    /**
      * @return A view matcher that matches a divider view.
      */
     public static Matcher<View> isDivider() {
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java
index d1c28f55..2fd67e6 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java
@@ -28,6 +28,12 @@
 import android.view.View;
 import android.widget.EditText;
 
+import androidx.annotation.AttrRes;
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+
+import com.google.android.material.color.MaterialColors;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -38,6 +44,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
 
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
@@ -77,12 +85,43 @@
  */
 @SuppressWarnings({"ArraysAsListWithZeroOrOneArgument", "ResultOfMethodCallIgnored"})
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
+@Config(manifest = Config.NONE,
+        shadows = {TabGridDialogMediatorUnitTest.ShadowMaterialColors.class})
 // clang-format off
 @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID})
 @Features.DisableFeatures(ChromeFeatureList.TAB_GROUPS_CONTINUATION_ANDROID)
+// clang-format on
 public class TabGridDialogMediatorUnitTest {
-    // clang-format on
+    // Cannot easily mock Theme because it is a final class. Instead shadow MaterialColors. The
+    // actual color value doesn't matter, just need to not NPE with Context/Theme/TypedValue object
+    // interactions.
+    @Implements(MaterialColors.class)
+    static class ShadowMaterialColors {
+        @Implementation
+        @ColorInt
+        public static int getColor(@NonNull View view, @AttrRes int colorAttributeResId) {
+            return 0;
+        }
+
+        @ColorInt
+        public static int getColor(
+                Context context, @AttrRes int colorAttributeResId, String errorMessageComponent) {
+            return 0;
+        }
+
+        @ColorInt
+        public static int getColor(
+                @NonNull View view, @AttrRes int colorAttributeResId, @ColorInt int defaultValue) {
+            return 0;
+        }
+
+        @ColorInt
+        public static int getColor(@NonNull Context context, @AttrRes int colorAttributeResId,
+                @ColorInt int defaultValue) {
+            return 0;
+        }
+    }
+
     @Rule
     public TestRule mProcessor = new Features.JUnitProcessor();
 
@@ -145,7 +184,6 @@
 
     @Before
     public void setUp() {
-
         MockitoAnnotations.initMocks(this);
 
         mTab1 = prepareTab(TAB1_ID, TAB1_TITLE);
diff --git a/chrome/android/features/vr/BUILD.gn b/chrome/android/features/vr/BUILD.gn
index 77aa17e..ee2523d 100644
--- a/chrome/android/features/vr/BUILD.gn
+++ b/chrome/android/features/vr/BUILD.gn
@@ -80,6 +80,7 @@
     "//chrome/browser/tab:java",
     "//chrome/browser/tabmodel:java",
     "//chrome/browser/ui/android/omnibox:util_java",
+    "//chrome/browser/ui/android/page_info:java",
     "//chrome/browser/ui/messages/android:java",
     "//chrome/browser/util:java",
     "//components/browser_ui/modaldialog/android:java",
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
index 80d03bc..11b971b5 100644
--- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
+++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
@@ -48,6 +48,7 @@
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
 import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionUtil;
 import org.chromium.chrome.browser.page_info.ChromePageInfo;
+import org.chromium.chrome.browser.page_info.ChromePageInfoHighlight;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.RedirectHandlerTabHelper;
 import org.chromium.chrome.browser.tab.Tab;
@@ -67,7 +68,6 @@
 import org.chromium.chrome.browser.vr.keyboard.VrInputMethodManagerWrapper;
 import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController;
 import org.chromium.components.external_intents.RedirectHandler;
-import org.chromium.components.page_info.PageInfoController;
 import org.chromium.components.page_info.PageInfoController.OpenedFromSource;
 import org.chromium.content_public.browser.ImeAdapter;
 import org.chromium.content_public.browser.LoadUrlParams;
@@ -604,7 +604,7 @@
         if (tab == null) return;
         new ChromePageInfo(mModalDialogManagerSupplier, null, OpenedFromSource.VR,
                 /*storeInfoActionHandlerSupplier=*/null)
-                .show(tab, PageInfoController.NO_HIGHLIGHTED_PERMISSION, /*fromStoreIcon=*/false);
+                .show(tab, ChromePageInfoHighlight.noHighlight());
     }
 
     // Called because showing audio permission dialog isn't supported in VR. This happens when
diff --git a/chrome/android/java/res/drawable-hdpi/toolbar_shadow_focused.png b/chrome/android/java/res/drawable-hdpi/toolbar_shadow_focused.png
deleted file mode 100644
index e380331e..0000000
--- a/chrome/android/java/res/drawable-hdpi/toolbar_shadow_focused.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/toolbar_shadow_normal.png b/chrome/android/java/res/drawable-hdpi/toolbar_shadow_normal.png
deleted file mode 100644
index 83afe5e..0000000
--- a/chrome/android/java/res/drawable-hdpi/toolbar_shadow_normal.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/toolbar_shadow_focused.png b/chrome/android/java/res/drawable-mdpi/toolbar_shadow_focused.png
deleted file mode 100644
index f616007..0000000
--- a/chrome/android/java/res/drawable-mdpi/toolbar_shadow_focused.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/toolbar_shadow_normal.png b/chrome/android/java/res/drawable-mdpi/toolbar_shadow_normal.png
deleted file mode 100644
index a39d3a8..0000000
--- a/chrome/android/java/res/drawable-mdpi/toolbar_shadow_normal.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-sw600dp/toolbar_shadow.xml b/chrome/android/java/res/drawable-sw600dp/toolbar_shadow.xml
deleted file mode 100644
index d4108dfb..0000000
--- a/chrome/android/java/res/drawable-sw600dp/toolbar_shadow.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/toolbar_shadow_normal"
-    android:gravity="top|fill_horizontal" />
diff --git a/chrome/android/java/res/drawable-xhdpi/toolbar_shadow_focused.png b/chrome/android/java/res/drawable-xhdpi/toolbar_shadow_focused.png
deleted file mode 100644
index ace8517..0000000
--- a/chrome/android/java/res/drawable-xhdpi/toolbar_shadow_focused.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/toolbar_shadow_normal.png b/chrome/android/java/res/drawable-xhdpi/toolbar_shadow_normal.png
deleted file mode 100644
index 02e03cf..0000000
--- a/chrome/android/java/res/drawable-xhdpi/toolbar_shadow_normal.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/toolbar_shadow_focused.png b/chrome/android/java/res/drawable-xxhdpi/toolbar_shadow_focused.png
deleted file mode 100644
index da197d31..0000000
--- a/chrome/android/java/res/drawable-xxhdpi/toolbar_shadow_focused.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/toolbar_shadow_normal.png b/chrome/android/java/res/drawable-xxhdpi/toolbar_shadow_normal.png
deleted file mode 100644
index af20aca0..0000000
--- a/chrome/android/java/res/drawable-xxhdpi/toolbar_shadow_normal.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/toolbar_shadow_focused.png b/chrome/android/java/res/drawable-xxxhdpi/toolbar_shadow_focused.png
deleted file mode 100644
index 410b0516..0000000
--- a/chrome/android/java/res/drawable-xxxhdpi/toolbar_shadow_focused.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/toolbar_shadow_normal.png b/chrome/android/java/res/drawable-xxxhdpi/toolbar_shadow_normal.png
deleted file mode 100644
index 95f647a2..0000000
--- a/chrome/android/java/res/drawable-xxxhdpi/toolbar_shadow_normal.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable/toolbar_shadow.xml b/chrome/android/java/res/drawable/toolbar_shadow.xml
deleted file mode 100644
index fefb304..0000000
--- a/chrome/android/java/res/drawable/toolbar_shadow.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
-    <item>
-        <bitmap
-            android:src="@drawable/toolbar_shadow_normal"
-            android:gravity="top|fill_horizontal" />
-    </item>
-    <item>
-        <bitmap
-            android:src="@drawable/toolbar_shadow_focused"
-            android:gravity="top|fill_horizontal" />
-    </item>
-</transition>
diff --git a/chrome/android/java/res/layout/bookmark_save_flow.xml b/chrome/android/java/res/layout/bookmark_save_flow.xml
index ac24562..368eb32 100644
--- a/chrome/android/java/res/layout/bookmark_save_flow.xml
+++ b/chrome/android/java/res/layout/bookmark_save_flow.xml
@@ -1,11 +1,13 @@
-<?xml version="1.0" encoding="utf-8"?><!-- Copyright 2021 The Chromium Authors. All rights reserved.
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
 
 <org.chromium.ui.widget.ViewLookupCachingFrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    android:focusable="true">
 
   <LinearLayout
       android:layout_width="match_parent"
@@ -26,45 +28,45 @@
           android:layout_gravity="center_vertical|start"
           android:background="@drawable/bookmark_save_flow_background"
           android:foreground="@drawable/bookmark_save_flow_ripple"
-          android:scaleType="centerInside" />
-
-      <LinearLayout
-          android:layout_width="match_parent"
-          android:layout_height="wrap_content"
-          android:layout_gravity="center_vertical|start"
-          android:orientation="horizontal">
+          android:scaleType="centerInside"
+          android:contentDescription="@string/bookmark_action_bar_edit_folder" />
 
         <LinearLayout
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:orientation="vertical">
+            android:layout_gravity="center_vertical|start"
+            android:orientation="vertical"
+            android:screenReaderFocusable="true"
+            android:focusable="true">
 
           <TextView
               android:id="@+id/title_text"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:ellipsize="end"
-              android:textAppearance="@style/TextAppearance.TextMediumThick.Primary" />
+              android:textAppearance="@style/TextAppearance.TextMediumThick.Primary"
+              android:focusable="false" />
 
           <TextView
               android:id="@+id/subtitle_text"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:ellipsize="end"
-              android:textAppearance="@style/TextAppearance.TextMedium.Primary" />
+              android:textAppearance="@style/TextAppearance.TextMedium.Primary"
+              android:focusable="false" />
         </LinearLayout>
 
-        <TextView
-            android:id="@+id/bookmark_edit"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:layout_gravity="center_vertical"
-            android:gravity="end"
-            android:text="@string/bookmark_item_edit"
-            android:paddingHorizontal="24dp"
-            android:textAppearance="@style/TextAppearance.TextMedium.Blue" />
-      </LinearLayout>
+      <org.chromium.ui.widget.ButtonCompat
+          android:id="@+id/bookmark_edit"
+          android:layout_width="0dp"
+          android:layout_height="72dp"
+          android:layout_weight="1"
+          android:gravity="center|end"
+          android:layout_gravity="end"
+          android:text="@string/bookmark_item_edit"
+          android:textAppearance="@style/TextAppearance.TextMedium.Blue"
+          style="@style/TextButton"
+          android:paddingEnd="24dp" />
     </LinearLayout>
 
     <View
@@ -92,7 +94,7 @@
           android:layout_width="0dp"
           android:layout_height="wrap_content"
           android:layout_weight="1"
-          android:layout_gravity="center_vertical" 
+          android:layout_gravity="center_vertical"
           android:orientation="vertical">
         <TextView
             android:id="@+id/notification_switch_title"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 1da1584..04ff65e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1628,18 +1628,12 @@
 
     @Override
     protected int getToolbarShadowResource() {
-        final boolean themeRefactorEnabled =
-                CachedFeatureFlags.isEnabled(ChromeFeatureList.THEME_REFACTOR_ANDROID);
-        return themeRefactorEnabled ? R.drawable.toolbar_hairline
-                                    : R.drawable.modern_toolbar_shadow;
+        return R.drawable.toolbar_hairline;
     }
 
     @Override
     protected int getToolbarShadowLayoutHeight() {
-        final int res = CachedFeatureFlags.isEnabled(ChromeFeatureList.THEME_REFACTOR_ANDROID)
-                ? R.dimen.toolbar_hairline_height
-                : R.dimen.toolbar_shadow_height;
-        return getResources().getDimensionPixelSize(res);
+        return getResources().getDimensionPixelSize(R.dimen.toolbar_hairline_height);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
index 1eb888d..262f519 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -143,6 +143,7 @@
 import org.chromium.chrome.browser.offlinepages.indicator.OfflineIndicatorController;
 import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper;
 import org.chromium.chrome.browser.page_info.ChromePageInfo;
+import org.chromium.chrome.browser.page_info.ChromePageInfoHighlight;
 import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.printing.PrintShareActivity;
@@ -209,7 +210,6 @@
 import org.chromium.components.embedder_support.util.UrlUtilities;
 import org.chromium.components.feature_engagement.EventConstants;
 import org.chromium.components.feature_engagement.Tracker;
-import org.chromium.components.page_info.PageInfoController;
 import org.chromium.components.page_info.PageInfoController.OpenedFromSource;
 import org.chromium.components.policy.CombinedPolicyProvider;
 import org.chromium.components.policy.CombinedPolicyProvider.PolicyChangeListener;
@@ -2537,8 +2537,7 @@
             ChromePageInfo pageInfo = new ChromePageInfo(getModalDialogManagerSupplier(), null,
                     OpenedFromSource.MENU,
                     () -> mRootUiCoordinator.getMerchantTrustSignalsCoordinatorSupplier().get());
-            pageInfo.show(currentTab, PageInfoController.NO_HIGHLIGHTED_PERMISSION,
-                    /*fromStoreIcon=*/false);
+            pageInfo.show(currentTab, ChromePageInfoHighlight.noHighlight());
             return true;
         }
 
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 7f0624fb..bf633652 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
@@ -107,7 +107,6 @@
                 add(ChromeFeatureList.TAB_GROUPS_ANDROID);
                 add(ChromeFeatureList.TAB_GROUPS_CONTINUATION_ANDROID);
                 add(ChromeFeatureList.TAB_TO_GTS_ANIMATION);
-                add(ChromeFeatureList.THEME_REFACTOR_ANDROID);
                 add(ChromeFeatureList.TOOLBAR_USE_HARDWARE_BITMAP_DRAW);
                 add(ChromeFeatureList.USE_CHIME_ANDROID_SDK);
                 add(ChromeFeatureList.WEB_APK_TRAMPOLINE_ON_INITIAL_INTENT);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java
index b400ea39..8b1368e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java
@@ -24,6 +24,7 @@
 import org.chromium.chrome.browser.autofill.settings.AutofillProfileBridge.AddressUiComponent;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.payments.AutofillAddress;
+import org.chromium.chrome.browser.payments.AutofillAddress.CompletenessCheckType;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -151,7 +152,8 @@
         final String editTitle;
         final AutofillAddress address;
         if (toEdit == null) {
-            address = new AutofillAddress(mContext, new AutofillProfile());
+            address = new AutofillAddress(
+                    mContext, new AutofillProfile(), getCompletenessCheckType());
             editTitle = mContext.getString(R.string.autofill_create_profile);
         } else {
             address = toEdit;
@@ -240,26 +242,26 @@
                     EditorFieldModel.createTextInput(EditorFieldModel.INPUT_TYPE_HINT_PERSON_NAME));
         }
 
-        // Phone number is present for all countries.
-        if (mPhoneField == null) {
-            String requiredErrorMessage = mCheckRequiredFields
-                    ? mContext.getString(
-                            R.string.pref_edit_dialog_field_required_validation_message)
-                    : null;
-            mPhoneField = EditorFieldModel.createTextInput(EditorFieldModel.INPUT_TYPE_HINT_PHONE,
-                    mContext.getString(R.string.autofill_profile_editor_phone_number),
-                    mPhoneNumbers, mPhoneFormatter, mPhoneValidator, null /* valueIconGenerator */,
-                    requiredErrorMessage,
-                    mContext.getString(R.string.payments_phone_invalid_validation_message),
-                    EditorFieldModel.LENGTH_COUNTER_LIMIT_NONE, null /* value */);
-        }
-
-        // Phone number field is cached, so its value needs to be updated for every new profile
-        // that's being edited.
-        mPhoneField.setValue(mProfile.getPhoneNumber());
-
-        // Email address is present only for autofill settings.
+        // Email address and phone number are present only for autofill settings.
         if (mPurpose == Purpose.AUTOFILL_SETTINGS) {
+            // Phone number is present for all countries.
+            if (mPhoneField == null) {
+                String requiredErrorMessage = mCheckRequiredFields
+                        ? mContext.getString(
+                                R.string.pref_edit_dialog_field_required_validation_message)
+                        : null;
+                mPhoneField = EditorFieldModel.createTextInput(
+                        EditorFieldModel.INPUT_TYPE_HINT_PHONE,
+                        mContext.getString(R.string.autofill_profile_editor_phone_number),
+                        mPhoneNumbers, mPhoneFormatter, mPhoneValidator,
+                        null /* valueIconGenerator */, requiredErrorMessage,
+                        mContext.getString(R.string.payments_phone_invalid_validation_message),
+                        EditorFieldModel.LENGTH_COUNTER_LIMIT_NONE, null /* value */);
+            }
+            // Phone number field is cached, so its value needs to be updated for every new profile
+            // that's being edited.
+            mPhoneField.setValue(mProfile.getPhoneNumber());
+
             if (mEmailField == null) {
                 mEmailField = EditorFieldModel.createTextInput(
                         EditorFieldModel.INPUT_TYPE_HINT_EMAIL,
@@ -306,12 +308,17 @@
         mEditorDialog.show(mEditor);
     }
 
+    public @CompletenessCheckType int getCompletenessCheckType() {
+        return mPurpose == Purpose.AUTOFILL_ASSISTANT ? CompletenessCheckType.IGNORE_PHONE
+                                                      : CompletenessCheckType.NORMAL;
+    }
+
     /** Saves the edited profile on disk. */
     private void commitChanges(AutofillProfile profile) {
         // Country code and phone number are always required and are always collected from the
         // editor model.
         profile.setCountryCode(mCountryField.getValue().toString());
-        profile.setPhoneNumber(mPhoneField.getValue().toString());
+        if (mPhoneField != null) profile.setPhoneNumber(mPhoneField.getValue().toString());
         if (mEmailField != null) profile.setEmailAddress(mEmailField.getValue().toString());
         if (mHonorificField != null) {
             profile.setHonorificPrefix(mHonorificField.getValue().toString());
@@ -443,7 +450,7 @@
             mEditor.addField(field);
         }
         // Phone number (and email/nickname if applicable) are the last fields of the address.
-        mEditor.addField(mPhoneField);
+        if (mPhoneField != null) mEditor.addField(mPhoneField);
         if (mEmailField != null) mEditor.addField(mEmailField);
         if (mNicknameField != null) mEditor.addField(mNicknameField);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/CardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/CardEditor.java
index f5bfca58..c7d25377 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/CardEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/CardEditor.java
@@ -723,7 +723,8 @@
                     profile = findTargetProfile(mProfilesForBillingAddress, eventData.first);
                 }
 
-                final AutofillAddress editAddress = new AutofillAddress(mContext, profile);
+                final AutofillAddress editAddress = new AutofillAddress(
+                        mContext, profile, mAddressEditor.getCompletenessCheckType());
                 mAddressEditor.edit(editAddress, new Callback<AutofillAddress>() {
                     @Override
                     public void onResult(AutofillAddress billingAddress) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowCoordinator.java
index c92db9b..a6fdabb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowCoordinator.java
@@ -7,6 +7,7 @@
 import android.content.Context;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -98,7 +99,11 @@
         mBottomSheetController.requestShowContent(mBottomSheetContent, /* animate= */ true);
         mMediator.show(bookmarkId, meta, fromExplicitTrackUi);
 
-        setupAutodismiss();
+        AccessibilityManager am =
+                (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        if (!am.isTouchExplorationEnabled()) {
+            setupAutodismiss();
+        }
     }
 
     private void close() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowMediator.java
index 11050c12..8ecbdc5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowMediator.java
@@ -172,7 +172,11 @@
 
     @Override
     public void bookmarkModelChanged() {
-        if (mBookmarkId == null) return;
+        // Possibility that the bookmark is deleted while in accessibility mode.
+        if (mBookmarkId == null || mBookmarkModel.getBookmarkById(mBookmarkId) == null) {
+            mCloseRunnable.run();
+            return;
+        }
         bindBookmarkProperties(mBookmarkId, mPowerBookmarkMeta, mFromExplicitTrackUi);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
index 807987c..6b6d83c9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -43,8 +43,6 @@
 import org.chromium.chrome.browser.dependency_injection.ChromeActivityCommonsModule;
 import org.chromium.chrome.browser.dependency_injection.ModuleFactoryOverrides;
 import org.chromium.chrome.browser.flags.ActivityType;
-import org.chromium.chrome.browser.flags.CachedFeatureFlags;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.metrics.UmaSessionStats;
 import org.chromium.chrome.browser.night_mode.NightModeStateProvider;
 import org.chromium.chrome.browser.night_mode.PowerSavingModeMonitor;
@@ -395,9 +393,7 @@
 
     @Override
     protected int getToolbarShadowResource() {
-        final boolean themeRefactorEnabled =
-                CachedFeatureFlags.isEnabled(ChromeFeatureList.THEME_REFACTOR_ANDROID);
-        return themeRefactorEnabled ? R.drawable.toolbar_hairline : R.drawable.toolbar_shadow;
+        return R.drawable.toolbar_hairline;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 51d79c6..540f46e3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -42,8 +42,8 @@
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
 import org.chromium.chrome.browser.night_mode.NightModeStateProvider;
 import org.chromium.chrome.browser.page_info.ChromePageInfo;
+import org.chromium.chrome.browser.page_info.ChromePageInfoHighlight;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.components.page_info.PageInfoController;
 import org.chromium.components.page_info.PageInfoController.OpenedFromSource;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
@@ -213,8 +213,7 @@
             String publisher = getToolbarManager().getContentPublisher();
             new ChromePageInfo(getModalDialogManagerSupplier(), publisher, OpenedFromSource.MENU,
                     () -> mRootUiCoordinator.getMerchantTrustSignalsCoordinatorSupplier().get())
-                    .show(tab, PageInfoController.NO_HIGHLIGHTED_PERMISSION,
-                            /*fromStoreIcon=*/false);
+                    .show(tab, ChromePageInfoHighlight.noHighlight());
             return true;
         }
         return super.onMenuOrKeyboardAction(id, fromMenu);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
index 65c6ad6..190e743d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
@@ -57,6 +57,7 @@
 import org.chromium.chrome.browser.omnibox.UrlBarData;
 import org.chromium.chrome.browser.omnibox.styles.OmniboxTheme;
 import org.chromium.chrome.browser.page_info.ChromePageInfo;
+import org.chromium.chrome.browser.page_info.ChromePageInfoHighlight;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TrustedCdn;
 import org.chromium.chrome.browser.theme.ThemeUtils;
@@ -68,7 +69,6 @@
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.browser_ui.widget.TintedDrawable;
 import org.chromium.components.embedder_support.util.UrlUtilities;
-import org.chromium.components.page_info.PageInfoController;
 import org.chromium.components.page_info.PageInfoController.OpenedFromSource;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.WebContents;
@@ -734,8 +734,7 @@
                 // For now we don't show "store info" row for custom tab.
                 new ChromePageInfo(mModalDialogManagerSupplier, getContentPublisher(),
                         OpenedFromSource.TOOLBAR, /*storeInfoActionHandlerSupplier=*/null)
-                        .show(currentTab, PageInfoController.NO_HIGHLIGHTED_PERMISSION,
-                                /*fromStoreIcon=*/false);
+                        .show(currentTab, ChromePageInfoHighlight.noHighlight());
             });
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java b/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java
index 8fea615..ce0a22f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java
@@ -33,6 +33,8 @@
 import org.chromium.components.url_formatter.UrlFormatter;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.common.Referrer;
+import org.chromium.network.mojom.ReferrerPolicy;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.url.GURL;
 
@@ -63,6 +65,22 @@
     boolean mTriggerPreload;
     // Records whether a preloaded tab matched.
     boolean mTabMatches;
+    // Records whether we have already recorded the histogram for the duration between the load
+    // decision and the match decision; this histogram should be recorded only on the first match
+    // decision.
+    private boolean mRecordedLoadDecisionToMatchDecisionHistogram;
+
+    // Whether a tab preload was prevented only by the ElideTabPreloadAtStartup feature.
+    private boolean mPreloadPreventedOnlyByFeature;
+    // The params that would have been used for the preload if not prevented by the feature.
+    // NOTE: We explicitly track only the params that are necessary for comparison of tab matching
+    // to avoid calling IntentHandler#createLoadUrlParamsForIntent(). The latter is undesirable
+    // because it is destructive to the intent metadata, which is problematic in the case where the
+    // LoadUrlParams are not intended for usage (as they're not here).
+    private String mUrlForPreloadPreventedOnlyByFeature;
+    private String mReferrerForPreloadPreventedOnlyByFeature;
+    // Whether the tab preload that was prevented only by the feature would have matched.
+    private boolean mPreloadPreventedOnlyByFeatureWouldHaveMatched;
 
     public static void failNextTabMatchForTesting() {
         sFailNextTabMatchForTesting = true;
@@ -84,6 +102,18 @@
         ActivityTabStartupMetricsTracker.addObserver(this);
     }
 
+    // Returns true if a startup tab preload either (a) was triggered or (b) was prevented
+    // from triggering only by the ElideTabPreloadAtStartup Feature.
+    private boolean preloadWasViable() {
+        return mTriggerPreload || mPreloadPreventedOnlyByFeature;
+    }
+
+    // Returns true if a match of a preloaded tab either (a) occurred or (b) was prevented from
+    // occurring only by the ElideTabPreloadAtStartup Feature.
+    private boolean tabMatchWasViable() {
+        return mTabMatches || mPreloadPreventedOnlyByFeatureWouldHaveMatched;
+    }
+
     @Override
     public void onDestroy() {
         if (mTab != null) mTab.destroy();
@@ -96,38 +126,55 @@
 
     @Override
     public void onFirstNavigationStart() {
-        if (mLoadDecisionMs == 0) return;
-
-        long currentTimeMs = SystemClock.uptimeMillis();
-        long triggerpointToFirstNavigationStartMs = currentTimeMs - mLoadDecisionMs;
-
-        // Note that we don't use recordDurationFromLoadDecisionIntoHistogram() here as this
-        // point is reached before tab matching occurs.
-        String suffix = mTriggerPreload ? ".Load" : ".NoLoad";
-        RecordHistogram.recordMediumTimesHistogram(
-                "Android.StartupTabPreloader.LoadDecisionToFirstNavigationStart" + suffix,
-                triggerpointToFirstNavigationStartMs);
+        recordDurationFromLoadDecisionIntoPreTabMatchHistogram(
+                "Android.StartupTabPreloader.LoadDecisionToFirstNavigationStart");
     }
 
     @Override
     public void onFirstVisibleContent() {
-        recordDurationFromLoadDecisionIntoHistogram(
+        recordDurationFromLoadDecisionIntoPostTabMatchHistogram(
                 "Android.StartupTabPreloader.LoadDecisionToFirstVisibleContent");
     }
 
+    @Override
+    public void onFirstNavigationCommit() {
+        recordDurationFromLoadDecisionIntoPostTabMatchHistogram(
+                "Android.StartupTabPreloader.LoadDecisionToFirstNavigationCommit");
+    }
+
+    @Override
+    public void onFirstContentfulPaint() {
+        recordDurationFromLoadDecisionIntoPostTabMatchHistogram(
+                "Android.StartupTabPreloader.LoadDecisionToFirstContentfulPaint");
+    }
+
     // Records the duration from the load decision to the current time into |histogram| (suffixed
-    // by the state of the tab preload and match decisions).
-    private void recordDurationFromLoadDecisionIntoHistogram(String histogram) {
+    // by the state of the tab preload decision). To be used when the current time is before the
+    // tab match decision has occurred.
+    private void recordDurationFromLoadDecisionIntoPreTabMatchHistogram(String histogram) {
+        if (mLoadDecisionMs == 0) return;
+
+        long currentTimeMs = SystemClock.uptimeMillis();
+        long triggerpointToCurrentTimeMs = currentTimeMs - mLoadDecisionMs;
+
+        String suffix = preloadWasViable() ? ".Load" : ".NoLoad";
+        RecordHistogram.recordMediumTimesHistogram(histogram + suffix, triggerpointToCurrentTimeMs);
+    }
+
+    // Records the duration from the load decision to the current time into |histogram| (suffixed
+    // by the state of the tab preload and match decisions). To be used when the tab match decision
+    // may have already occurred at the present time.
+    private void recordDurationFromLoadDecisionIntoPostTabMatchHistogram(String histogram) {
         if (mLoadDecisionMs == 0) return;
 
         long currentTimeMs = SystemClock.uptimeMillis();
         long triggerpointToCurrentTimeMs = currentTimeMs - mLoadDecisionMs;
 
         String suffix = ".NoLoad";
-        if (mTriggerPreload) {
+        if (preloadWasViable()) {
             if (mTab != null) {
                 suffix = ".LoadPreMatch";
-            } else if (mTabMatches) {
+            } else if (tabMatchWasViable()) {
                 suffix = ".LoadAndMatch";
             } else {
                 suffix = ".LoadAndMismatch";
@@ -137,22 +184,58 @@
         RecordHistogram.recordMediumTimesHistogram(histogram + suffix, triggerpointToCurrentTimeMs);
     }
 
+    // Returns whether the state specified for the tab preload and the actual load match.
+    private boolean doesPreloadStateMatch(@TabLaunchType int preconnectLaunchType,
+            @TabLaunchType int loadLaunchType, LoadUrlParams preconnectParams,
+            LoadUrlParams loadParams) {
+        boolean tabMatch = preconnectLaunchType == loadLaunchType
+                && doLoadUrlParamsMatchForWarmupManagerNavigation(preconnectParams, loadParams)
+                && !sFailNextTabMatchForTesting;
+        sFailNextTabMatchForTesting = false;
+
+        return tabMatch;
+    }
+
     /**
      * Returns the Tab if loadUrlParams and type match, otherwise the Tab is discarded.
      *
-     * @param loadUrlParams The actual parameters of the url load.
-     * @param type The actual launch type type.
-     * @return The results of maybeNavigate() if they match loadUrlParams and type or null
-     *         otherwise.
+     * @param loadUrlParams The actual parameters of the url load.  @param type The actual launch
+     * type type.  @return The results of maybeNavigate() if they match loadUrlParams and type or
+     * null otherwise.
      */
     public Tab takeTabIfMatchingOrDestroy(LoadUrlParams loadUrlParams, @TabLaunchType int type) {
-        if (mTab == null) return null;
+        if (!mRecordedLoadDecisionToMatchDecisionHistogram) {
+            // NOTE: This histogram is segmented only by state of the load decision as it covers
+            // the duration from the load decision *up to* the tab match decision.
+            recordDurationFromLoadDecisionIntoPreTabMatchHistogram(
+                    "Android.StartupTabPreloader.LoadDecisionToMatchDecision");
+            mRecordedLoadDecisionToMatchDecisionHistogram = true;
+        }
 
-        mTabMatches = type == mTab.getLaunchType()
-                && doLoadUrlParamsMatchForWarmupManagerNavigation(mLoadUrlParams, loadUrlParams)
-                && !sFailNextTabMatchForTesting;
+        if (mTab == null) {
+            if (mUrlForPreloadPreventedOnlyByFeature != null) {
+                // Construct a LoadUrlParams object for the preload that would have occurred.
+                LoadUrlParams loadUrlParamsForPreloadPreventedOnlyByFeature =
+                        new LoadUrlParams(mUrlForPreloadPreventedOnlyByFeature);
+                if (mReferrerForPreloadPreventedOnlyByFeature != null) {
+                    loadUrlParamsForPreloadPreventedOnlyByFeature.setReferrer(new Referrer(
+                            mReferrerForPreloadPreventedOnlyByFeature, ReferrerPolicy.DEFAULT));
+                }
 
-        sFailNextTabMatchForTesting = false;
+                // Calculate whether a tab match *would have* occurred if the preload wasn't
+                // prevented by the feature. This is used later for metrics tracking.
+                mPreloadPreventedOnlyByFeatureWouldHaveMatched =
+                        doesPreloadStateMatch(TabLaunchType.FROM_EXTERNAL_APP, type,
+                                loadUrlParamsForPreloadPreventedOnlyByFeature, loadUrlParams);
+                mUrlForPreloadPreventedOnlyByFeature = null;
+                mReferrerForPreloadPreventedOnlyByFeature = null;
+            }
+
+            return null;
+        }
+
+        mTabMatches =
+                doesPreloadStateMatch(mTab.getLaunchType(), type, mLoadUrlParams, loadUrlParams);
 
         RecordHistogram.recordBooleanHistogram(
                 "Startup.Android.StartupTabPreloader.TabTaken", mTabMatches);
@@ -202,6 +285,9 @@
             ProfileManager.removeObserver(this);
             mTriggerPreload = shouldLoadTab();
             mLoadDecisionMs = SystemClock.uptimeMillis();
+            RecordHistogram.recordMediumTimesHistogram(
+                    "Android.StartupTabPreloader.ActivityStartToLoadDecision",
+                    mLoadDecisionMs - mStartupMetricsTracker.getActivityStartTimeMs());
             if (mTriggerPreload) loadTab();
             RecordHistogram.recordBooleanHistogram(
                     "Startup.Android.StartupTabPreloader.TabLoaded", mTriggerPreload);
@@ -216,13 +302,11 @@
      */
     @VisibleForTesting
     boolean shouldLoadTab() {
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.ELIDE_TAB_PRELOAD_AT_STARTUP)) {
-            return false;
-        }
-
         // If mTab isn't null we've been called before and there is nothing to do.
         if (mTab != null) return false;
 
+        mPreloadPreventedOnlyByFeature = false;
+
         Intent intent = mIntentSupplier.get();
         if (IntentUtils.safeGetBooleanExtra(intent, EXTRA_DISABLE_STARTUP_TAB_PRELOADER, false)) {
             return false;
@@ -248,6 +332,22 @@
         // We want to get the TabDelegateFactory but only ChromeTabCreator has one.
         if (!(tabCreator instanceof ChromeTabCreator)) return false;
 
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.ELIDE_TAB_PRELOAD_AT_STARTUP)) {
+            mPreloadPreventedOnlyByFeature = true;
+            GURL url = UrlFormatter.fixupUrl(getUrlFromIntent(intent));
+
+            // NOTE: We avoid calling IntentHandler.createLoadUrlParamsForIntent() here as that
+            // call is destructive to the metadata associated with the intent. Instead, we save the
+            // parameters of the load that are used in the check for matching later. This is
+            // fragile, but this state is used only for evaluating the effectiveness of startup tab
+            // preloading.
+            mUrlForPreloadPreventedOnlyByFeature = url.getSpec();
+            mReferrerForPreloadPreventedOnlyByFeature =
+                    IntentHandler.getReferrerUrlIncludingExtraHeaders(intent);
+
+            return false;
+        }
+
         return true;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java
index 27a5cc95..ad2afad 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java
@@ -39,6 +39,16 @@
          * Called when recording first visible content. This will be fired at most once.
          */
         void onFirstVisibleContent();
+
+        /**
+         * Called when recording first navigation commit. This will be fired at most once.
+         */
+        void onFirstNavigationCommit();
+
+        /**
+         * Called when recording first contentful paint. This will be fired at most once.
+         */
+        void onFirstContentfulPaint();
     }
 
     private static ObserverList<Observer> sObservers;
@@ -115,6 +125,12 @@
         tabModelSelectorSupplier.addObserver((selector) -> registerObservers(selector));
     }
 
+    // Returns the time since the activity was started (relative to which metrics such as time to
+    // first visible content are calculated).
+    public long getActivityStartTimeMs() {
+        return mActivityStartTimeMs;
+    }
+
     private void registerObservers(TabModelSelector tabModelSelector) {
         if (!mShouldTrackStartupMetrics) return;
         mTabModelSelectorTabObserver =
@@ -226,6 +242,10 @@
             if (mHistogramSuffix.equals(UMA_HISTOGRAM_TABBED_SUFFIX)) {
                 recordFirstVisibleContent(mFirstCommitTimeMs);
             }
+
+            for (Observer observer : sObservers) {
+                observer.onFirstNavigationCommit();
+            }
         }
         mShouldTrackStartupMetrics = false;
     }
@@ -248,6 +268,10 @@
             if (mHistogramSuffix.equals(UMA_HISTOGRAM_TABBED_SUFFIX)) {
                 recordVisibleContent(durationMs);
             }
+
+            for (Observer observer : sObservers) {
+                observer.onFirstContentfulPaint();
+            }
         }
         // This is the last event we track, so destroy this tracker and remove observers.
         destroy();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfo.java
index fc2aa26..d5f9b53 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfo.java
@@ -14,7 +14,6 @@
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabUtils;
-import org.chromium.components.content_settings.ContentSettingsType;
 import org.chromium.components.page_info.PageInfoController;
 import org.chromium.components.page_info.PageInfoController.OpenedFromSource;
 import org.chromium.content_public.browser.WebContents;
@@ -47,18 +46,16 @@
     /**
      * Show page info dialog.
      * @param tab Tab object containing the page whose information to be displayed.
-     * @param permission The {@link ContentSettingsType} to be highlighted on this page.
-     * @param fromStoreIcon Whether user enters page info via the store icon in omnibox, used to
-     *         determine whether to highlight the "Store info" row.
+     * @param pageInfoHighlight Providing the highlight row info related to this dialog.
      */
-    public void show(Tab tab, @ContentSettingsType int permission, boolean fromStoreIcon) {
+    public void show(Tab tab, ChromePageInfoHighlight pageInfoHighlight) {
         WebContents webContents = tab.getWebContents();
         Activity activity = TabUtils.getActivity(tab);
         PageInfoController.show(activity, webContents, mPublisher, mSource,
                 new ChromePageInfoControllerDelegate(activity, webContents,
                         mModalDialogManagerSupplier,
                         new OfflinePageUtils.TabOfflinePageLoadUrlDelegate(tab),
-                        mStoreInfoActionHandlerSupplier, fromStoreIcon),
-                permission);
+                        mStoreInfoActionHandlerSupplier, pageInfoHighlight),
+                pageInfoHighlight);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java
index d5a21793..dc9741c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java
@@ -75,7 +75,7 @@
     private final Context mContext;
     private final Profile mProfile;
     private final Supplier<StoreInfoActionHandler> mStoreInfoActionHandlerSupplier;
-    private final boolean mPageInfoOpenedFromStoreIcon;
+    private final ChromePageInfoHighlight mPageInfoHighlight;
     private String mOfflinePageCreationDate;
     private OfflinePageLoadUrlDelegate mOfflinePageLoadUrlDelegate;
 
@@ -83,7 +83,7 @@
             Supplier<ModalDialogManager> modalDialogManagerSupplier,
             OfflinePageLoadUrlDelegate offlinePageLoadUrlDelegate,
             @Nullable Supplier<StoreInfoActionHandler> storeInfoActionHandlerSupplier,
-            boolean pageInfoOpenedFromStoreIcon) {
+            ChromePageInfoHighlight pageInfoHighlight) {
         super(new ChromeAutocompleteSchemeClassifier(Profile.fromWebContents(webContents)),
                 VrModuleProvider.getDelegate(),
                 /** isSiteSettingsAvailable= */
@@ -95,7 +95,7 @@
         mModalDialogManagerSupplier = modalDialogManagerSupplier;
         mProfile = Profile.fromWebContents(mWebContents);
         mStoreInfoActionHandlerSupplier = storeInfoActionHandlerSupplier;
-        mPageInfoOpenedFromStoreIcon = pageInfoOpenedFromStoreIcon;
+        mPageInfoHighlight = pageInfoHighlight;
 
         initOfflinePageParams();
         mOfflinePageLoadUrlDelegate = offlinePageLoadUrlDelegate;
@@ -255,7 +255,8 @@
             storeInfoRow.setId(PageInfoStoreInfoController.STORE_INFO_ROW_ID);
             rowWrapper.addView(storeInfoRow);
             controllers.add(new PageInfoStoreInfoController(mainController, storeInfoRow,
-                    mStoreInfoActionHandlerSupplier, mPageInfoOpenedFromStoreIcon));
+                    mStoreInfoActionHandlerSupplier,
+                    mPageInfoHighlight.shouldHighlightStoreInfo()));
         }
         return controllers;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerLauncher.java
index 93b976c..40ca3aa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerLauncher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerLauncher.java
@@ -12,9 +12,7 @@
 import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.sync.SyncService;
-import org.chromium.components.signin.identitymanager.ConsentLevel;
 import org.chromium.components.signin.identitymanager.IdentityManager;
-import org.chromium.components.sync.ModelType;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.WindowAndroid;
 
@@ -33,11 +31,18 @@
      */
     public static void showPasswordSettings(
             Activity activity, @ManagePasswordsReferrer int referrer) {
-        if (isSyncingPasswordsWithoutCustomPassphrase()
+        IdentityManager identityManager = IdentityServicesProvider.get().getIdentityManager(
+                Profile.getLastUsedRegularProfile());
+        SyncService syncService = SyncService.get();
+        if (PasswordManagerHelper.isSyncingPasswordsWithoutCustomPassphrase(
+                    identityManager, syncService)
                 && ChromeFeatureList.isEnabled(ChromeFeatureList.PASSWORD_SCRIPTS_FETCHING)) {
             PasswordScriptsFetcherBridge.prewarmCache();
         }
-        PasswordManagerHelper.showPasswordSettings(activity, referrer, new SettingsLauncherImpl());
+        CredentialManagerLauncher credentialManagerLauncher = null;
+        PasswordManagerHelper.showPasswordSettings(activity, referrer, new SettingsLauncherImpl(),
+                CredentialManagerLauncherFactory.getInstance().createLauncher(), identityManager,
+                syncService);
     }
 
     @CalledByNative
@@ -48,20 +53,4 @@
         WeakReference<Activity> currentActivity = window.getActivity();
         showPasswordSettings(currentActivity.get(), referrer);
     }
-
-    public static boolean isSyncingPasswordsWithoutCustomPassphrase() {
-        IdentityManager identityManager = IdentityServicesProvider.get().getIdentityManager(
-                Profile.getLastUsedRegularProfile());
-        if (!identityManager.hasPrimaryAccount(ConsentLevel.SYNC)) return false;
-
-        SyncService syncService = SyncService.get();
-        if (syncService == null
-                || !syncService.getActiveDataTypes().contains(ModelType.PASSWORDS)) {
-            return false;
-        }
-
-        if (syncService.isUsingExplicitPassphrase()) return false;
-
-        return true;
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
index 826b8a9..566cb67 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
@@ -35,11 +35,11 @@
 import org.chromium.chrome.browser.password_check.PasswordCheckReferrer;
 import org.chromium.chrome.browser.password_manager.ManagePasswordsReferrer;
 import org.chromium.chrome.browser.password_manager.PasswordManagerHelper;
-import org.chromium.chrome.browser.password_manager.PasswordManagerLauncher;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.settings.ChromeManagedPreferenceDelegate;
 import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
+import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.sync.SyncService;
 import org.chromium.chrome.browser.sync.settings.SyncSettingsUtils;
 import org.chromium.components.browser_ui.settings.ChromeBasePreference;
@@ -49,6 +49,7 @@
 import org.chromium.components.browser_ui.settings.TextMessagePreference;
 import org.chromium.components.prefs.PrefService;
 import org.chromium.components.signin.base.CoreAccountInfo;
+import org.chromium.components.signin.identitymanager.IdentityManager;
 import org.chromium.components.user_prefs.UserPrefs;
 import org.chromium.ui.text.SpanApplier;
 
@@ -575,7 +576,11 @@
     }
 
     private void displayManageAccountLink() {
-        if (!PasswordManagerLauncher.isSyncingPasswordsWithoutCustomPassphrase()) {
+        IdentityManager identityManager = IdentityServicesProvider.get().getIdentityManager(
+                Profile.getLastUsedRegularProfile());
+        SyncService syncService = SyncService.get();
+        if (!PasswordManagerHelper.isSyncingPasswordsWithoutCustomPassphrase(
+                    identityManager, syncService)) {
             return;
         }
         if (mSearchQuery != null && !mNoPasswords) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAddress.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAddress.java
index 6b12932..7a58952 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAddress.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAddress.java
@@ -67,23 +67,38 @@
 
     @Nullable private static Pattern sRegionCodePattern;
 
-    private Context mContext;
+    private final Context mContext;
     private AutofillProfile mProfile;
     @Nullable private String mShippingLabelWithCountry;
     @Nullable private String mShippingLabelWithoutCountry;
     @Nullable private String mBillingLabel;
+    private final @CompletenessCheckType int mCheckType;
 
     /**
      * Builds the autofill address.
      *
+     * @param context The context where this address was created.
      * @param profile The autofill profile containing the address information.
      */
     public AutofillAddress(Context context, AutofillProfile profile) {
+        this(context, profile, CompletenessCheckType.NORMAL);
+    }
+
+    /**
+     * Builds the autofill address.
+     *
+     * @param context The context where this address was created.
+     * @param profile The autofill profile containing the address information.
+     * @param checkType The type of completeness to check.
+     */
+    public AutofillAddress(
+            Context context, AutofillProfile profile, @CompletenessCheckType int checkType) {
         super(profile.getGUID(), profile.getFullName(), profile.getLabel(),
                 profile.getPhoneNumber(), null);
         mContext = context;
         mProfile = profile;
         mIsEditable = true;
+        mCheckType = checkType;
         checkAndUpdateAddressCompleteness();
     }
 
@@ -180,8 +195,8 @@
      * status.
      */
     private void checkAndUpdateAddressCompleteness() {
-        Pair<Integer, Integer> messageResIds = getEditMessageAndTitleResIds(
-                checkAddressCompletionStatus(mProfile, CompletenessCheckType.NORMAL));
+        Pair<Integer, Integer> messageResIds =
+                getEditMessageAndTitleResIds(checkAddressCompletionStatus(mProfile, mCheckType));
 
         mEditMessage = messageResIds.first.intValue() == 0
                 ? null
@@ -239,8 +254,9 @@
      * will use the default locale to fill in a blank country code before sending the address to the
      * renderer.
      *
-     * @param  profile The autofill profile containing the address information.
-     * @return int     The completion status.
+     * @param profile   The autofill profile containing the address information.
+     * @param checkType The type of completeness to check.
+     * @return int      The completion status.
      */
     @CompletionStatus
     public static int checkAddressCompletionStatus(
@@ -332,11 +348,11 @@
 
     /** @return The missing fields of the shipping profile. */
     public int getMissingFieldsOfShippingProfile() {
-        return checkAddressCompletionStatus(mProfile, CompletenessCheckType.NORMAL);
+        return checkAddressCompletionStatus(mProfile, mCheckType);
     }
 
     private int calculateCompletenessScore() {
-        int missingFields = checkAddressCompletionStatus(mProfile, CompletenessCheckType.NORMAL);
+        int missingFields = checkAddressCompletionStatus(mProfile, mCheckType);
 
         // Count how many are set. The completeness of the address is weighted so as
         // to dominate the other fields.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/toolbar/PaymentHandlerToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/toolbar/PaymentHandlerToolbarCoordinator.java
index a7e6617..c0d471f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/toolbar/PaymentHandlerToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/toolbar/PaymentHandlerToolbarCoordinator.java
@@ -14,6 +14,7 @@
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
 import org.chromium.chrome.browser.page_info.ChromePageInfoControllerDelegate;
+import org.chromium.chrome.browser.page_info.ChromePageInfoHighlight;
 import org.chromium.chrome.browser.payments.handler.toolbar.PaymentHandlerToolbarMediator.PaymentHandlerToolbarMediatorDelegate;
 import org.chromium.components.omnibox.SecurityStatusIcon;
 import org.chromium.components.page_info.PageInfoController;
@@ -154,7 +155,7 @@
                         /*offlinePageLoadUrlDelegate=*/
                         new OfflinePageUtils.WebContentsOfflinePageLoadUrlDelegate(mWebContents),
                         /*storeInfoActionHandlerSupplier=*/null,
-                        /*pageInfoOpenedFromStoreIcon=*/false),
-                PageInfoController.NO_HIGHLIGHTED_PERMISSION);
+                        ChromePageInfoHighlight.noHighlight()),
+                ChromePageInfoHighlight.noHighlight());
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index 6d559929..aa9c0fe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -191,7 +191,7 @@
                 /*shareDelegateSupplier=*/null, /*incognitoStateProvider=*/null,
                 getLifecycleDispatcher(), overrideUrlLoadingDelegate, /*backKeyBehavior=*/this,
                 SearchEngineLogoUtils.getInstance(), /*launchAssistanceSettingsAction=*/() -> {},
-                /*pageInfoAction=*/(tab, permission, fromStoreIcon) -> {},
+                /*pageInfoAction=*/(tab, pageInfoHighlight) -> {},
                 IntentHandler::bringTabToFront,
                 /*saveOfflineButtonState=*/(tab) -> false, /*omniboxUma*/(url, transition) -> {},
                 TabWindowManagerSingleton::getInstance, /*bookmarkState=*/(url) -> false,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
index 787f65d..01917af7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
@@ -13,6 +13,7 @@
 import android.view.View.OnAttachStateChangeListener;
 import android.view.accessibility.AccessibilityEvent;
 
+import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
@@ -69,6 +70,8 @@
 import org.chromium.ui.util.ColorUtils;
 import org.chromium.url.GURL;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteBuffer;
 
 /**
@@ -211,8 +214,21 @@
     private int mThemeColor;
     private boolean mUsedCriticalPersistedTabData;
 
-    /** Whether or not the user manually changed the user agent. */
-    private boolean mUserForcedUserAgent;
+    /** Tab level Request Desktop Site setting. */
+    private @TabUserAgent int mTabUserAgent;
+
+    // TODO(https://crbug.com/1251794): Determine if this should be defined somewhere like TabState
+    // for when we persist to disk.
+    /**
+     * Defines the tab level Request Desktop Site settings.
+     */
+    @IntDef({TabUserAgent.DEFAULT, TabUserAgent.MOBILE, TabUserAgent.DESKTOP})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TabUserAgent {
+        int DEFAULT = 0; /* No tab level setting */
+        int MOBILE = 1; /* Tab level setting is mobile layout */
+        int DESKTOP = 2; /* Tab level setting is desktop layout */
+    }
 
     /**
      * Creates an instance of a {@link TabImpl}.
@@ -1639,7 +1655,7 @@
 
         // We only calculate the user agent when users did not manually choose one.
         // TODO(crbug.com/1251794): Desktop site setting in app menu does not persist after restart.
-        if (!mUserForcedUserAgent
+        if (mTabUserAgent == TabUserAgent.DEFAULT
                 && ContentFeatureList.isEnabled(ContentFeatureList.REQUEST_DESKTOP_SITE_GLOBAL)) {
             // We only do the following logic to choose the desktop/mobile user agent if:
             // 1. User never manually made a choice in the app menu for requesting desktop site.
@@ -1674,8 +1690,8 @@
         return UserAgentOverrideOption.INHERIT;
     }
 
-    void setUserForcedUserAgent() {
-        mUserForcedUserAgent = true;
+    void setTabUserAgent(@TabUserAgent int tabUserAgent) {
+        mTabUserAgent = tabUserAgent;
     }
 
     private void switchUserAgentIfNeeded() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
index 4a5d18f7..7bd90cef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
@@ -17,9 +17,11 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tab.TabImpl.TabUserAgent;
 import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge;
 import org.chromium.components.content_settings.ContentSettingValues;
 import org.chromium.components.content_settings.ContentSettingsType;
+import org.chromium.content_public.browser.ContentFeatureList;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.WindowAndroid;
@@ -91,7 +93,16 @@
         final boolean reloadOnChange = !tab.isNativePage();
         tab.getWebContents().getNavigationController().setUseDesktopUserAgent(
                 switchToDesktop, reloadOnChange);
-        if (forcedByUser) ((TabImpl) tab).setUserForcedUserAgent();
+        if (forcedByUser) {
+            @TabUserAgent
+            int tabUserAgent = switchToDesktop ? TabUserAgent.DESKTOP : TabUserAgent.MOBILE;
+            if (ContentFeatureList.isEnabled(ContentFeatureList.REQUEST_DESKTOP_SITE_GLOBAL)
+                    && isDesktopSiteGlobalEnabled(Profile.fromWebContents(tab.getWebContents()))
+                            == switchToDesktop) {
+                tabUserAgent = TabUserAgent.DEFAULT;
+            }
+            ((TabImpl) tab).setTabUserAgent(tabUserAgent);
+        }
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index ba67648..9c13fae 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -4036,7 +4036,7 @@
     @Test
     @SmallTest
     @Feature({"ContextualSearch"})
-    @DisableIf.Build(sdk_is_greater_than = Build.VERSION_CODES.O, message = "crbug.com/1182040")
+    @FlakyTest(message = "https://crbug.com/1182040")
     @DisableIf.Build(supported_abis_includes = "arm64-v8a", message = "crbug.com/1240342")
     public void testRelatedSearchesItemSelected() throws Exception {
         FeatureList.setTestFeatures(ENABLE_RELATED_SEARCHES_IN_BAR);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderTest.java
index 6028b14..3ab0742 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderTest.java
@@ -52,6 +52,12 @@
             "Startup.Android.Cold.TimeToFirstVisibleContent";
     private static final String VISIBLE_CONTENT_HISTOGRAM =
             "Startup.Android.Cold.TimeToVisibleContent";
+    private static final String ACTIVITY_START_TO_PRELOAD_TRIGGER =
+            "Android.StartupTabPreloader.ActivityStartToLoadDecision";
+    private static final String PRELOAD_TRIGGER_TO_MATCH_DECISION_PRELOAD =
+            "Android.StartupTabPreloader.LoadDecisionToMatchDecision.Load";
+    private static final String PRELOAD_TRIGGER_TO_MATCH_DECISION_NO_PRELOAD =
+            "Android.StartupTabPreloader.LoadDecisionToMatchDecision.NoLoad";
     private static final String PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_START_PRELOAD =
             "Android.StartupTabPreloader.LoadDecisionToFirstNavigationStart.Load";
     private static final String PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_START_NO_PRELOAD =
@@ -64,6 +70,28 @@
             "Android.StartupTabPreloader.LoadDecisionToFirstVisibleContent.LoadAndMismatch";
     private static final String PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_NO_PRELOAD =
             "Android.StartupTabPreloader.LoadDecisionToFirstVisibleContent.NoLoad";
+    private static final String PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_COMMIT_PRELOAD_BEFORE_MATCH =
+            "Android.StartupTabPreloader.LoadDecisionToFirstNavigationCommit.LoadPreMatch";
+    private static final String PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_COMMIT_PRELOAD_AND_TAKE =
+            "Android.StartupTabPreloader.LoadDecisionToFirstNavigationCommit.LoadAndMatch";
+    private static final String PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_COMMIT_PRELOAD_AND_DROP =
+            "Android.StartupTabPreloader.LoadDecisionToFirstNavigationCommit.LoadAndMismatch";
+    private static final String PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_COMMIT_NO_PRELOAD =
+            "Android.StartupTabPreloader.LoadDecisionToFirstNavigationCommit.NoLoad";
+    private static final String PRELOAD_TRIGGER_TO_FIRST_CONTENTFUL_PAINT_PRELOAD_BEFORE_MATCH =
+            "Android.StartupTabPreloader.LoadDecisionToFirstContentfulPaint.LoadPreMatch";
+    private static final String PRELOAD_TRIGGER_TO_FIRST_CONTENTFUL_PAINT_PRELOAD_AND_TAKE =
+            "Android.StartupTabPreloader.LoadDecisionToFirstContentfulPaint.LoadAndMatch";
+    private static final String PRELOAD_TRIGGER_TO_FIRST_CONTENTFUL_PAINT_PRELOAD_AND_DROP =
+            "Android.StartupTabPreloader.LoadDecisionToFirstContentfulPaint.LoadAndMismatch";
+    private static final String PRELOAD_TRIGGER_TO_FIRST_CONTENTFUL_PAINT_NO_PRELOAD =
+            "Android.StartupTabPreloader.LoadDecisionToFirstContentfulPaint.NoLoad";
+
+    // Used for verifying expected histogram counts.
+    private static final int NO_PRELOAD = 0;
+    private static final int PRELOAD = 1;
+    private static final int NO_PRELOAD_MATCH = 0;
+    private static final int PRELOAD_MATCH = 1;
 
     @Rule
     public ChromeTabbedActivityTestRule mActivityRule = new ChromeTabbedActivityTestRule();
@@ -71,6 +99,72 @@
     @Rule
     public EmbeddedTestServerRule mServerRule = new EmbeddedTestServerRule();
 
+    // Verifies the state of various startup metrics being recorded appropriately for the varues of
+    // |preload| and |preloadMatch| (specified by the constants above).
+    private void assertStartupMetricsRecorded(int preload, int preloadMatch) {
+        int noPreload = 1 - preload;
+        int preloadMismatch = (preload == 1 && preloadMatch == 0) ? 1 : 0;
+
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        ACTIVITY_START_TO_PRELOAD_TRIGGER));
+
+        Assert.assertEquals(preload,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_START_PRELOAD));
+        Assert.assertEquals(noPreload,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_START_NO_PRELOAD));
+
+        Assert.assertEquals(preload,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_MATCH_DECISION_PRELOAD));
+        Assert.assertEquals(noPreload,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_MATCH_DECISION_NO_PRELOAD));
+
+        Assert.assertEquals(preloadMatch,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_PRELOAD_AND_TAKE));
+        Assert.assertEquals(preloadMismatch,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_PRELOAD_AND_DROP));
+        Assert.assertEquals(noPreload,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_NO_PRELOAD));
+
+        Assert.assertEquals(preloadMatch,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_COMMIT_PRELOAD_AND_TAKE));
+        Assert.assertEquals(preloadMismatch,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_COMMIT_PRELOAD_AND_DROP));
+        Assert.assertEquals(noPreload,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_COMMIT_NO_PRELOAD));
+
+        Assert.assertEquals(preloadMatch,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_CONTENTFUL_PAINT_PRELOAD_AND_TAKE));
+        Assert.assertEquals(preloadMismatch,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_CONTENTFUL_PAINT_PRELOAD_AND_DROP));
+        Assert.assertEquals(noPreload,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_CONTENTFUL_PAINT_NO_PRELOAD));
+
+        // This case never triggers in these tests.
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_PRELOAD_BEFORE_MATCH));
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_COMMIT_PRELOAD_BEFORE_MATCH));
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_FIRST_CONTENTFUL_PAINT_PRELOAD_BEFORE_MATCH));
+    }
+
     @Test
     @LargeTest
     @DisableFeatures(ChromeFeatureList.ELIDE_TAB_PRELOAD_AT_STARTUP)
@@ -119,24 +213,7 @@
                 1, RecordHistogram.getHistogramTotalCountForTesting(VISIBLE_CONTENT_HISTOGRAM));
 
         // Startup tab preload-specific startup metrics should also have been recorded.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_START_PRELOAD));
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_START_NO_PRELOAD));
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_PRELOAD_AND_TAKE));
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_PRELOAD_AND_DROP));
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_NO_PRELOAD));
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_PRELOAD_BEFORE_MATCH));
+        assertStartupMetricsRecorded(PRELOAD, PRELOAD_MATCH);
     }
 
     @Test
@@ -174,24 +251,7 @@
                 1, RecordHistogram.getHistogramTotalCountForTesting(VISIBLE_CONTENT_HISTOGRAM));
 
         // Startup tab preload-specific startup metrics should also have been recorded.
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_START_PRELOAD));
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_START_NO_PRELOAD));
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_PRELOAD_AND_TAKE));
-        Assert.assertEquals(1,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_PRELOAD_AND_DROP));
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_NO_PRELOAD));
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_PRELOAD_BEFORE_MATCH));
+        assertStartupMetricsRecorded(PRELOAD, NO_PRELOAD_MATCH);
     }
 
     @Test
@@ -227,24 +287,86 @@
                 1, RecordHistogram.getHistogramTotalCountForTesting(VISIBLE_CONTENT_HISTOGRAM));
 
         // Startup tab preload-specific startup metrics should also have been recorded.
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_START_PRELOAD));
+        assertStartupMetricsRecorded(NO_PRELOAD, NO_PRELOAD_MATCH);
+    }
+
+    @Test
+    @LargeTest
+    @FlakyTest(message = "https://crbug.com/1271158")
+    @EnableFeatures(ChromeFeatureList.ELIDE_TAB_PRELOAD_AT_STARTUP)
+    public void
+    testStartupTabPreloaderStartupLoadingMetricsRecordedWhenTabWouldBeTakenIfNotPreventedByFeature()
+            throws Exception {
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        mActivityRule.startMainActivityFromIntent(
+                intent, mServerRule.getServer().getURL(TEST_PAGE));
+
+        // The StartupTabPreloader should not have actually loaded a url.
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
+
+        // First contentful paint should be recorded.
+        CriteriaHelper.pollUiThread(()
+                                            -> RecordHistogram.getHistogramTotalCountForTesting(
+                                                       FIRST_CONTENTFUL_PAINT_HISTOGRAM)
+                        == 1);
+        // First contentful paint is the last startup metric to be recorded, so the other startup
+        // metrics should also have been recorded at this point.
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramTotalCountForTesting(FIRST_COMMIT_HISTOGRAM));
         Assert.assertEquals(1,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_NAVIGATION_START_NO_PRELOAD));
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_PRELOAD_AND_TAKE));
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_PRELOAD_AND_DROP));
+                RecordHistogram.getHistogramTotalCountForTesting(FIRST_VISIBLE_CONTENT_HISTOGRAM));
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramTotalCountForTesting(VISIBLE_CONTENT_HISTOGRAM));
+
+        // Startup tab preload-specific startup metrics should also have been recorded, with the
+        // state reflecting what it would have been if startup tab preloading were not prevented by
+        // the base::Feature.
+        assertStartupMetricsRecorded(PRELOAD, PRELOAD_MATCH);
+    }
+
+    @Test
+    @LargeTest
+    @FlakyTest(message = "https://crbug.com/1271158")
+    @EnableFeatures(ChromeFeatureList.ELIDE_TAB_PRELOAD_AT_STARTUP)
+    public void
+    testStartupTabPreloaderStartupLoadingMetricsRecordedWhenTabWouldBeDroppedIfNotPreventedByFeature()
+            throws Exception {
+        StartupTabPreloader.failNextTabMatchForTesting();
+
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        mActivityRule.startMainActivityFromIntent(
+                intent, mServerRule.getServer().getURL(TEST_PAGE));
+
+        // The StartupTabPreloader should not have actually loaded a url.
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
+
+        // First contentful paint should be recorded.
+        CriteriaHelper.pollUiThread(()
+                                            -> RecordHistogram.getHistogramTotalCountForTesting(
+                                                       FIRST_CONTENTFUL_PAINT_HISTOGRAM)
+                        == 1);
+
+        // First contentful paint is the last startup metric to be recorded, so the other startup
+        // metrics should also have been recorded at this point.
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramTotalCountForTesting(FIRST_COMMIT_HISTOGRAM));
         Assert.assertEquals(1,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_NO_PRELOAD));
-        Assert.assertEquals(0,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        PRELOAD_TRIGGER_TO_FIRST_VISIBLE_CONTENT_PRELOAD_BEFORE_MATCH));
+                RecordHistogram.getHistogramTotalCountForTesting(FIRST_VISIBLE_CONTENT_HISTOGRAM));
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramTotalCountForTesting(VISIBLE_CONTENT_HISTOGRAM));
+
+        // Startup tab preload-specific startup metrics should also have been recorded, with the
+        // state reflecting what it would have been if startup tab preloading were not prevented by
+        // the base::Feature.
+        assertStartupMetricsRecorded(PRELOAD, NO_PRELOAD_MATCH);
     }
 
     @Test
@@ -326,6 +448,15 @@
                 1, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
         Assert.assertEquals(
                 1, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        ACTIVITY_START_TO_PRELOAD_TRIGGER));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_MATCH_DECISION_PRELOAD));
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_MATCH_DECISION_NO_PRELOAD));
 
         Tab currentTab = mActivityRule.getActivity().getActivityTab();
 
@@ -342,5 +473,47 @@
                 1, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
         Assert.assertEquals(
                 1, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        ACTIVITY_START_TO_PRELOAD_TRIGGER));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_MATCH_DECISION_PRELOAD));
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        PRELOAD_TRIGGER_TO_MATCH_DECISION_NO_PRELOAD));
+    }
+
+    @Test
+    @LargeTest
+    @EnableFeatures(ChromeFeatureList.ELIDE_TAB_PRELOAD_AT_STARTUP)
+    public void testStartupTabPreloaderMultipleTabCreationWithFeatureEnabled() throws Exception {
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        mActivityRule.startMainActivityFromIntent(
+                intent, mServerRule.getServer().getURL(TEST_PAGE));
+
+        // The StartupTabPreloader should not have loaded a url.
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
+
+        Tab currentTab = mActivityRule.getActivity().getActivityTab();
+
+        // Creating a second tab should not cause a browser crash. Verifies safety of subtle
+        // logic handling metrics in the case where the feature is enabled.
+        intent = new Intent(Intent.ACTION_VIEW);
+        String url = mServerRule.getServer().getURL(TEST_PAGE2);
+        mActivityRule.getActivity().startActivity(mActivityRule.prepareUrlIntent(intent, url));
+
+        CriteriaHelper.pollUiThread(
+                () -> mActivityRule.getActivity().getActivityTab() != currentTab);
+        ChromeTabUtils.waitForTabPageLoaded(mActivityRule.getActivity().getActivityTab(), url);
+
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoAboutThisSiteTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoAboutThisSiteTest.java
index ab22469..db78070b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoAboutThisSiteTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoAboutThisSiteTest.java
@@ -126,7 +126,7 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             new ChromePageInfo(activity.getModalDialogManagerSupplier(), null,
                     PageInfoController.OpenedFromSource.TOOLBAR, null)
-                    .show(tab, PageInfoController.NO_HIGHLIGHTED_PERMISSION, false);
+                    .show(tab, ChromePageInfoHighlight.noHighlight());
         });
         onViewWaiting(allOf(withId(org.chromium.chrome.R.id.page_info_url_wrapper), isDisplayed()));
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewDarkModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewDarkModeTest.java
index f0a4534f..e2307cd9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewDarkModeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewDarkModeTest.java
@@ -81,8 +81,7 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             new ChromePageInfo(
                     activity.getModalDialogManagerSupplier(), null, OpenedFromSource.TOOLBAR, null)
-                    .show(tab, PageInfoController.NO_HIGHLIGHTED_PERMISSION,
-                            /*fromStoreIcon=*/false);
+                    .show(tab, ChromePageInfoHighlight.noHighlight());
         });
         onViewWaiting(allOf(withId(R.id.page_info_url_wrapper), isDisplayed()));
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
index 22d4a46..ad8c16d9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
@@ -208,7 +208,7 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             new ChromePageInfo(activity.getModalDialogManagerSupplier(), null,
                     PageInfoController.OpenedFromSource.TOOLBAR, null)
-                    .show(tab, highlightedPermission, /*fromStoreIcon=*/false);
+                    .show(tab, ChromePageInfoHighlight.forPermission(highlightedPermission));
         });
         onViewWaiting(allOf(withId(R.id.page_info_url_wrapper), isDisplayed()));
     }
@@ -631,7 +631,7 @@
                     new ChromePageInfoControllerDelegate(activity, tab.getWebContents(),
                             activity::getModalDialogManager,
                             new OfflinePageUtils.TabOfflinePageLoadUrlDelegate(tab), null,
-                            /*pageInfoOpenedFromStoreIcon=*/false) {
+                            ChromePageInfoHighlight.noHighlight()) {
                         @Override
                         public boolean isShowingPaintPreviewPage() {
                             return true;
@@ -639,7 +639,7 @@
                     };
             PageInfoController.show(sActivityTestRule.getActivity(), tab.getWebContents(), null,
                     PageInfoController.OpenedFromSource.MENU, pageInfoControllerDelegate,
-                    PageInfoController.NO_HIGHLIGHTED_PERMISSION);
+                    ChromePageInfoHighlight.noHighlight());
         });
         onViewWaiting(allOf(withText(R.string.page_info_connection_paint_preview), isDisplayed()));
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
index ce6fd4d..c1a7fe6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
@@ -166,27 +166,6 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> tab.addObserver(mPermissionUpdateWaiter));
     }
 
-    private void setAllowLocation(final boolean enabled) {
-        LocationSettingsTestUtil.setSystemLocationSettingEnabled(true);
-        LocationProviderOverrider.setLocationProviderImpl(new MockLocationProvider());
-        final SettingsActivity settingsActivity = SiteSettingsTestUtils.startSiteSettingsCategory(
-                SiteSettingsCategory.Type.DEVICE_LOCATION);
-
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            SingleCategorySettings websitePreferences =
-                    (SingleCategorySettings) settingsActivity.getMainFragment();
-            ChromeSwitchPreference location =
-                    (ChromeSwitchPreference) websitePreferences.findPreference(
-                            SingleCategorySettings.BINARY_TOGGLE_KEY);
-
-            websitePreferences.onPreferenceChange(location, enabled);
-            Assert.assertEquals("Location should be " + (enabled ? "allowed" : "blocked"), enabled,
-                    WebsitePreferenceBridge.areAllLocationSettingsEnabled(
-                            getBrowserContextHandle()));
-            settingsActivity.finish();
-        });
-    }
-
     private void triggerEmbargoForOrigin(String url) throws TimeoutException {
         // Ignore notification request 4 times to enter embargo. 5th one ensures that notifications
         // are blocked by actually causing a deny-by-embargo.
@@ -207,7 +186,7 @@
     @Test
     @SmallTest
     @Feature({"Preferences"})
-    @DisabledTest(message = "Flaky, see https://crbug.com/1270293")
+    @DisableIf.Build(supported_abis_includes = "arm", message = "https://crbug.com/1270293")
     public void testSetAllowLocationEnabled() throws Exception {
         LocationSettingsTestUtil.setSystemLocationSettingEnabled(true);
         LocationProviderOverrider.setLocationProviderImpl(new MockLocationProvider());
@@ -216,8 +195,9 @@
                 .run();
         TestThreadUtils.runOnUiThreadBlocking(
                 ()
-                        -> WebsitePreferenceBridge.areAllLocationSettingsEnabled(
-                                getBrowserContextHandle()));
+                        -> Assert.assertTrue("Location should be allowed.",
+                                WebsitePreferenceBridge.areAllLocationSettingsEnabled(
+                                        getBrowserContextHandle())));
 
         initializeUpdateWaiter(true /* expectGranted */);
 
@@ -232,7 +212,7 @@
     @Test
     @SmallTest
     @Feature({"Preferences"})
-    @DisabledTest(message = "Flaky, see https://crbug.com/1270293")
+    @DisableIf.Build(supported_abis_includes = "arm", message = "https://crbug.com/1270293")
     public void testSetAllowLocationNotEnabled() throws Exception {
         LocationSettingsTestUtil.setSystemLocationSettingEnabled(true);
         LocationProviderOverrider.setLocationProviderImpl(new MockLocationProvider());
@@ -241,8 +221,9 @@
                 .run();
         TestThreadUtils.runOnUiThreadBlocking(
                 ()
-                        -> WebsitePreferenceBridge.areAllLocationSettingsEnabled(
-                                getBrowserContextHandle()));
+                        -> Assert.assertFalse("Location should be blocked.",
+                                WebsitePreferenceBridge.areAllLocationSettingsEnabled(
+                                        getBrowserContextHandle())));
 
         // Launch a page that uses geolocation. No permission prompt is expected.
         initializeUpdateWaiter(false /* expectGranted */);
@@ -1448,7 +1429,7 @@
             }
 
             Assert.assertEquals(actualKeys.toString() + " should match " + expectedKeys.toString(),
-                    actualKeys, expectedKeys);
+                    expectedKeys, actualKeys);
         }
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/subresource_filter/SubresourceFilterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/subresource_filter/SubresourceFilterTest.java
index 20beae3..b19be092 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/subresource_filter/SubresourceFilterTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/subresource_filter/SubresourceFilterTest.java
@@ -9,6 +9,7 @@
 import android.view.View;
 import android.widget.TextView;
 
+import androidx.test.espresso.Espresso;
 import androidx.test.filters.LargeTest;
 
 import org.junit.After;
@@ -21,6 +22,7 @@
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.MockSafeBrowsingApiHandler;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -52,6 +54,7 @@
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.test.util.UiRestriction;
 
 import java.util.List;
 import java.util.concurrent.ExecutionException;
@@ -197,48 +200,20 @@
 
     @Test
     @LargeTest
+    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
     @EnableFeatures(ChromeFeatureList.MESSAGES_FOR_ANDROID_ADS_BLOCKED)
-    public void resourceFilteredClickLearnMore_MessagesUI() throws Exception {
-        String url = mTestServer.getURL(PAGE_WITH_JPG);
-        Assert.assertFalse(
-                loadPageWithBlockableContentAndTestIfBlocked(url, METADATA_FOR_ENFORCEMENT));
+    public void resourceFilteredClickLearnMore_MessagesUI_ReshowDialogOnPhoneOnBackPress()
+            throws Exception {
+        testResourceFilteredClickLearnMore_MessagesUIFlow();
+    }
 
-        CallbackHelper tabCreatedCallback = new CallbackHelper();
-        TabModel tabModel = mActivityTestRule.getActivity().getTabModelSelector().getCurrentModel();
-        TestThreadUtils.runOnUiThreadBlocking(() -> tabModel.addObserver(new TabModelObserver() {
-            @Override
-            public void didAddTab(
-                    Tab tab, @TabLaunchType int type, @TabCreationState int creationState) {
-                if (tab.getUrl().getSpec().equals(LEARN_MORE_PAGE)) {
-                    tabCreatedCallback.notifyCalled();
-                }
-            }
-        }));
-
-        // Check that the Ads Blocked message is showing and get the active message.
-        PropertyModel message = verifyAndGetAdsBlockedMessage();
-
-        int currentTabCreatedCallbackCount = tabCreatedCallback.getCallCount();
-
-        // Trigger the Ads Blocked dialog and simulate the "Learn more" link click.
-        createAdsBlockedDialog(message);
-        View dialogView = ((TabModalPresenter) mActivityTestRule.getActivity()
-                                   .getModalDialogManager()
-                                   .getCurrentPresenterForTest())
-                                  .getDialogContainerForTest();
-        TextView messageView = dialogView.findViewById(R.id.message);
-        Spanned spannedMessage = (Spanned) messageView.getText();
-        ClickableSpan[] spans =
-                spannedMessage.getSpans(0, spannedMessage.length(), ClickableSpan.class);
-        Assert.assertEquals(
-                "Ads Blocked dialog message text must have only 1 ClickableSpan.", 1, spans.length);
-        TestThreadUtils.runOnUiThreadBlocking(() -> spans[0].onClick(messageView));
-
-        // Wait for the tab to be added with the correct URL. Note, do not wait for this URL to be
-        // loaded since it is not controlled by the test instrumentation. Just waiting for the
-        // navigation to start should be OK though.
-        tabCreatedCallback.waitForCallback(
-                "Never received tab created event", currentTabCreatedCallbackCount);
+    @Test
+    @LargeTest
+    @Restriction(UiRestriction.RESTRICTION_TYPE_TABLET)
+    @EnableFeatures(ChromeFeatureList.MESSAGES_FOR_ANDROID_ADS_BLOCKED)
+    public void resourceFilteredClickLearnMore_MessagesUI_ReshowDialogOnTabletOnBackPress()
+            throws Exception {
+        testResourceFilteredClickLearnMore_MessagesUIFlow();
     }
 
     @Test
@@ -298,6 +273,59 @@
         CriteriaHelper.pollUiThread(() -> infoBars.isEmpty());
     }
 
+    private void testResourceFilteredClickLearnMore_MessagesUIFlow()
+            throws TimeoutException, ExecutionException, InterruptedException {
+        String url = mTestServer.getURL(PAGE_WITH_JPG);
+        Assert.assertFalse(
+                loadPageWithBlockableContentAndTestIfBlocked(url, METADATA_FOR_ENFORCEMENT));
+
+        CallbackHelper tabCreatedCallback = new CallbackHelper();
+        TabModel tabModel = mActivityTestRule.getActivity().getTabModelSelector().getCurrentModel();
+        TestThreadUtils.runOnUiThreadBlocking(() -> tabModel.addObserver(new TabModelObserver() {
+            @Override
+            public void didAddTab(
+                    Tab tab, @TabLaunchType int type, @TabCreationState int creationState) {
+                if (tab.getUrl().getSpec().equals(LEARN_MORE_PAGE)) {
+                    tabCreatedCallback.notifyCalled();
+                }
+            }
+        }));
+
+        // Check that the Ads Blocked message is showing and get the active message.
+        PropertyModel message = verifyAndGetAdsBlockedMessage();
+
+        int currentTabCreatedCallbackCount = tabCreatedCallback.getCallCount();
+
+        // Trigger the Ads Blocked dialog and simulate the "Learn more" link click.
+        createAdsBlockedDialog(message);
+        View dialogView = ((TabModalPresenter) mActivityTestRule.getActivity()
+                                   .getModalDialogManager()
+                                   .getCurrentPresenterForTest())
+                                  .getDialogContainerForTest();
+        TextView messageView = dialogView.findViewById(R.id.message);
+        Spanned spannedMessage = (Spanned) messageView.getText();
+        ClickableSpan[] spans =
+                spannedMessage.getSpans(0, spannedMessage.length(), ClickableSpan.class);
+        Assert.assertEquals(
+                "Ads Blocked dialog message text must have only 1 ClickableSpan.", 1, spans.length);
+        TestThreadUtils.runOnUiThreadBlocking(() -> spans[0].onClick(messageView));
+
+        // Wait for the tab to be added with the correct URL. Note, do not wait for this URL to be
+        // loaded since it is not controlled by the test instrumentation. Just waiting for the
+        // navigation to start should be OK though.
+        tabCreatedCallback.waitForCallback(
+                "Never received tab created event", currentTabCreatedCallbackCount);
+
+        // Press the back button to go to the original tab where the dialog was shown.
+        Espresso.pressBack();
+
+        CriteriaHelper.pollUiThread(() -> {
+            // Verify that the dialog is re-shown on the original tab.
+            return mActivityTestRule.getActivity().getModalDialogManager().getCurrentDialogForTest()
+                    != null;
+        }, "The dialog should be re-shown on navigation to the original tab.");
+    }
+
     private boolean loadPageWithBlockableContentAndTestIfBlocked(String url, String metadata)
             throws TimeoutException {
         MockSafeBrowsingApiHandler.addMockResponse(url, metadata);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/RequestDesktopSiteTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/RequestDesktopSiteTest.java
index 8cdd0c0..fd4cc8b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/RequestDesktopSiteTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/RequestDesktopSiteTest.java
@@ -51,10 +51,11 @@
 @Batch(Batch.PER_CLASS)
 @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-@Features.EnableFeatures(ContentFeatureList.REQUEST_DESKTOP_SITE_EXCEPTIONS)
+@Features.EnableFeatures(ContentFeatureList.REQUEST_DESKTOP_SITE_GLOBAL)
 public class RequestDesktopSiteTest {
     private static final String URL_1 = "https://www.chromium.org/";
     private static final String URL_2 = "https://www.example.com/";
+    private CallbackHelper mMenuObserver;
 
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
@@ -72,6 +73,17 @@
                 .shouldTriggerHelpUI(ArgumentMatchers.anyString());
         mActivityTestRule.startMainActivityOnBlankPage();
         assertContentSettingsHistogramRecorded();
+        mMenuObserver = new CallbackHelper();
+        mActivityTestRule.getAppMenuCoordinator().getAppMenuHandler().addObserver(
+                new AppMenuObserver() {
+                    @Override
+                    public void onMenuVisibilityChanged(boolean isVisible) {
+                        mMenuObserver.notifyCalled();
+                    }
+
+                    @Override
+                    public void onMenuHighlightChanged(boolean highlighting) {}
+                });
     }
 
     @After
@@ -87,32 +99,16 @@
 
     @Test
     @SmallTest
+    @Features.EnableFeatures(ContentFeatureList.REQUEST_DESKTOP_SITE_EXCEPTIONS)
     public void testGlobalSiteSettingsAndException() throws TimeoutException {
         Tab tab = mActivityTestRule.loadUrlInNewTab(URL_1);
         assertUsingDesktopUserAgent(tab, false, "Default user agent should be mobile.");
 
-        CallbackHelper menuObserver = new CallbackHelper();
-        mActivityTestRule.getAppMenuCoordinator().getAppMenuHandler().addObserver(
-                new AppMenuObserver() {
-                    @Override
-                    public void onMenuVisibilityChanged(boolean isVisible) {
-                        menuObserver.notifyCalled();
-                    }
-
-                    @Override
-                    public void onMenuHighlightChanged(boolean highlighting) {}
-                });
-
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             AppMenuTestSupport.showAppMenu(mActivityTestRule.getAppMenuCoordinator(), null, false);
         });
-
-        menuObserver.waitForCallback(0);
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            AppMenuTestSupport.callOnItemClick(
-                    mActivityTestRule.getAppMenuCoordinator(), R.id.request_desktop_site_id);
-        });
-        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(tab.isLoading(), Matchers.is(false)));
+        mMenuObserver.waitForCallback(0);
+        toggleFromAppMenu(tab);
         assertUsingDesktopUserAgent(
                 tab, true, "User agent should be desktop according to site settings.");
         assertChangeUserActionRecorded(true);
@@ -122,17 +118,70 @@
                 tab, false, "Site settings exceptions should not affect other URL.");
 
         // Change site settings and reload.
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            WebsitePreferenceBridge.setContentSettingEnabled(
-                    Profile.fromWebContents(tab.getWebContents()),
-                    ContentSettingsType.REQUEST_DESKTOP_SITE, true);
-            tab.reload();
-        });
-        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(tab.isLoading(), Matchers.is(false)));
+        updateGlobalSetting(tab, true);
         assertUsingDesktopUserAgent(
                 tab, true, "User agent should be desktop according to global site settings.");
     }
 
+    @Test
+    @SmallTest
+    public void testUnsetPerTabSettings() throws TimeoutException {
+        Tab tab = mActivityTestRule.loadUrlInNewTab(URL_1);
+        // Explicitly set the global setting to mobile to avoid flakiness.
+        updateGlobalSetting(tab, false);
+        assertUsingDesktopUserAgent(tab, false,
+                "Tab layout should be <Mobile>, while global settings is <Mobile> and tab level settings is <Default>.");
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            AppMenuTestSupport.showAppMenu(mActivityTestRule.getAppMenuCoordinator(), null, false);
+        });
+        mMenuObserver.waitForCallback(0);
+        toggleFromAppMenu(tab);
+        assertUsingDesktopUserAgent(tab, true,
+                "Tab layout should be <Desktop>, while global settings is <Mobile> and tab level settings is <Desktop>.");
+
+        updateGlobalSetting(tab, true);
+        assertUsingDesktopUserAgent(tab, true,
+                "Tab layout should be <Desktop>, while global settings is <Desktop> and tab level settings is <Desktop>.");
+
+        updateGlobalSetting(tab, false);
+        assertUsingDesktopUserAgent(tab, true,
+                "Tab layout should be <Desktop>, while global settings is <Mobile> and tab level settings is <Desktop>.");
+
+        toggleFromAppMenu(tab);
+        assertUsingDesktopUserAgent(tab, false,
+                "Tab layout should be <Mobile>, while global settings is <Mobile> and tab level settings is <Default>.");
+
+        updateGlobalSetting(tab, true);
+        assertUsingDesktopUserAgent(tab, true,
+                "Tab layout should be <Desktop>, while global settings is <Desktop> and tab level settings is <Default>.");
+    }
+
+    @Test
+    @SmallTest
+    public void testGlobalAndPerTabSettings() throws TimeoutException {
+        Tab tab = mActivityTestRule.loadUrlInNewTab(URL_1);
+        updateGlobalSetting(tab, true);
+        assertUsingDesktopUserAgent(tab, true,
+                "Tab layout should be <Desktop>, while global settings is <Desktop> and tab level settings is <Default>.");
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            AppMenuTestSupport.showAppMenu(mActivityTestRule.getAppMenuCoordinator(), null, false);
+        });
+        mMenuObserver.waitForCallback(0);
+        toggleFromAppMenu(tab);
+        assertUsingDesktopUserAgent(tab, false,
+                "Tab layout should be <Mobile>, while global settings is <Desktop> and tab level settings is <Mobile>.");
+
+        updateGlobalSetting(tab, false);
+        assertUsingDesktopUserAgent(tab, false,
+                "Tab layout should be <Mobile>, while global settings is <Mobile> and tab level settings is <Mobile>.");
+
+        toggleFromAppMenu(tab);
+        assertUsingDesktopUserAgent(tab, true,
+                "Tab layout should be <Desktop>, while global settings is <Mobile> and tab level settings is <Desktop>.");
+    }
+
     private void assertUsingDesktopUserAgent(
             Tab tab, boolean useDesktopUserAgent, String errorMessage) {
         Assert.assertNotNull("Tab does not have a WebContent.", tab.getWebContents());
@@ -158,4 +207,22 @@
                 RecordHistogram.getHistogramValueCountForTesting(
                         "Android.RequestDesktopSite.UserSwitchToDesktop", sample));
     }
+
+    private void updateGlobalSetting(Tab tab, boolean setting) {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            WebsitePreferenceBridge.setContentSettingEnabled(
+                    Profile.fromWebContents(tab.getWebContents()),
+                    ContentSettingsType.REQUEST_DESKTOP_SITE, setting);
+            tab.reload();
+        });
+        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(tab.isLoading(), Matchers.is(false)));
+    }
+
+    private void toggleFromAppMenu(Tab tab) {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            AppMenuTestSupport.callOnItemClick(
+                    mActivityTestRule.getAppMenuCoordinator(), R.id.request_desktop_site_id);
+        });
+        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(tab.isLoading(), Matchers.is(false)));
+    }
 }
diff --git a/chrome/app/chrome_crash_reporter_client.h b/chrome/app/chrome_crash_reporter_client.h
index 89247022..0f935bed 100644
--- a/chrome/app/chrome_crash_reporter_client.h
+++ b/chrome/app/chrome_crash_reporter_client.h
@@ -11,7 +11,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/no_destructor.h"
 #include "build/build_config.h"
 #include "components/crash/core/app/crash_reporter_client.h"
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index c4f1980f..7e805bb 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -4272,6 +4272,12 @@
   <message name="IDS_CROSTINI_TERMINAL_STATUS_READY" desc="Text shown in the crostini terminal when it just finished the initialization and it is ready to use.">
     Ready
   </message>
+  <message name="IDS_CROSTINI_TERMINAL_CONNECT_TO_LINUX" desc="Text shown in the right-click menu to allow users to open terminal and use Linux.">
+    Connect to Linux
+  </message>
+  <message name="IDS_CROSTINI_TERMINAL_CONNECT_TO_SSH" desc="Text shown in the right-click menu to allow users to open terminal and connect to a remote machine using SSH. SSH is 'Secure SHell' and should probably not be translated since users of all languages likley know it as 'SSH'.">
+    Connect to SSH
+  </message>
   <message name="IDS_CROSTINI_INSTALLER_TITLE" desc="Title of the Crostini installer, a dialog for installing Linux.">
     Set up Linux development environment
   </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_DONE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_DONE.png.sha1
deleted file mode 100644
index afd7bd82..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_DONE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-f4d76e1c540780ba80e4b6568367695c93d73f68
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_FAILED.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_FAILED.png.sha1
deleted file mode 100644
index afd7bd82..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_FAILED.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-f4d76e1c540780ba80e4b6568367695c93d73f68
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_IN_PROGRESS.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_IN_PROGRESS.png.sha1
deleted file mode 100644
index afd7bd82..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_NOTIFICATION_IN_PROGRESS.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-f4d76e1c540780ba80e4b6568367695c93d73f68
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_TITLE.png.sha1
deleted file mode 100644
index afd7bd82..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_EXPORT_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-f4d76e1c540780ba80e4b6568367695c93d73f68
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_DONE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_DONE.png.sha1
deleted file mode 100644
index bceb036..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_DONE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-67a7f5b5f40ee10862fdb1ce486f99f99812a5cf
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_FAILED.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_FAILED.png.sha1
deleted file mode 100644
index bceb036..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_FAILED.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-67a7f5b5f40ee10862fdb1ce486f99f99812a5cf
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_IN_PROGRESS.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_IN_PROGRESS.png.sha1
deleted file mode 100644
index bceb036..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_NOTIFICATION_IN_PROGRESS.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-67a7f5b5f40ee10862fdb1ce486f99f99812a5cf
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_TITLE.png.sha1
deleted file mode 100644
index bceb036..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_IMPORT_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-67a7f5b5f40ee10862fdb1ce486f99f99812a5cf
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_TERMINAL_CONNECT_TO_LINUX.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_TERMINAL_CONNECT_TO_LINUX.png.sha1
new file mode 100644
index 0000000..da8809d
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_TERMINAL_CONNECT_TO_LINUX.png.sha1
@@ -0,0 +1 @@
+f05d5acb6e3853af3bbb961afe1eeea9dbcd832c
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_TERMINAL_CONNECT_TO_SSH.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_TERMINAL_CONNECT_TO_SSH.png.sha1
new file mode 100644
index 0000000..da8809d
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_TERMINAL_CONNECT_TO_SSH.png.sha1
@@ -0,0 +1 @@
+f05d5acb6e3853af3bbb961afe1eeea9dbcd832c
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_PLUGIN_VM_INSTALLER_ERROR_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_PLUGIN_VM_INSTALLER_ERROR_MESSAGE.png.sha1
deleted file mode 100644
index 6d1ff04..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_PLUGIN_VM_INSTALLER_ERROR_MESSAGE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-2f7b77c25f84e15d99a3355c9c03e5004a876a8c
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_PLUGIN_VM_INSTALLER_FINISHED_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_PLUGIN_VM_INSTALLER_FINISHED_MESSAGE.png.sha1
deleted file mode 100644
index 041fae7d..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_PLUGIN_VM_INSTALLER_FINISHED_MESSAGE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-90635bbbb7c6cda1709096f278d4479dbfc9794c
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 06f899cc..47a027e 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1769,7 +1769,7 @@
                desc="When starting a download, let the user know we're starting the download.">
         Starting...
       </message>
-      <if expr="chromeos">
+      <if expr="chromeos or lacros">
         <message name="IDS_DOWNLOAD_STATUS_IN_PROGRESS_TITLE"
                  desc="The title of a download notification: the current download status is in progress.">
                  Downloading <ph name="FILE_NAME">$1<ex>somedocument.pdf</ex></ph>
@@ -1993,21 +1993,21 @@
         This file is encrypted. Ask its owner to decrypt.
       </message>
 
-      <if expr="chromeos">
+      <if expr="chromeos or lacros">
         <message name="IDS_PROMPT_BLOCKED_MIXED_DOWNLOAD_TITLE"
                  desc="In the download notification, a title of the message shown on a download blocked for being insecure.">
           Insecure download blocked
         </message>
       </if>
 
-      <if expr="chromeos">
+      <if expr="chromeos or lacros">
         <message name="IDS_PROMPT_BLOCKED_MALICIOUS_DOWNLOAD_TITLE"
                  desc="In the download notification, a title of message shown for blocked download">
           Dangerous download blocked
         </message>
       </if>
 
-      <if expr="chromeos">
+      <if expr="chromeos or lacros">
         <message name="IDS_PROMPT_SEND_TO_SAFEBROWSING_DOWNLOAD_TITLE"
                  desc="In the download notification, a title of message shown indicating that the file may be malicious and Safe Browsing recommends sending the file to Google">
           Scan file before opening?
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index ce609aa0..235d950f8 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -82,10 +82,10 @@
     Device name
   </message>
   <message name="IDS_SETTINGS_UPGRADE_ROLLBACK_IN_PROGRESS" desc="Status label: Rolling back ChromiumOS or Chrome OS.">
-    Your administrator is rolling back this device (<ph name="PROGRESS_PERCENT">$1<ex>90%</ex></ph>)
+    <ph name="MANAGER">$1<ex>google.com</ex></ph> is putting this device on a previous version (<ph name="PROGRESS_PERCENT">$2<ex>90%</ex></ph>)
   </message>
   <message name="IDS_SETTINGS_UPGRADE_ROLLBACK_SUCCESS" desc="Status label: Successfully rolled back Chrome OS. All data on the device will be deleted during the next reboot.">
-    Your administrator rolled back this device. Please save important files, then restart. All data on the device will be deleted.
+    <ph name="MANAGER">$1<ex>google.com</ex></ph> has put this device on a previous version. Please save important files, then restart. All data on the device will be deleted.
   </message>
   <message name="IDS_SETTINGS_UPGRADE_SUCCESSFUL_CHANNEL_SWITCH" desc="Status label: Channel was successfully switched on ChromiumOS/ChromeOS">
     Channel changed. Restart your device to apply changes.
@@ -3134,13 +3134,13 @@
     Connecting to your phone
   </message>
   <message name="IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_TITLE" desc="The title of the screen lock dialog containing the Phone Hub notification opt-in flow shown when the user has confirmed to enable the app stream that will stream phone to their Chromebook.">
-    Set a PIN or password to continue
+    Set a PIN or password
   </message>
   <message name="IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_SUBTITLE" desc="The subtitle of the screen lock dialog containing the Phone Hub notification opt-in flow shown when the user has confirmed to enable the app stream that will stream phone to their Chromebook.">
-    Protect your phone's data when this Chromebook wakes from sleep.
+    This PIN or password protects your data on this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>, including any content you stream from your phone.
   </message>
-  <message name="IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_INSTRUCTION" desc="The instruction message of the screen lock dialog containing the smart lock will log in when the phone is nearby.">
-    Smart lock will automatically log you in when your phone is nearby.
+  <message name="IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_INSTRUCTION" desc="The instruction message of the screen lock dialog.">
+    Choose either one each time you sign in
   </message>
   <message name="IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_INSTRUCTIONS" desc="The second paragraph of text shown in the dialog containing the Phone Hub notification opt-in flow. Alerts the user that to enable notifications, they need to have their phone unlocked, nearby, and with Bluetooth/Wi-Fi on to complete setup.">
     Make sure your phone is nearby, unlocked, and has Bluetooth and Wi-Fi turned on.
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_INSTRUCTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_INSTRUCTION.png.sha1
index ed799c5..647bd57 100644
--- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_INSTRUCTION.png.sha1
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_INSTRUCTION.png.sha1
@@ -1 +1 @@
-12fe8090282c2cf7e9553039dab4a59b91eb99eb
\ No newline at end of file
+377efb6d99c62d8ac1b0568870b168263ea0ebac
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_SUBTITLE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_SUBTITLE.png.sha1
index ed799c5..647bd57 100644
--- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_SUBTITLE.png.sha1
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_SUBTITLE.png.sha1
@@ -1 +1 @@
-12fe8090282c2cf7e9553039dab4a59b91eb99eb
\ No newline at end of file
+377efb6d99c62d8ac1b0568870b168263ea0ebac
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_TITLE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_TITLE.png.sha1
index ed799c5..647bd57 100644
--- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_TITLE.png.sha1
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_TITLE.png.sha1
@@ -1 +1 @@
-12fe8090282c2cf7e9553039dab4a59b91eb99eb
\ No newline at end of file
+377efb6d99c62d8ac1b0568870b168263ea0ebac
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPGRADE_ROLLBACK_IN_PROGRESS.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPGRADE_ROLLBACK_IN_PROGRESS.png.sha1
new file mode 100644
index 0000000..757e769
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPGRADE_ROLLBACK_IN_PROGRESS.png.sha1
@@ -0,0 +1 @@
+71a90c91bf5f0a295916597f6a1ebb20785b445c
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPGRADE_ROLLBACK_SUCCESS.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPGRADE_ROLLBACK_SUCCESS.png.sha1
new file mode 100644
index 0000000..7e2ba7f
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPGRADE_ROLLBACK_SUCCESS.png.sha1
@@ -0,0 +1 @@
+ec568d98e2b38fcbf6d9387262e51e19a4914ef9
\ No newline at end of file
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn
index 3c95662..94c6628 100644
--- a/chrome/app/vector_icons/BUILD.gn
+++ b/chrome/app/vector_icons/BUILD.gn
@@ -191,6 +191,10 @@
     ]
   }
 
+  if (is_chromeos) {
+    sources += [ "notification_download.icon" ]
+  }
+
   if (is_chromeos_ash) {
     sources += [
       "autocorrect_undo.icon",
@@ -198,7 +202,6 @@
       "notification_battery.icon",
       "notification_captive_portal.icon",
       "notification_cellular_alert.icon",
-      "notification_download.icon",
       "notification_end_of_support.icon",
       "notification_family_link.icon",
       "notification_google.icon",
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 57118bf..d3c7fc6 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2481,6 +2481,7 @@
       "//chromeos/components/local_search_service/public/cpp:cpp",
       "//chromeos/components/local_search_service/public/mojom",
       "//chromeos/components/multidevice/debug_webui",
+      "//chromeos/components/quick_answers/public/cpp:cpp",
       "//chromeos/components/quick_answers/public/cpp:prefs",
       "//chromeos/dbus/attestation",
       "//chromeos/dbus/attestation:attestation_proto",
@@ -2571,6 +2572,8 @@
       "android/android_theme_resources.h",
       "android/autocomplete/tab_matcher_android.cc",
       "android/autocomplete/tab_matcher_android.h",
+      "android/autofill_assistant/annotate_dom_model_service_factory.cc",
+      "android/autofill_assistant/annotate_dom_model_service_factory.h",
       "android/autofill_assistant/assistant_bottom_bar_delegate.cc",
       "android/autofill_assistant/assistant_bottom_bar_delegate.h",
       "android/autofill_assistant/assistant_collect_user_data_delegate.cc",
@@ -3417,6 +3420,7 @@
       "//components/assist_ranker/proto",
       "//components/autofill_assistant/browser",
       "//components/autofill_assistant/browser:proto",
+      "//components/autofill_assistant/content/browser",
       "//components/background_sync",
       "//components/bookmarks/common/android",
       "//components/browser_ui/contacts_picker/android",
@@ -4617,10 +4621,6 @@
       "component_updater/smart_dim_component_installer.h",
       "device_identity/chromeos/device_oauth2_token_store_chromeos.cc",
       "device_identity/chromeos/device_oauth2_token_store_chromeos.h",
-      "download/notification/download_item_notification.cc",
-      "download/notification/download_item_notification.h",
-      "download/notification/download_notification_manager.cc",
-      "download/notification/download_notification_manager.h",
       "enterprise/reporting/android_app_info_generator.cc",
       "enterprise/reporting/android_app_info_generator.h",
       "feedback/system_logs/log_sources/lacros_log_files_log_source.cc",
@@ -5225,6 +5225,10 @@
       "apps/intent_helper/chromeos_intent_picker_helpers.h",
       "apps/intent_helper/metrics/intent_handling_metrics.cc",
       "apps/intent_helper/metrics/intent_handling_metrics.h",
+      "download/notification/download_item_notification.cc",
+      "download/notification/download_item_notification.h",
+      "download/notification/download_notification_manager.cc",
+      "download/notification/download_notification_manager.h",
       "media/platform_verification_chromeos.cc",
       "media/platform_verification_chromeos.h",
       "platform_keys/extension_key_permissions_service.cc",
@@ -7649,10 +7653,10 @@
     ]
     configs += [ "//build/config/linux/dbus" ]
     deps += [
+      "//ash/components/attestation:test_support",
       "//ash/public/cpp",
       "//chrome/test:test_support_ui",
       "//chromeos:test_support",
-      "//chromeos/attestation:test_support",
       "//chromeos/dbus",
       "//chromeos/dbus/cros_disks",
       "//chromeos/disks",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 89b2bd29..97c87dfb 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3984,9 +3984,6 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(chrome::android::kToolbarMicIphAndroid,
                                     kIphMicToolbarVariations,
                                     "ToolbarMicIphAndroid")},
-    {"theme-refactor-android", flag_descriptions::kThemeRefactorAndroidName,
-     flag_descriptions::kThemeRefactorAndroidDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kThemeRefactorAndroid)},
 #endif  // OS_ANDROID
     {"disallow-doc-written-script-loads",
      flag_descriptions::kDisallowDocWrittenScriptsUiName,
@@ -6685,7 +6682,7 @@
     {"enable-bluetooth-spp-in-serial-api",
      flag_descriptions::kEnableBluetoothSerialPortProfileInSerialApiName,
      flag_descriptions::kEnableBluetoothSerialPortProfileInSerialApiDescription,
-     kOsMac,
+     kOsAll,
      SINGLE_VALUE_TYPE(switches::kEnableBluetoothSerialPortProfileInSerialApi)},
 
     {"enable-lite-video", flag_descriptions::kLiteVideoName,
diff --git a/chrome/browser/android/autofill_assistant/annotate_dom_model_service_factory.cc b/chrome/browser/android/autofill_assistant/annotate_dom_model_service_factory.cc
new file mode 100644
index 0000000..fd4cfbd0
--- /dev/null
+++ b/chrome/browser/android/autofill_assistant/annotate_dom_model_service_factory.cc
@@ -0,0 +1,61 @@
+// 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/android/autofill_assistant/annotate_dom_model_service_factory.h"
+
+#include "base/feature_list.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
+#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/autofill_assistant/browser/features.h"
+#include "components/autofill_assistant/content/browser/annotate_dom_model_service.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/translate/content/browser/translate_model_service.h"
+
+AnnotateDomModelServiceFactory::AnnotateDomModelServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "AnnotateDomModelService",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+AnnotateDomModelServiceFactory::~AnnotateDomModelServiceFactory() = default;
+
+// static
+AnnotateDomModelServiceFactory* AnnotateDomModelServiceFactory::GetInstance() {
+  static base::NoDestructor<AnnotateDomModelServiceFactory> factory;
+  return factory.get();
+}
+
+// static
+autofill_assistant::AnnotateDomModelService*
+AnnotateDomModelServiceFactory::GetForBrowserContext(
+    content::BrowserContext* browser_context) {
+  return static_cast<autofill_assistant::AnnotateDomModelService*>(
+      GetInstance()->GetServiceForBrowserContext(browser_context, true));
+}
+
+KeyedService* AnnotateDomModelServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  if (!base::FeatureList::IsEnabled(
+          autofill_assistant::features::kAutofillAssistantAnnotateDom)) {
+    return nullptr;
+  }
+
+  // The optimization guide service must be available for the annotate DOM
+  // model service to be created.
+  auto* opt_guide = OptimizationGuideKeyedServiceFactory::GetForProfile(
+      Profile::FromBrowserContext(context));
+  if (!opt_guide) {
+    return nullptr;
+  }
+
+  scoped_refptr<base::SequencedTaskRunner> background_task_runner =
+      base::ThreadPool::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
+  return new autofill_assistant::AnnotateDomModelService(
+      opt_guide, background_task_runner);
+}
diff --git a/chrome/browser/android/autofill_assistant/annotate_dom_model_service_factory.h b/chrome/browser/android/autofill_assistant/annotate_dom_model_service_factory.h
new file mode 100644
index 0000000..4572885
--- /dev/null
+++ b/chrome/browser/android/autofill_assistant/annotate_dom_model_service_factory.h
@@ -0,0 +1,41 @@
+// 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_ANDROID_AUTOFILL_ASSISTANT_ANNOTATE_DOM_MODEL_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_ANDROID_AUTOFILL_ASSISTANT_ANNOTATE_DOM_MODEL_SERVICE_FACTORY_H_
+
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace autofill_assistant {
+class AnnotateDomModelService;
+}  // namespace autofill_assistant
+
+// Creates instances of |AnnotateDomMOdelService| per |BrowserContext|.
+class AnnotateDomModelServiceFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  AnnotateDomModelServiceFactory();
+  ~AnnotateDomModelServiceFactory() override;
+
+  // Gets the lazy instance of the factory.
+  static AnnotateDomModelServiceFactory* GetInstance();
+
+  // Gets the |AnnotateDomModelService| for the |browser_context|.
+  //
+  // Returns nullptr if the features that allows for annotating DOM is disabled.
+  // Only available when the optimization guide service is.
+  static autofill_assistant::AnnotateDomModelService* GetForBrowserContext(
+      content::BrowserContext* context);
+
+ private:
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+};
+
+#endif  //  CHROME_BROWSER_ANDROID_AUTOFILL_ASSISTANT_ANNOTATE_DOM_MODEL_SERVICE_FACTORY_H_
diff --git a/chrome/browser/android/autofill_assistant/client_android.cc b/chrome/browser/android/autofill_assistant/client_android.cc
index 04b652c..a6ff288b 100644
--- a/chrome/browser/android/autofill_assistant/client_android.cc
+++ b/chrome/browser/android/autofill_assistant/client_android.cc
@@ -19,10 +19,10 @@
 #include "base/time/default_tick_clock.h"
 #include "chrome/android/features/autofill_assistant/jni_headers/AutofillAssistantClient_jni.h"
 #include "chrome/android/features/autofill_assistant/jni_headers/AutofillAssistantDirectActionImpl_jni.h"
+#include "chrome/browser/android/autofill_assistant/annotate_dom_model_service_factory.h"
 #include "chrome/browser/android/autofill_assistant/ui_controller_android_utils.h"
 #include "chrome/browser/autofill/android/personal_data_manager_android.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
-#include "chrome/browser/flags/android/chrome_feature_list.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/profiles/profile.h"
@@ -640,7 +640,9 @@
   controller_ = std::make_unique<Controller>(
       web_contents_, /* client= */ this, base::DefaultTickClock::GetInstance(),
       RuntimeManagerImpl::GetForWebContents(web_contents_)->GetWeakPtr(),
-      std::move(service), std::move(tts_controller), ukm::UkmRecorder::Get());
+      std::move(service), std::move(tts_controller), ukm::UkmRecorder::Get(),
+      AnnotateDomModelServiceFactory::GetInstance()->GetForBrowserContext(
+          web_contents_->GetBrowserContext()));
   controller_->SetStatusMessage(status_message);
   if (progress_bar_config) {
     controller_->SetStepProgressBarConfiguration(*progress_bar_config);
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index 999a6c94..e0cd4f24 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -34,7 +34,6 @@
 #include "chrome/browser/android/feedback/screenshot_mode.h"
 #include "chrome/browser/autofill/android/personal_data_manager_android.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
-#include "chrome/browser/flags/android/chrome_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.h b/chrome/browser/android/bookmarks/bookmark_bridge.h
index 1d50d74..00adc5ae 100644
--- a/chrome/browser/android/bookmarks/bookmark_bridge.h
+++ b/chrome/browser/android/bookmarks/bookmark_bridge.h
@@ -11,7 +11,6 @@
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_weak_ref.h"
-#include "base/compiler_specific.h"
 #include "base/guid.h"
 #include "base/scoped_observation.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/android/devtools_manager_delegate_android.h b/chrome/browser/android/devtools_manager_delegate_android.h
index 869cc054..5b6be32e 100644
--- a/chrome/browser/android/devtools_manager_delegate_android.h
+++ b/chrome/browser/android/devtools_manager_delegate_android.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/devtools_agent_host_observer.h"
 #include "content/public/browser/devtools_manager_delegate.h"
 
diff --git a/chrome/browser/android/recently_closed_tabs_bridge.h b/chrome/browser/android/recently_closed_tabs_bridge.h
index 9b2f626..58b6ada 100644
--- a/chrome/browser/android/recently_closed_tabs_bridge.h
+++ b/chrome/browser/android/recently_closed_tabs_bridge.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_ANDROID_RECENTLY_CLOSED_TABS_BRIDGE_H_
 
 #include "base/android/scoped_java_ref.h"
-#include "base/compiler_specific.h"
 #include "components/sessions/core/tab_restore_service_observer.h"
 
 class Profile;
diff --git a/chrome/browser/android/webapps/launchpad/java/src/org/chromium/chrome/browser/webapps/launchpad/LaunchpadPageTest.java b/chrome/browser/android/webapps/launchpad/java/src/org/chromium/chrome/browser/webapps/launchpad/LaunchpadPageTest.java
index 552daba..f3e7a86 100644
--- a/chrome/browser/android/webapps/launchpad/java/src/org/chromium/chrome/browser/webapps/launchpad/LaunchpadPageTest.java
+++ b/chrome/browser/android/webapps/launchpad/java/src/org/chromium/chrome/browser/webapps/launchpad/LaunchpadPageTest.java
@@ -34,6 +34,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.settings.SettingsActivity;
@@ -136,6 +137,7 @@
 
     @Test
     @MediumTest
+    @FlakyTest(message = "https://crbug.com/1271233")
     public void testManagementMenuAppPermissions() {
         LaunchpadTestUtils.setPermissionDefaults(LaunchpadTestUtils.APP_URL_2);
         openLaunchpadPage();
diff --git a/chrome/browser/apps/app_service/instance_registry_updater.cc b/chrome/browser/apps/app_service/instance_registry_updater.cc
index c4a37a0..cac403d 100644
--- a/chrome/browser/apps/app_service/instance_registry_updater.cc
+++ b/chrome/browser/apps/app_service/instance_registry_updater.cc
@@ -107,7 +107,10 @@
     InstanceState state) {
   auto instance = std::make_unique<apps::Instance>(app_id, instance_id, window);
   instance->UpdateState(state, base::Time::Now());
-  instance_registry_.OnInstance(std::move(instance));
+
+  std::vector<std::unique_ptr<apps::Instance>> deltas;
+  deltas.push_back(std::move(instance));
+  instance_registry_.OnInstances(std::move(deltas));
 }
 
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc b/chrome/browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc
index 3cf0d5f2..36bd99be 100644
--- a/chrome/browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc
+++ b/chrome/browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc
@@ -371,9 +371,12 @@
         app_id, apps::Instance::InstanceKey::ForWindowBasedApp(window));
     instance->UpdateState(state, base::Time::Now());
 
+    std::vector<std::unique_ptr<apps::Instance>> deltas;
+    deltas.push_back(std::move(instance));
+
     apps::AppServiceProxyFactory::GetForProfile(testing_profile_.get())
         ->InstanceRegistry()
-        .OnInstance(std::move(instance));
+        .OnInstances(std::move(deltas));
   }
 
   void ModifyWebAppInstance(const std::string& app_id,
@@ -383,9 +386,12 @@
         app_id, apps::Instance::InstanceKey::ForWebBasedApp(window));
     instance->UpdateState(state, base::Time::Now());
 
+    std::vector<std::unique_ptr<apps::Instance>> deltas;
+    deltas.push_back(std::move(instance));
+
     apps::AppServiceProxyFactory::GetForProfile(testing_profile_.get())
         ->InstanceRegistry()
-        .OnInstance(std::move(instance));
+        .OnInstances(std::move(deltas));
   }
 
   std::unique_ptr<Browser> CreateBrowserWithAuraWindow1() {
diff --git a/chrome/browser/apps/app_service/publishers/crostini_apps.cc b/chrome/browser/apps/app_service/publishers/crostini_apps.cc
index af39385..93c981b 100644
--- a/chrome/browser/apps/app_service/publishers/crostini_apps.cc
+++ b/chrome/browser/apps/app_service/publishers/crostini_apps.cc
@@ -7,9 +7,6 @@
 #include <utility>
 
 #include "ash/public/cpp/app_menu_constants.h"
-#include "base/strings/strcat.h"
-#include "base/strings/string_split.h"
-#include "base/strings/stringprintf.h"
 #include "chrome/browser/apps/app_service/app_icon/app_icon_factory.h"
 #include "chrome/browser/apps/app_service/app_icon/dip_px_util.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
@@ -20,6 +17,7 @@
 #include "chrome/browser/ash/crostini/crostini_package_service.h"
 #include "chrome/browser/ash/crostini/crostini_pref_names.h"
 #include "chrome/browser/ash/crostini/crostini_shelf_utils.h"
+#include "chrome/browser/ash/crostini/crostini_terminal.h"
 #include "chrome/browser/ash/crostini/crostini_util.h"
 #include "chrome/browser/ash/guest_os/guest_os_registry_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -59,24 +57,6 @@
   return d.device_scale_factor() != 1.0;
 }
 
-constexpr char delimiter[] = "{.}";
-
-std::string ShortcutIdFromContainerId(const crostini::ContainerId& id) {
-  return base::StrCat({id.vm_name, delimiter, id.container_name});
-}
-
-base::flat_map<std::string, std::string> ExtrasFromShortcutId(
-    const std::string& shortcut_id) {
-  std::vector<std::string> pieces = base::SplitStringUsingSubstr(
-      shortcut_id, delimiter, base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
-  auto extras = base::flat_map<std::string, std::string>();
-  if (pieces.size() == 2) {
-    extras["vm_name"] = pieces[0];
-    extras["container_name"] = pieces[1];
-  }
-  return extras;
-}
-
 }  // namespace
 
 namespace apps {
@@ -231,23 +211,6 @@
       ->QueueUninstallApplication(app_id);
 }
 
-void CrostiniApps::AddTerminalShortcuts(apps::mojom::MenuItemsPtr* menu_items) {
-  const base::Value* container_list =
-      profile_->GetPrefs()->GetList(crostini::prefs::kCrostiniContainers);
-  if (container_list && container_list->GetList().size() > 1) {
-    int command_id = ash::LAUNCH_APP_SHORTCUT_FIRST;
-    for (const auto& dict : container_list->GetList()) {
-      crostini::ContainerId id(dict);
-      if (!id.vm_name.empty() && !id.container_name.empty()) {
-        std::string shortcut_id = ShortcutIdFromContainerId(id);
-        std::string label = base::StrCat({id.vm_name, ":", id.container_name});
-        AddShortcutCommandItem(command_id++, shortcut_id, label,
-                               gfx::ImageSkia(), menu_items);
-      }
-    }
-  }
-}
-
 void CrostiniApps::GetMenuModel(const std::string& app_id,
                                 apps::mojom::MenuType menu_type,
                                 int64_t display_id,
@@ -263,14 +226,9 @@
   }
 
   if (app_id == crostini::kCrostiniTerminalSystemAppId) {
-    AddCommandItem(ash::SETTINGS, IDS_INTERNAL_APP_SETTINGS, &menu_items);
-    if (crostini::IsCrostiniRunning(profile_)) {
-      AddCommandItem(ash::SHUTDOWN_GUEST_OS,
-                     IDS_CROSTINI_SHUT_DOWN_LINUX_MENU_ITEM, &menu_items);
-    }
-    if (crostini::CrostiniFeatures::Get()->IsMultiContainerAllowed(profile_)) {
-      AddTerminalShortcuts(&menu_items);
-    }
+    crostini::AddTerminalMenuItems(profile_, &menu_items);
+    crostini::AddTerminalMenuShortcuts(profile_, &menu_items,
+                                       ash::LAUNCH_APP_SHORTCUT_FIRST);
   }
 
   if (ShouldAddOpenItem(app_id, menu_type, profile_)) {
@@ -308,10 +266,8 @@
                                              const std::string& shortcut_id,
                                              int64_t display_id) {
   if (app_id == crostini::kCrostiniTerminalSystemAppId) {
-    apps::mojom::IntentPtr intent = apps::mojom::Intent::New();
-    intent->extras = ExtrasFromShortcutId(shortcut_id);
-    crostini::LaunchCrostiniAppWithIntent(profile_, app_id, display_id,
-                                          std::move(intent));
+    crostini::ExecuteTerminalMenuShortcutCommand(profile_, shortcut_id,
+                                                 display_id);
   }
 }
 
diff --git a/chrome/browser/apps/app_service/publishers/crostini_apps.h b/chrome/browser/apps/app_service/publishers/crostini_apps.h
index a1ea72b..6f8e26b 100644
--- a/chrome/browser/apps/app_service/publishers/crostini_apps.h
+++ b/chrome/browser/apps/app_service/publishers/crostini_apps.h
@@ -110,8 +110,6 @@
   // once it can support hiding apps.
   void OnCrostiniEnabledChanged();
 
-  void AddTerminalShortcuts(apps::mojom::MenuItemsPtr* menu_items);
-
   std::unique_ptr<App> CreateApp(
       const guest_os::GuestOsRegistryService::Registration& registration,
       bool generate_new_icon_key);
diff --git a/chrome/browser/apps/app_service/publishers/extension_apps_base.cc b/chrome/browser/apps/app_service/publishers/extension_apps_base.cc
index 7976727..5156e34 100644
--- a/chrome/browser/apps/app_service/publishers/extension_apps_base.cc
+++ b/chrome/browser/apps/app_service/publishers/extension_apps_base.cc
@@ -12,6 +12,7 @@
 #include "ash/public/cpp/shelf_types.h"
 #include "base/callback.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/one_shot_event.h"
 #include "base/scoped_observation.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/apps/app_service/app_icon/app_icon_factory.h"
@@ -338,10 +339,23 @@
 void ExtensionAppsBase::Initialize() {
   RegisterPublisher(AppType::kExtension);
 
+  prefs_observation_.Observe(extensions::ExtensionPrefs::Get(profile_));
+  registry_observation_.Observe(extensions::ExtensionRegistry::Get(profile_));
+
   DCHECK(profile_);
   PublisherBase::Initialize(proxy()->AppService(),
                             apps::mojom::AppType::kExtension);
 
+  // Publish apps after all extensions have been loaded, to include all apps
+  // including the disabled apps.
+  extensions::ExtensionSystem::Get(profile_)->ready().Post(
+      FROM_HERE, base::BindOnce(&ExtensionAppsBase::OnExtensionsReady,
+                                weak_factory_.GetWeakPtr()));
+
+  app_service_ = proxy()->AppService().get();
+}
+
+void ExtensionAppsBase::OnExtensionsReady() {
   std::vector<std::unique_ptr<App>> apps;
   extensions::ExtensionRegistry* registry =
       extensions::ExtensionRegistry::Get(profile_);
@@ -357,10 +371,6 @@
   //
   // If making changes to which sets are consulted, also change ShouldShow,
   // OnHideWebStoreIconPrefChanged.
-
-  prefs_observation_.Observe(extensions::ExtensionPrefs::Get(profile_));
-  registry_observation_.Observe(extensions::ExtensionRegistry::Get(profile_));
-  app_service_ = proxy()->AppService().get();
 }
 
 void ExtensionAppsBase::LoadIcon(const std::string& app_id,
diff --git a/chrome/browser/apps/app_service/publishers/extension_apps_base.h b/chrome/browser/apps/app_service/publishers/extension_apps_base.h
index 5fd62a2..a2d5bff 100644
--- a/chrome/browser/apps/app_service/publishers/extension_apps_base.h
+++ b/chrome/browser/apps/app_service/publishers/extension_apps_base.h
@@ -133,6 +133,8 @@
   // and should therefore by handled by this publisher.
   virtual bool Accepts(const extensions::Extension* extension) = 0;
 
+  void OnExtensionsReady();
+
   // apps::AppPublisher overrides.
   void LoadIcon(const std::string& app_id,
                 const IconKey& icon_key,
diff --git a/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc b/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc
index bd3bdaf8..ed6e9fa 100644
--- a/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc
+++ b/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc
@@ -815,13 +815,15 @@
     DCHECK(base::Contains(app_window_to_aura_window_, app_window));
     window = app_window_to_aura_window_[app_window];
   }
+  std::vector<std::unique_ptr<apps::Instance>> deltas;
   auto instance = std::make_unique<apps::Instance>(
       app_window->extension_id(),
       apps::Instance::InstanceKey::ForWindowBasedApp(window));
   instance->SetLaunchId(GetLaunchId(app_window));
   instance->UpdateState(new_state, base::Time::Now());
   instance->SetBrowserContext(app_window->browser_context());
-  instance_registry_->OnInstance(std::move(instance));
+  deltas.push_back(std::move(instance));
+  instance_registry_->OnInstances(std::move(deltas));
 }
 
 content::WebContents* ExtensionAppsChromeOs::LaunchImpl(
diff --git a/chrome/browser/apps/platform_apps/api/sync_file_system/extension_sync_event_observer.h b/chrome/browser/apps/platform_apps/api/sync_file_system/extension_sync_event_observer.h
index e46dc33d..f9184ab 100644
--- a/chrome/browser/apps/platform_apps/api/sync_file_system/extension_sync_event_observer.h
+++ b/chrome/browser/apps/platform_apps/api/sync_file_system/extension_sync_event_observer.h
@@ -8,7 +8,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/values.h"
 #include "chrome/browser/sync_file_system/sync_event_observer.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
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 3f45736..10154dbc 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
@@ -6,6 +6,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
+#include "build/build_config.h"
 #include "chrome/browser/ash/account_manager/account_manager_policy_controller.h"
 #include "chrome/browser/ash/account_manager/account_manager_policy_controller_factory.h"
 #include "chrome/browser/ash/account_manager/child_account_type_changed_user_data.h"
@@ -186,9 +187,17 @@
             accounts[0].key.id());
 }
 
+// TODO(crbug.com/1271335): Flaky on ChromeOS
+#if defined(OS_CHROMEOS)
+#define MAYBE_SecondaryAccountsAreRemovedAfterAccountTypeChangedWithCoexistenceEnabled \
+  DISABLED_SecondaryAccountsAreRemovedAfterAccountTypeChangedWithCoexistenceEnabled
+#else
+#define MAYBE_SecondaryAccountsAreRemovedAfterAccountTypeChangedWithCoexistenceEnabled \
+  SecondaryAccountsAreRemovedAfterAccountTypeChangedWithCoexistenceEnabled
+#endif
 IN_PROC_BROWSER_TEST_F(
     AccountManagerPolicyControllerTest,
-    SecondaryAccountsAreRemovedAfterAccountTypeChangedWithCoexistenceEnabled) {
+    MAYBE_SecondaryAccountsAreRemovedAfterAccountTypeChangedWithCoexistenceEnabled) {
   std::vector<::account_manager::Account> accounts =
       GetAccountManagerAccounts();
   const std::vector<::account_manager::Account>::size_type
diff --git a/chrome/browser/ash/app_mode/kiosk_app_update_service.h b/chrome/browser/ash/app_mode/kiosk_app_update_service.h
index 78b4d1f..544a7cc 100644
--- a/chrome/browser/ash/app_mode/kiosk_app_update_service.h
+++ b/chrome/browser/ash/app_mode/kiosk_app_update_service.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager_observer.h"
diff --git a/chrome/browser/ash/app_mode/kiosk_mode_idle_app_name_notification.h b/chrome/browser/ash/app_mode/kiosk_mode_idle_app_name_notification.h
index 0e32682e..c3812aa 100644
--- a/chrome/browser/ash/app_mode/kiosk_mode_idle_app_name_notification.h
+++ b/chrome/browser/ash/app_mode/kiosk_mode_idle_app_name_notification.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/timer/timer.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "ui/base/user_activity/user_activity_observer.h"
diff --git a/chrome/browser/ash/app_restore/arc_app_launch_handler.cc b/chrome/browser/ash/app_restore/arc_app_launch_handler.cc
index 7e195fc3..0fedc85 100644
--- a/chrome/browser/ash/app_restore/arc_app_launch_handler.cc
+++ b/chrome/browser/ash/app_restore/arc_app_launch_handler.cc
@@ -423,19 +423,19 @@
 
     bool launch_ghost_window = false;
 #if BUILDFLAG(ENABLE_WAYLAND_SERVER)
-    if (window_handler_ && (data_it.second->bounds_in_root.has_value() ||
-                            data_it.second->current_bounds.has_value())) {
-      RecordArcGhostWindowLaunch(/*is_arc_ghost_window=*/true);
-      window_handler_->LaunchArcGhostWindow(app_id, arc_session_id,
-                                            data_it.second.get());
+    if (window_handler_ &&
+        (data_it.second->bounds_in_root.has_value() ||
+         data_it.second->current_bounds.has_value()) &&
+        window_handler_->LaunchArcGhostWindow(app_id, arc_session_id,
+                                              data_it.second.get())) {
       launch_ghost_window = true;
     } else {
-      RecordArcGhostWindowLaunch(/*is_arc_ghost_window=*/false);
       // Only record bounds state when no ghost window launch.
       RecordLaunchBoundsState(data_it.second->bounds_in_root.has_value(),
                               data_it.second->current_bounds.has_value());
     }
 #endif
+    RecordArcGhostWindowLaunch(launch_ghost_window);
 
     const auto& file_path = handler_->profile()->GetPath();
     int32_t event_flags = data_it.second->event_flag.value();
diff --git a/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc b/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc
index 6c6de85..9981b77d 100644
--- a/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc
+++ b/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc
@@ -20,7 +20,7 @@
     ArcWindowHandler* handler,
     int window_id,
     int64_t display_id,
-    gfx::Rect bounds)
+    const gfx::Rect& bounds)
     : window_id_(window_id),
       bounds_(gfx::Rect(bounds)),
       pending_close_(false),
diff --git a/chrome/browser/ash/app_restore/arc_ghost_window_delegate.h b/chrome/browser/ash/app_restore/arc_ghost_window_delegate.h
index b6c516b..58c0e05 100644
--- a/chrome/browser/ash/app_restore/arc_ghost_window_delegate.h
+++ b/chrome/browser/ash/app_restore/arc_ghost_window_delegate.h
@@ -24,7 +24,7 @@
                          ArcWindowHandler* handler,
                          int window_id,
                          int64_t display_id,
-                         gfx::Rect bounds);
+                         const gfx::Rect& bounds);
   ~ArcGhostWindowDelegate() override;
 
   // exo::ClientControlledShellSurface::Delegate
diff --git a/chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.cc b/chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.cc
index 74e5798d..a92710b 100644
--- a/chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.cc
+++ b/chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ash/app_restore/arc_ghost_window_view.h"
 #include "chrome/browser/ash/app_restore/arc_window_utils.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
+#include "components/app_restore/app_restore_data.h"
 #include "components/app_restore/full_restore_utils.h"
 #include "components/app_restore/window_properties.h"
 #include "components/exo/buffer.h"
@@ -27,23 +28,22 @@
     ArcWindowHandler* window_handler,
     const std::string& app_id,
     int window_id,
-    absl::optional<int64_t> display_id,
-    gfx::Rect bounds,
-    absl::optional<chromeos::WindowStateType> window_state,
-    absl::optional<gfx::Size> maximum_size,
-    absl::optional<gfx::Size> minimum_size,
-    absl::optional<std::u16string> title,
-    absl::optional<uint32_t> color,
+    const gfx::Rect& bounds,
+    app_restore::AppRestoreData* restore_data,
     base::RepeatingClosure close_callback) {
-  int64_t display_id_value = display_id.value_or(display::kInvalidDisplayId);
+  int64_t display_id_value =
+      restore_data->display_id.value_or(display::kInvalidDisplayId);
   absl::optional<double> scale_factor = GetDisplayScaleFactor(display_id_value);
-  DCHECK(scale_factor.has_value());
+  if (!scale_factor.has_value())
+    return nullptr;
 
   // TODO(sstan): Fallback to system default color or other topic color, if
   // the task hasn't valid theme color.
-  uint32_t theme_color = color.has_value() && IsValidThemeColor(color.value())
-                             ? color.value()
-                             : SK_ColorWHITE;
+  uint32_t theme_color =
+      restore_data->status_bar_color.has_value() &&
+              IsValidThemeColor(restore_data->status_bar_color.value())
+          ? restore_data->status_bar_color.value()
+          : SK_ColorWHITE;
 
   // TODO(sstan): Handle the desk container from full_restore data.
   int container = ash::desks_util::GetActiveDeskContainerId();
@@ -59,17 +59,17 @@
       bounds));
   shell_surface->set_close_callback(std::move(close_callback));
 
-  shell_surface->SetAppId(app_id.c_str());
+  shell_surface->SetAppId(app_id);
   shell_surface->SetBounds(display_id_value, bounds);
 
-  if (maximum_size.has_value())
-    shell_surface->SetMaximumSize(maximum_size.value());
+  if (restore_data->maximum_size.has_value())
+    shell_surface->SetMaximumSize(restore_data->maximum_size.value());
 
-  if (minimum_size.has_value())
-    shell_surface->SetMinimumSize(minimum_size.value());
+  if (restore_data->minimum_size.has_value())
+    shell_surface->SetMinimumSize(restore_data->minimum_size.value());
 
-  if (title.has_value())
-    shell_surface->SetTitle(title.value());
+  if (restore_data->title.has_value())
+    shell_surface->SetTitle(restore_data->title.value());
 
   // Set frame buttons.
   constexpr uint32_t kAllButtonMask =
@@ -89,8 +89,9 @@
 
   // Change the minimized at the last operation, since we need create the window
   // entity first and hide it on ash shelf.
-  if (window_state.has_value() &&
-      *window_state == chromeos::WindowStateType::kMinimized) {
+  if (restore_data->window_state_type.has_value() &&
+      restore_data->window_state_type.value() ==
+          chromeos::WindowStateType::kMinimized) {
     shell_surface->SetMinimized();
     shell_surface->controller_surface()->Commit();
   }
diff --git a/chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.h b/chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.h
index 7ce061ad..26628f1 100644
--- a/chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.h
+++ b/chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.h
@@ -10,6 +10,10 @@
 #include "components/exo/client_controlled_shell_surface.h"
 #include "ui/gfx/geometry/rect.h"
 
+namespace app_restore {
+struct AppRestoreData;
+}  // namespace app_restore
+
 namespace ash {
 namespace full_restore {
 
@@ -19,13 +23,8 @@
     ArcWindowHandler* window_handler,
     const std::string& app_id,
     int window_id,
-    absl::optional<int64_t> display_id,
-    gfx::Rect bounds,
-    absl::optional<chromeos::WindowStateType> window_state,
-    absl::optional<gfx::Size> maximum_size,
-    absl::optional<gfx::Size> minimum_size,
-    absl::optional<std::u16string> title,
-    absl::optional<uint32_t> color,
+    const gfx::Rect& bounds,
+    app_restore::AppRestoreData* restore_data,
     base::RepeatingClosure close_callback);
 
 // ArcGhostWindowShellSurface class is a shell surface which controlled its
diff --git a/chrome/browser/ash/app_restore/arc_window_handler.cc b/chrome/browser/ash/app_restore/arc_window_handler.cc
index 806df9c..13079b6 100644
--- a/chrome/browser/ash/app_restore/arc_window_handler.cc
+++ b/chrome/browser/ash/app_restore/arc_window_handler.cc
@@ -71,7 +71,7 @@
   session_id_to_pending_window_info_.clear();
 }
 
-void ArcWindowHandler::LaunchArcGhostWindow(
+bool ArcWindowHandler::LaunchArcGhostWindow(
     const std::string& app_id,
     int32_t session_id,
     app_restore::AppRestoreData* restore_data) {
@@ -79,7 +79,7 @@
   DCHECK(restore_data->current_bounds.has_value());
   DCHECK(restore_data->display_id.has_value());
 
-  gfx::Rect adjust_bounds = restore_data->current_bounds.value();
+  gfx::Rect adjust_bounds = restore_data->current_bounds.value_or(gfx::Rect());
 
   // Replace the screen bounds by root bounds if there is.
   if (restore_data->bounds_in_root.has_value())
@@ -96,15 +96,15 @@
                         0, 0);
   }
 
-  session_id_to_shell_surface_.emplace(
-      session_id,
-      InitArcGhostWindow(
-          this, app_id, session_id, restore_data->display_id, adjust_bounds,
-          restore_data->window_state_type, restore_data->maximum_size,
-          restore_data->minimum_size, restore_data->title,
-          restore_data->status_bar_color,
-          base::BindRepeating(&ArcWindowHandler::CloseWindow,
-                              weak_ptr_factory_.GetWeakPtr(), session_id)));
+  auto shell_surface = InitArcGhostWindow(
+      this, app_id, session_id, adjust_bounds, restore_data,
+      base::BindRepeating(&ArcWindowHandler::CloseWindow,
+                          weak_ptr_factory_.GetWeakPtr(), session_id));
+  if (!shell_surface)
+    return false;
+
+  session_id_to_shell_surface_.emplace(session_id, std::move(shell_surface));
+  return true;
 }
 
 void ArcWindowHandler::CloseWindow(int session_id) {
diff --git a/chrome/browser/ash/app_restore/arc_window_handler.h b/chrome/browser/ash/app_restore/arc_window_handler.h
index 4e0daf3e..b029a48 100644
--- a/chrome/browser/ash/app_restore/arc_window_handler.h
+++ b/chrome/browser/ash/app_restore/arc_window_handler.h
@@ -64,7 +64,9 @@
   ArcWindowHandler& operator=(const ArcWindowHandler&) = delete;
   ~ArcWindowHandler() override;
 
-  void LaunchArcGhostWindow(const std::string& app_id,
+  // Returns true if the ghost window is created and launched. Otherwise,
+  // returns false.
+  bool LaunchArcGhostWindow(const std::string& app_id,
                             int32_t session_id,
                             ::app_restore::AppRestoreData* restore_data);
 
diff --git a/chrome/browser/ash/arc/arc_ui_availability_reporter_unittest.cc b/chrome/browser/ash/arc/arc_ui_availability_reporter_unittest.cc
index c83d3c8..9163f2e 100644
--- a/chrome/browser/ash/arc/arc_ui_availability_reporter_unittest.cc
+++ b/chrome/browser/ash/arc/arc_ui_availability_reporter_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "ash/components/arc/test/arc_util_test_support.h"
 #include "ash/components/arc/test/fake_app_instance.h"
-#include "ash/components/arc/test/fake_intent_helper_instance.h"
 #include "base/command_line.h"
 #include "base/metrics/histogram_samples.h"
 #include "base/metrics/statistics_recorder.h"
@@ -16,6 +15,7 @@
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/session/arc_service_manager.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/ash/arc/intent_helper/arc_external_protocol_dialog_unittest.cc b/chrome/browser/ash/arc/intent_helper/arc_external_protocol_dialog_unittest.cc
index 0d6d06b..7f6156c 100644
--- a/chrome/browser/ash/arc/intent_helper/arc_external_protocol_dialog_unittest.cc
+++ b/chrome/browser/ash/arc/intent_helper/arc_external_protocol_dialog_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "ash/components/arc/arc_prefs.h"
 #include "ash/components/arc/test/connection_holder_util.h"
-#include "ash/components/arc/test/fake_intent_helper_instance.h"
 #include "base/time/time.h"
 #include "chrome/browser/ash/arc/arc_web_contents_data.h"
 #include "chrome/browser/sharing/click_to_call/click_to_call_ui_controller.h"
@@ -21,6 +20,7 @@
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/session/arc_service_manager.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc b/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc
index e7fbc95..220d56b 100644
--- a/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc
+++ b/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc
@@ -13,7 +13,6 @@
 #include "ash/components/arc/test/arc_util_test_support.h"
 #include "ash/components/arc/test/connection_holder_util.h"
 #include "ash/components/arc/test/fake_backup_settings_instance.h"
-#include "ash/components/arc/test/fake_intent_helper_instance.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/command_line.h"
@@ -36,6 +35,7 @@
 #include "chromeos/network/proxy/proxy_config_handler.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/session/arc_service_manager.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
 #include "components/policy/core/common/policy_map.h"
diff --git a/chrome/browser/ash/arc/intent_helper/arc_settings_service_unittest.cc b/chrome/browser/ash/arc/intent_helper/arc_settings_service_unittest.cc
index f44b03c..ea44e19 100644
--- a/chrome/browser/ash/arc/intent_helper/arc_settings_service_unittest.cc
+++ b/chrome/browser/ash/arc/intent_helper/arc_settings_service_unittest.cc
@@ -11,7 +11,6 @@
 #include "ash/components/arc/test/connection_holder_util.h"
 #include "ash/components/arc/test/fake_arc_session.h"
 #include "ash/components/arc/test/fake_backup_settings_instance.h"
-#include "ash/components/arc/test/fake_intent_helper_instance.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "chrome/browser/ash/arc/arc_optin_uma.h"
@@ -31,6 +30,7 @@
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/session/arc_service_manager.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/testing_pref_store.h"
 #include "components/user_manager/scoped_user_manager.h"
diff --git a/chrome/browser/ash/arc/survey/arc_survey_service.cc b/chrome/browser/ash/arc/survey/arc_survey_service.cc
index b5292e8..41be33c4 100644
--- a/chrome/browser/ash/arc/survey/arc_survey_service.cc
+++ b/chrome/browser/ash/arc/survey/arc_survey_service.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "base/memory/singleton.h"
 #include "base/time/time.h"
+#include "base/values.h"
 #include "chrome/browser/ash/hats/hats_config.h"
 #include "chrome/browser/ash/hats/hats_finch_helper.h"
 #include "chrome/browser/ash/hats/hats_notification_controller.h"
@@ -21,8 +22,10 @@
 
 namespace {
 
-const int kArcGameSurveyTriggerTimeInMinutes = 10;
-constexpr char kKeyPackageNames[] = "package_names";
+const base::TimeDelta kArcGameElapsedTimeSurveyTrigger = base::Minutes(10);
+constexpr char kJSONKeyElapsedTimeSurveyTriggerMin[] =
+    "elapsed_time_survey_trigger_min";
+constexpr char kJSONKeyPackageNames[] = "package_names";
 constexpr char kKeyMostRecentAndroidGame[] = "mostRecentAndroidGame";
 
 // Singleton factory for ArcSurveyServiceFactory.
@@ -60,22 +63,22 @@
 
 ArcSurveyService::ArcSurveyService(content::BrowserContext* context,
                                    ArcBridgeService* arc_bridge_service)
-    : profile_(Profile::FromBrowserContext(context)) {
-  VLOG(1) << "ArcSurveyService created";
+    : elapsed_time_survey_trigger_(kArcGameElapsedTimeSurveyTrigger),
+      profile_(Profile::FromBrowserContext(context)) {
+  DVLOG(1) << "ArcSurveyService created";
 
   if (!base::FeatureList::IsEnabled(ash::kHatsArcGamesSurvey.feature)) {
     VLOG(1) << "ARC Games HaTS survey feature is not enabled";
     return;
   }
-  const std::string survey_data =
-      ash::HatsFinchHelper::GetCustomClientDataAsString(
-          ash::kHatsArcGamesSurvey);
+  std::string survey_data = ash::HatsFinchHelper::GetCustomClientDataAsString(
+      ash::kHatsArcGamesSurvey);
   if (survey_data.length() == 0) {
-    VLOG(1) << "No HaTS config found for ARC Games.";
+    VLOG(1) << "No survey data found for ARC Games.";
     return;
   }
-  if (!LoadPackageNames(survey_data)) {
-    VLOG(1) << "List of package names not loaded.";
+  if (!LoadSurveyData(survey_data)) {
+    VLOG(1) << "Error loading the survey data.";
     return;
   }
   ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_);
@@ -88,21 +91,47 @@
   task_id_map_.clear();
 }
 
-bool ArcSurveyService::LoadPackageNames(const std::string& survey_data) {
-  const absl::optional<base::Value> root = base::JSONReader::Read(survey_data);
+bool ArcSurveyService::LoadSurveyData(std::string survey_data) {
+  absl::optional<base::Value> root = base::JSONReader::Read(survey_data);
   if (!root) {
-    VLOG(2) << "Error reading survey data";
-    return false;
+    LOG(ERROR) << "Unable to find JSON root. Trying char substitutions.";
+    base::ReplaceSubstringsAfterOffset(&survey_data, 0, R"(\{@})", ":");
+    base::ReplaceSubstringsAfterOffset(&survey_data, 0, R"(\{~})", ",");
+    base::ReplaceSubstringsAfterOffset(&survey_data, 0, R"(\{%})", ".");
+    DVLOG(1) << "Data after substitution: " << survey_data;
+    root = base::JSONReader::Read(survey_data);
+    if (!root) {
+      LOG(ERROR) << "Unable to find JSON root after substitution";
+      return false;
+    }
   }
-  const base::Value* list = root->FindListKey(kKeyPackageNames);
+
+  // Load trigger duration
+  absl::optional<int> elapsed_time_survey_trigger_min =
+      root->FindIntKey(kJSONKeyElapsedTimeSurveyTriggerMin);
+  if (elapsed_time_survey_trigger_min) {
+    elapsed_time_survey_trigger_ =
+        (elapsed_time_survey_trigger_min.value() >= 0)
+            ? base::Minutes(elapsed_time_survey_trigger_min.value())
+            : kArcGameElapsedTimeSurveyTrigger;
+    DVLOG(1) << "Survey elapsed time trigger: " << elapsed_time_survey_trigger_;
+  }
+
+  // Load package names
+  const base::Value* list = root->FindListKey(kJSONKeyPackageNames);
   if (!list) {
-    VLOG(2) << "Package name list not found in survey data.";
+    VLOG(1) << "List of package names not found in the survey data.";
     return false;
   }
-  for (const auto& item : list->GetList()) {
+  const base::Value::ConstListView items = list->GetList();
+  if (items.empty()) {
+    VLOG(1) << "List of package names is empty in the survey data.";
+    return false;
+  }
+  for (const auto& item : items) {
     const std::string* package_name = item.GetIfString();
     if (!package_name) {
-      VLOG(2) << "Non-string value found in list";
+      VLOG(1) << "Non-string value found in list. Ignoring all results.";
       allowed_packages_.clear();
       return false;
     }
@@ -169,13 +198,12 @@
     package_name_map_.erase(package_name_iterator);
 
     // Trigger ArcGames survey if it's been active for at least
-    // |kArcGameSurveyTriggerTimeInMinutes|.
-    base::TimeDelta elapsedTime =
+    // |elapsed_time_survey_trigger_|.
+    base::TimeDelta elapsed_time =
         base::Time::NowFromSystemTime() - on_task_create_timestamp;
-    if (elapsedTime.InMinutes() >= kArcGameSurveyTriggerTimeInMinutes) {
-      VLOG(1) << "~~~ Elapsed time is more than "
-              << kArcGameSurveyTriggerTimeInMinutes << ": "
-              << elapsedTime.InMinutes();
+    if (elapsed_time >= elapsed_time_survey_trigger_) {
+      DVLOG(1) << "Elapsed time is more than " << elapsed_time_survey_trigger_
+               << ": " << elapsed_time.InMinutes();
       if (ash::HatsNotificationController::ShouldShowSurveyToProfile(
               profile_, ash::kHatsArcGamesSurvey)) {
         const base::flat_map<std::string, std::string> product_specific_data = {
diff --git a/chrome/browser/ash/arc/survey/arc_survey_service.h b/chrome/browser/ash/arc/survey/arc_survey_service.h
index 5bbb625..b5e57828 100644
--- a/chrome/browser/ash/arc/survey/arc_survey_service.h
+++ b/chrome/browser/ash/arc/survey/arc_survey_service.h
@@ -11,6 +11,7 @@
 #include <set>
 
 #include "base/scoped_observation.h"
+#include "base/time/time.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "components/keyed_service/core/keyed_service.h"
 
@@ -70,7 +71,7 @@
 
  private:
   friend class ArcSurveyServiceTest;
-  bool LoadPackageNames(const std::string& survey_data);
+  bool LoadSurveyData(std::string survey_data);
 
   base::ScopedObservation<ArcAppListPrefs, ArcAppListPrefs::Observer>
       arc_prefs_observer_{this};
@@ -97,6 +98,9 @@
   // List of package names for which to show the survey.
   std::set<std::string> allowed_packages_;
 
+  // Minimum time an app needs to have run before showing the ARC Games survey.
+  base::TimeDelta elapsed_time_survey_trigger_;
+
   // Unowned pointer.
   Profile* const profile_;
 
diff --git a/chrome/browser/ash/arc/survey/arc_survey_service_unittest.cc b/chrome/browser/ash/arc/survey/arc_survey_service_unittest.cc
index 9113bea7..09532fa1 100644
--- a/chrome/browser/ash/arc/survey/arc_survey_service_unittest.cc
+++ b/chrome/browser/ash/arc/survey/arc_survey_service_unittest.cc
@@ -7,6 +7,7 @@
 #include <cstdint>
 #include <memory>
 
+#include "base/time/time.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/session/arc_service_manager.h"
@@ -55,14 +56,18 @@
     return arc_survey_service_->GetTaskIdMapForTesting();
   }
 
-  bool LoadPackageNames(const std::string package_names) {
-    return arc_survey_service_->LoadPackageNames(package_names);
+  bool LoadSurveyData(std::string package_names) {
+    return arc_survey_service_->LoadSurveyData(package_names);
   }
 
   std::set<std::string>& GetAllowedPackageNameSet() {
     return arc_survey_service_->allowed_packages_;
   }
 
+  const base::TimeDelta GetElapsedTimeSurveyTrigger() {
+    return arc_survey_service_->elapsed_time_survey_trigger_;
+  }
+
  private:
   content::BrowserTaskEnvironment task_environment_;
   TestingProfile testing_profile_;
@@ -74,7 +79,7 @@
 
 TEST_F(ArcSurveyServiceTest, SingleTask) {
   // Create task
-  EXPECT_EQ(0, GetPackageNameMap()->size());
+  EXPECT_TRUE(GetPackageNameMap()->empty());
   OnTaskCreated(1, kPackageA);
 
   EXPECT_EQ(1, GetPackageNameMap()->size());
@@ -91,13 +96,13 @@
 
   // Destroy original task
   OnTaskDestroyed(1);
-  EXPECT_EQ(0, GetPackageNameMap()->size());
-  EXPECT_EQ(0, getTaskIdMap()->size());
+  EXPECT_TRUE(GetPackageNameMap()->empty());
+  EXPECT_TRUE(getTaskIdMap()->empty());
 }
 
 TEST_F(ArcSurveyServiceTest, MultiPackage) {
   // Create 2 tasks
-  EXPECT_EQ(0, GetPackageNameMap()->size());
+  EXPECT_TRUE(GetPackageNameMap()->empty());
   OnTaskCreated(1, kPackageA);
   OnTaskCreated(2, kPackageB);
 
@@ -119,13 +124,13 @@
 
   // Destroy task w/ ID 1
   OnTaskDestroyed(1);
-  EXPECT_EQ(0, GetPackageNameMap()->size());
-  EXPECT_EQ(0, getTaskIdMap()->size());
+  EXPECT_TRUE(GetPackageNameMap()->empty());
+  EXPECT_TRUE(getTaskIdMap()->empty());
 }
 
 TEST_F(ArcSurveyServiceTest, MultiTask) {
   // Create 2 tasks for the same package
-  EXPECT_EQ(0, GetPackageNameMap()->size());
+  EXPECT_TRUE(GetPackageNameMap()->empty());
   OnTaskCreated(1, kPackageA);
   OnTaskCreated(2, kPackageA);
 
@@ -145,36 +150,102 @@
 
   // Destroy task w/ ID 1
   OnTaskDestroyed(1);
-  EXPECT_EQ(0, GetPackageNameMap()->size());
-  EXPECT_EQ(0, getTaskIdMap()->size());
+  EXPECT_TRUE(GetPackageNameMap()->empty());
+  EXPECT_TRUE(getTaskIdMap()->empty());
 }
 
-TEST_F(ArcSurveyServiceTest, LoadPackageNames) {
+TEST_F(ArcSurveyServiceTest, LoadSurveyData_InvalidFormats) {
   // Clear any existing entries.
   GetAllowedPackageNameSet().clear();
-  EXPECT_EQ(0, GetAllowedPackageNameSet().size());
+  EXPECT_TRUE(GetAllowedPackageNameSet().empty());
+  EXPECT_EQ(base::Minutes(10), GetElapsedTimeSurveyTrigger());
 
-  // INVALID: No JSON String
-  EXPECT_FALSE(LoadPackageNames("foobar1234"));
-  EXPECT_EQ(0, GetAllowedPackageNameSet().size());
+  // No JSON String
+  ASSERT_FALSE(LoadSurveyData("foobar1234"));
+  EXPECT_TRUE(GetAllowedPackageNameSet().empty());
+  EXPECT_EQ(base::Minutes(10), GetElapsedTimeSurveyTrigger());
 
-  // Invalid JSON String: |package_names| as the key and a string as the value.
-  EXPECT_FALSE(LoadPackageNames(R"({"package_names":"com.android.vending")"));
-  EXPECT_EQ(0, GetAllowedPackageNameSet().size());
+  // |package_names| as a key and a string as its value, AND
+  // |elapsed_time_survey_trigger| as a key and a string as its value.
+  ASSERT_FALSE(LoadSurveyData(R"({
+      "package_names":"com.android.vending",
+      "elapsed_time_survey_trigger_ min":"foo"})"));
+  EXPECT_TRUE(GetAllowedPackageNameSet().empty());
+  EXPECT_EQ(base::Minutes(10), GetElapsedTimeSurveyTrigger());
 
-  // Invalid JSON format: |package_names| as the key and not all the items in
-  // the list are strings.
-  EXPECT_FALSE(
-      LoadPackageNames(R"({"package_names":["com.android.vending",123]})"));
-  EXPECT_EQ(0, GetAllowedPackageNameSet().size());
+  // |elapsed_time_survey_trigger| as the key and a string as its value.
+  ASSERT_FALSE(LoadSurveyData(R"({
+      "package_names":"com.android.vending",
+      "elapsed_time_survey_trigger_ min":"foo")"));
+  EXPECT_TRUE(GetAllowedPackageNameSet().empty());
+  EXPECT_EQ(base::Minutes(10), GetElapsedTimeSurveyTrigger());
 
-  // Valid JSON Format: |package_names| as the key and ALL the items in the list
-  // are strings.
-  EXPECT_TRUE(LoadPackageNames(
-      R"({"package_names":["com.android.vending","com.android.settings"]})"));
+  // |package_names| as the key and not all the items in the list are strings.
+  ASSERT_FALSE(LoadSurveyData(R"({
+      "package_names":["com.android.vending",123]})"));
+  EXPECT_TRUE(GetAllowedPackageNameSet().empty());
+}
+
+TEST_F(ArcSurveyServiceTest, LoadSurveyData_ValidFormat) {
+  // Clear any existing entries.
+  GetAllowedPackageNameSet().clear();
+  EXPECT_TRUE(GetAllowedPackageNameSet().empty());
+  EXPECT_EQ(base::Minutes(10), GetElapsedTimeSurveyTrigger());
+
+  ASSERT_TRUE(LoadSurveyData(R"({
+      "package_names":["com.android.vending","com.android.settings"],
+      "elapsed_time_survey_trigger_min":200})"));
   EXPECT_EQ(2, GetAllowedPackageNameSet().size());
   EXPECT_EQ(1, GetAllowedPackageNameSet().count("com.android.vending"));
   EXPECT_EQ(1, GetAllowedPackageNameSet().count("com.android.settings"));
+  EXPECT_EQ(base::Minutes(200), GetElapsedTimeSurveyTrigger());
+}
+
+TEST_F(ArcSurveyServiceTest, LoadSurveyData_ValidFormat_EmptyList) {
+  // Clear any existing entries.
+  GetAllowedPackageNameSet().clear();
+  EXPECT_TRUE(GetAllowedPackageNameSet().empty());
+  EXPECT_EQ(base::Minutes(10), GetElapsedTimeSurveyTrigger());
+
+  ASSERT_FALSE(LoadSurveyData(R"({"package_names":[]})"));
+  EXPECT_TRUE(GetAllowedPackageNameSet().empty());
+  EXPECT_EQ(base::Minutes(10), GetElapsedTimeSurveyTrigger());
+}
+
+TEST_F(ArcSurveyServiceTest, LoadSurveyData_ValidFormat_NoSurveyTrigger) {
+  // Clear any existing entries.
+  GetAllowedPackageNameSet().clear();
+  EXPECT_TRUE(GetAllowedPackageNameSet().empty());
+  EXPECT_EQ(base::Minutes(10), GetElapsedTimeSurveyTrigger());
+
+  // No |elapsed_time_survey_trigger_min| key
+  ASSERT_TRUE(LoadSurveyData(R"({
+      "package_names":["com.android.vending","com.android.settings"]})"));
+  EXPECT_EQ(2, GetAllowedPackageNameSet().size());
+  EXPECT_EQ(1, GetAllowedPackageNameSet().count("com.android.vending"));
+  EXPECT_EQ(1, GetAllowedPackageNameSet().count("com.android.settings"));
+  EXPECT_EQ(base::Minutes(10), GetElapsedTimeSurveyTrigger());
+}
+
+TEST_F(ArcSurveyServiceTest, LoadSurveyData_ValidFormat_CharSubstitution) {
+  // Clear any existing entries.
+  GetAllowedPackageNameSet().clear();
+  EXPECT_TRUE(GetAllowedPackageNameSet().empty());
+  EXPECT_EQ(base::Minutes(10), GetElapsedTimeSurveyTrigger());
+
+  // Survey Data that requires character substitution.
+  // \{@} --> :
+  // \{~} --> ,
+  // \{%} --> .
+  ASSERT_TRUE(LoadSurveyData(R"({
+      "package_names"\{@}[
+         "com\{%}android\{%}vending"\{~}"com\{%}android\{%}settings"]\{~}
+      "elapsed_time_survey_trigger_min"\{@}500})"));
+
+  EXPECT_EQ(2, GetAllowedPackageNameSet().size());
+  EXPECT_EQ(1, GetAllowedPackageNameSet().count("com.android.vending"));
+  EXPECT_EQ(1, GetAllowedPackageNameSet().count("com.android.settings"));
+  EXPECT_EQ(base::Minutes(500), GetElapsedTimeSurveyTrigger());
 }
 
 }  // namespace arc
diff --git a/chrome/browser/ash/arc/user_session/arc_user_session_service_browsertest.cc b/chrome/browser/ash/arc/user_session/arc_user_session_service_browsertest.cc
index ae919c1..23f79c01 100644
--- a/chrome/browser/ash/arc/user_session/arc_user_session_service_browsertest.cc
+++ b/chrome/browser/ash/arc/user_session/arc_user_session_service_browsertest.cc
@@ -8,13 +8,13 @@
 
 #include "ash/components/arc/test/arc_util_test_support.h"
 #include "ash/components/arc/test/connection_holder_util.h"
-#include "ash/components/arc/test/fake_intent_helper_instance.h"
 #include "base/run_loop.h"
 #include "base/task/current_thread.h"
 #include "chrome/browser/ui/ash/shelf/chrome_shelf_prefs.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/session/arc_service_manager.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
 #include "components/session_manager/core/session_manager.h"
 #include "content/public/test/browser_test.h"
 
diff --git a/chrome/browser/ash/arc/user_session/arc_user_session_service_unittest.cc b/chrome/browser/ash/arc/user_session/arc_user_session_service_unittest.cc
index 3230a3e..75f5619 100644
--- a/chrome/browser/ash/arc/user_session/arc_user_session_service_unittest.cc
+++ b/chrome/browser/ash/arc/user_session/arc_user_session_service_unittest.cc
@@ -5,11 +5,11 @@
 #include "chrome/browser/ash/arc/user_session/arc_user_session_service.h"
 
 #include "ash/components/arc/test/connection_holder_util.h"
-#include "ash/components/arc/test/fake_intent_helper_instance.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/session/arc_service_manager.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
 #include "components/session_manager/core/session_manager.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ash/attestation/attestation_ca_client.h b/chrome/browser/ash/attestation/attestation_ca_client.h
index 38e1eac..e17ecc39 100644
--- a/chrome/browser/ash/attestation/attestation_ca_client.h
+++ b/chrome/browser/ash/attestation/attestation_ca_client.h
@@ -9,7 +9,7 @@
 #include <map>
 #include <string>
 
-#include "chromeos/attestation/attestation_flow.h"
+#include "ash/components/attestation/attestation_flow.h"
 #include "chromeos/dbus/constants/attestation_constants.h"
 
 namespace network {
diff --git a/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl.cc b/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl.cc
index 2d7ee3e..33bbb59 100644
--- a/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl.cc
+++ b/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl.cc
@@ -7,6 +7,8 @@
 #include <memory>
 #include <utility>
 
+#include "ash/components/attestation/attestation_flow.h"
+#include "ash/components/attestation/attestation_flow_adaptive.h"
 #include "base/bind.h"
 #include "base/check.h"
 #include "base/location.h"
@@ -14,8 +16,6 @@
 #include "base/time/time.h"
 #include "chrome/browser/ash/attestation/attestation_ca_client.h"
 #include "chrome/browser/ash/attestation/certificate_util.h"
-#include "chromeos/attestation/attestation_flow.h"
-#include "chromeos/attestation/attestation_flow_adaptive.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
 #include "components/account_id/account_id.h"
diff --git a/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl.h b/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl.h
index d7f5a55..5d6799a 100644
--- a/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl.h
+++ b/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl.h
@@ -13,9 +13,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "chrome/browser/ash/attestation/enrollment_certificate_uploader.h"
-// TODO(https://crbug.com/1164001): forward declare AttestationFlow
-// after //chromeos/attestation is moved to ash.
-#include "chromeos/attestation/attestation_flow.h"
 #include "chromeos/dbus/constants/attestation_constants.h"
 
 namespace policy {
@@ -25,6 +22,8 @@
 namespace ash {
 namespace attestation {
 
+class AttestationFlow;
+
 // A class which uploads enterprise enrollment certificates.
 class EnrollmentCertificateUploaderImpl : public EnrollmentCertificateUploader {
  public:
diff --git a/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl_unittest.cc b/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl_unittest.cc
index d39d0532..84900f36 100644
--- a/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl_unittest.cc
+++ b/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "ash/components/attestation/mock_attestation_flow.h"
 #include "ash/components/settings/cros_settings_names.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -19,7 +20,6 @@
 #include "chrome/browser/ash/attestation/enrollment_certificate_uploader_impl.h"
 #include "chrome/browser/ash/attestation/fake_certificate.h"
 #include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
-#include "chromeos/attestation/mock_attestation_flow.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ash/attestation/machine_certificate_uploader_impl.cc b/chrome/browser/ash/attestation/machine_certificate_uploader_impl.cc
index aa03c30..66ec087 100644
--- a/chrome/browser/ash/attestation/machine_certificate_uploader_impl.cc
+++ b/chrome/browser/ash/attestation/machine_certificate_uploader_impl.cc
@@ -7,6 +7,8 @@
 #include <memory>
 #include <string>
 
+#include "ash/components/attestation/attestation_flow.h"
+#include "ash/components/attestation/attestation_flow_adaptive.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
@@ -14,8 +16,6 @@
 #include "chrome/browser/ash/attestation/attestation_ca_client.h"
 #include "chrome/browser/ash/attestation/attestation_key_payload.pb.h"
 #include "chrome/browser/ash/attestation/certificate_util.h"
-#include "chromeos/attestation/attestation_flow.h"
-#include "chromeos/attestation/attestation_flow_adaptive.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/attestation/attestation_client.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
diff --git a/chrome/browser/ash/attestation/machine_certificate_uploader_impl.h b/chrome/browser/ash/attestation/machine_certificate_uploader_impl.h
index 0a71dad..b4d35d6 100644
--- a/chrome/browser/ash/attestation/machine_certificate_uploader_impl.h
+++ b/chrome/browser/ash/attestation/machine_certificate_uploader_impl.h
@@ -12,12 +12,9 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "chrome/browser/ash/attestation/machine_certificate_uploader.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-// TODO(https://crbug.com/1164001): forward declare AttestationFlow
-// after //chromeos/attestation is moved to ash.
-#include "chromeos/attestation/attestation_flow.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
 #include "chromeos/dbus/constants/attestation_constants.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace policy {
 class CloudPolicyClient;
@@ -26,6 +23,8 @@
 namespace ash {
 namespace attestation {
 
+class AttestationFlow;
+
 // A class which uploads enterprise machine certificates.
 class MachineCertificateUploaderImpl : public MachineCertificateUploader {
  public:
diff --git a/chrome/browser/ash/attestation/machine_certificate_uploader_impl_unittest.cc b/chrome/browser/ash/attestation/machine_certificate_uploader_impl_unittest.cc
index 293a1b4..273494f 100644
--- a/chrome/browser/ash/attestation/machine_certificate_uploader_impl_unittest.cc
+++ b/chrome/browser/ash/attestation/machine_certificate_uploader_impl_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "ash/components/attestation/mock_attestation_flow.h"
 #include "ash/components/settings/cros_settings_names.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -18,7 +19,6 @@
 #include "chrome/browser/ash/attestation/fake_certificate.h"
 #include "chrome/browser/ash/attestation/machine_certificate_uploader_impl.h"
 #include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
-#include "chromeos/attestation/mock_attestation_flow.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/attestation/fake_attestation_client.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
diff --git a/chrome/browser/ash/attestation/platform_verification_flow.cc b/chrome/browser/ash/attestation/platform_verification_flow.cc
index 21d1b1b4..fb943480 100644
--- a/chrome/browser/ash/attestation/platform_verification_flow.cc
+++ b/chrome/browser/ash/attestation/platform_verification_flow.cc
@@ -7,6 +7,8 @@
 #include <memory>
 #include <utility>
 
+#include "ash/components/attestation/attestation_flow.h"
+#include "ash/components/attestation/attestation_flow_adaptive.h"
 #include "ash/constants/ash_switches.h"
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -20,8 +22,6 @@
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/permissions/permission_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chromeos/attestation/attestation_flow.h"
-#include "chromeos/attestation/attestation_flow_adaptive.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/attestation/attestation.pb.h"
 #include "chromeos/dbus/attestation/attestation_client.h"
diff --git a/chrome/browser/ash/attestation/platform_verification_flow.h b/chrome/browser/ash/attestation/platform_verification_flow.h
index 424c166..ed082bd 100644
--- a/chrome/browser/ash/attestation/platform_verification_flow.h
+++ b/chrome/browser/ash/attestation/platform_verification_flow.h
@@ -13,9 +13,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
-// TODO(https://crbug.com/1164001): forward declare AttestationFlow
-// after //chromeos/attestation is moved to ash.
-#include "chromeos/attestation/attestation_flow.h"
 // TODO(https://crbug.com/1164001): forward declare AttestationClient
 // before ChromeOS source migration.
 #include "chromeos/dbus/attestation/attestation_client.h"
@@ -37,6 +34,7 @@
 namespace ash {
 namespace attestation {
 
+class AttestationFlow;
 class PlatformVerificationFlowTest;
 
 // This class allows platform verification for the content protection use case.
diff --git a/chrome/browser/ash/attestation/platform_verification_flow_unittest.cc b/chrome/browser/ash/attestation/platform_verification_flow_unittest.cc
index 99ea7d1..fe6b8e6 100644
--- a/chrome/browser/ash/attestation/platform_verification_flow_unittest.cc
+++ b/chrome/browser/ash/attestation/platform_verification_flow_unittest.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include "ash/components/attestation/mock_attestation_flow.h"
 #include "ash/components/settings/cros_settings_names.h"
 #include "base/bind.h"
 #include "base/run_loop.h"
@@ -17,7 +18,6 @@
 #include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
 #include "chrome/browser/profiles/profile_impl.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/attestation/mock_attestation_flow.h"
 #include "chromeos/dbus/attestation/attestation.pb.h"
 #include "chromeos/dbus/attestation/fake_attestation_client.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
diff --git a/chrome/browser/ash/attestation/tpm_challenge_key_subtle.cc b/chrome/browser/ash/attestation/tpm_challenge_key_subtle.cc
index a0c534d..711b2cb 100644
--- a/chrome/browser/ash/attestation/tpm_challenge_key_subtle.cc
+++ b/chrome/browser/ash/attestation/tpm_challenge_key_subtle.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ash/attestation/tpm_challenge_key_subtle.h"
 
+#include "ash/components/attestation/attestation_flow_adaptive.h"
 #include "ash/components/settings/cros_settings_names.h"
 #include "base/base64.h"
 #include "base/bind.h"
@@ -24,7 +25,6 @@
 #include "chrome/browser/extensions/chrome_extension_function_details.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/attestation/attestation_flow_adaptive.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/attestation/attestation_client.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
diff --git a/chrome/browser/ash/attestation/tpm_challenge_key_subtle.h b/chrome/browser/ash/attestation/tpm_challenge_key_subtle.h
index fd2d174..45e83322 100644
--- a/chrome/browser/ash/attestation/tpm_challenge_key_subtle.h
+++ b/chrome/browser/ash/attestation/tpm_challenge_key_subtle.h
@@ -8,12 +8,12 @@
 #include <memory>
 #include <string>
 
+#include "ash/components/attestation/attestation_flow.h"
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "chrome/browser/ash/attestation/tpm_challenge_key_result.h"
 #include "chrome/browser/platform_keys/platform_keys.h"
-#include "chromeos/attestation/attestation_flow.h"
 #include "chromeos/dbus/attestation/attestation_ca.pb.h"
 #include "chromeos/dbus/attestation/attestation_client.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
diff --git a/chrome/browser/ash/attestation/tpm_challenge_key_subtle_unittest.cc b/chrome/browser/ash/attestation/tpm_challenge_key_subtle_unittest.cc
index 3ac9117..f0a36ca 100644
--- a/chrome/browser/ash/attestation/tpm_challenge_key_subtle_unittest.cc
+++ b/chrome/browser/ash/attestation/tpm_challenge_key_subtle_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ash/attestation/tpm_challenge_key_subtle.h"
 
+#include "ash/components/attestation/mock_attestation_flow.h"
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/test/gmock_callback_support.h"
@@ -22,7 +23,6 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
-#include "chromeos/attestation/mock_attestation_flow.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/attestation/fake_attestation_client.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
diff --git a/chrome/browser/ash/boot_times_recorder.h b/chrome/browser/ash/boot_times_recorder.h
index 63bfc4c5..969f0af9 100644
--- a/chrome/browser/ash/boot_times_recorder.h
+++ b/chrome/browser/ash/boot_times_recorder.h
@@ -9,7 +9,6 @@
 
 #include "base/atomic_sequence_num.h"
 #include "base/callback_forward.h"
-#include "base/compiler_specific.h"
 #include "base/scoped_multi_source_observation.h"
 #include "chromeos/metrics/login_event_recorder.h"
 #include "content/public/browser/notification_observer.h"
diff --git a/chrome/browser/ash/child_accounts/family_user_app_metrics_unittest.cc b/chrome/browser/ash/child_accounts/family_user_app_metrics_unittest.cc
index ec87c8b..64f491a 100644
--- a/chrome/browser/ash/child_accounts/family_user_app_metrics_unittest.cc
+++ b/chrome/browser/ash/child_accounts/family_user_app_metrics_unittest.cc
@@ -194,15 +194,16 @@
     cache.OnApps(std::move(deltas), apps::mojom::AppType::kUnknown,
                  false /* should_notify_initialized */);
 
+    apps::InstanceRegistry::Instances instances;
     apps::InstanceRegistry& instance_registry =
         apps::AppServiceProxyFactory::GetForProfile(profile())
             ->InstanceRegistry();
     window_ = std::make_unique<aura::Window>(nullptr);
     window_->Init(ui::LAYER_NOT_DRAWN);
-    auto instance = std::make_unique<apps::Instance>(
+    instances.push_back(std::make_unique<apps::Instance>(
         /*app_id=*/"a",
-        apps::Instance::InstanceKey::ForWindowBasedApp(window_.get()));
-    instance_registry.OnInstance(std::move(instance));
+        apps::Instance::InstanceKey::ForWindowBasedApp(window_.get())));
+    instance_registry.OnInstances(std::move(instances));
   }
 
   SupervisedUserService* supervised_user_service() {
diff --git a/chrome/browser/ash/child_accounts/family_user_chrome_activity_metrics_unittest.cc b/chrome/browser/ash/child_accounts/family_user_chrome_activity_metrics_unittest.cc
index 97a0946..d617a40 100644
--- a/chrome/browser/ash/child_accounts/family_user_chrome_activity_metrics_unittest.cc
+++ b/chrome/browser/ash/child_accounts/family_user_chrome_activity_metrics_unittest.cc
@@ -137,9 +137,12 @@
         apps::Instance::InstanceKey::ForWindowBasedApp(window));
     instance->UpdateState(state, base::Time::Now());
 
+    std::vector<std::unique_ptr<apps::Instance>> deltas;
+    deltas.push_back(std::move(instance));
+
     apps::AppServiceProxyFactory::GetForProfile(profile())
         ->InstanceRegistry()
-        .OnInstance(std::move(instance));
+        .OnInstances(std::move(deltas));
   }
 
   std::unique_ptr<Browser> CreateBrowserWithAuraWindow() {
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.cc b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
index fc4b56c1..7721389 100644
--- a/chrome/browser/ash/chrome_browser_main_parts_ash.cc
+++ b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
@@ -26,7 +26,6 @@
 #include "ash/public/ash_interfaces.h"
 #include "ash/public/cpp/event_rewriter_controller.h"
 #include "ash/public/cpp/keyboard/keyboard_controller.h"
-#include "ash/public/cpp/quick_answers/controller/quick_answers_controller.h"
 #include "ash/shell.h"
 #include "ash/system/pcie_peripheral/pcie_peripheral_notification_controller.h"
 #include "base/bind.h"
@@ -180,6 +179,7 @@
 #include "chrome/common/pref_names.h"
 #include "chromeos/components/chromebox_for_meetings/buildflags/buildflags.h"  // PLATFORM_CFM
 #include "chromeos/components/local_search_service/public/cpp/local_search_service_proxy_factory.h"
+#include "chromeos/components/quick_answers/public/cpp/controller/quick_answers_controller.h"
 #include "chromeos/components/quick_answers/quick_answers_client.h"
 #include "chromeos/components/sensors/ash/sensor_hal_dispatcher.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
diff --git a/chrome/browser/ash/crostini/crostini_terminal.cc b/chrome/browser/ash/crostini/crostini_terminal.cc
index aef8de6..2ce259c 100644
--- a/chrome/browser/ash/crostini/crostini_terminal.cc
+++ b/chrome/browser/ash/crostini/crostini_terminal.cc
@@ -4,8 +4,11 @@
 
 #include "chrome/browser/ash/crostini/crostini_terminal.h"
 
+#include "ash/public/cpp/app_menu_constants.h"
 #include "base/bind.h"
 #include "base/containers/fixed_flat_map.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
 #include "base/strings/strcat.h"
@@ -13,6 +16,8 @@
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
+#include "chrome/browser/apps/app_service/menu_util.h"
+#include "chrome/browser/ash/crostini/crostini_features.h"
 #include "chrome/browser/ash/crostini/crostini_pref_names.h"
 #include "chrome/browser/ash/crostini/crostini_util.h"
 #include "chrome/browser/browser_process.h"
@@ -27,6 +32,7 @@
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
+#include "chrome/grit/generated_resources.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/escape.h"
@@ -47,6 +53,26 @@
 constexpr char kSettingPassCtrlW[] = "/hterm/profiles/default/pass-ctrl-w";
 constexpr bool kDefaultPassCtrlW = false;
 
+constexpr char kShortcutKey[] = "shortcut";
+constexpr char kShortcutValueTerminal[] = "terminal";
+
+std::string ShortcutIdFromContainerId(const crostini::ContainerId& id) {
+  base::Value dict = id.ToDictValue();
+  dict.SetKey(kShortcutKey, base::Value(kShortcutValueTerminal));
+  std::string shortcut_id;
+  base::JSONWriter::Write(dict, &shortcut_id);
+  return shortcut_id;
+}
+
+base::flat_map<std::string, std::string> ExtrasFromShortcutId(
+    const base::Value& shortcut) {
+  base::flat_map<std::string, std::string> extras;
+  for (const auto it : shortcut.DictItems()) {
+    extras[it.first] = it.second.GetString();
+  }
+  return extras;
+}
+
 GURL GenerateVshInCroshUrl(Profile* profile,
                            const ContainerId& container_id,
                            const std::string& cwd,
@@ -278,4 +304,57 @@
   return value->FindBoolKey(kSettingPassCtrlW).value_or(kDefaultPassCtrlW);
 }
 
+void AddTerminalMenuItems(Profile* profile,
+                          apps::mojom::MenuItemsPtr* menu_items) {
+  apps::AddCommandItem(ash::SETTINGS, IDS_INTERNAL_APP_SETTINGS, menu_items);
+  if (IsCrostiniRunning(profile)) {
+    apps::AddCommandItem(ash::SHUTDOWN_GUEST_OS,
+                         IDS_CROSTINI_SHUT_DOWN_LINUX_MENU_ITEM, menu_items);
+  }
+}
+
+void AddTerminalMenuShortcuts(Profile* profile,
+                              apps::mojom::MenuItemsPtr* menu_items,
+                              int next_command_id) {
+  if (!crostini::CrostiniFeatures::Get()->IsMultiContainerAllowed(profile)) {
+    return;
+  }
+
+  const base::Value* container_list =
+      profile->GetPrefs()->GetList(crostini::prefs::kCrostiniContainers);
+  if (container_list && container_list->GetList().size() > 1) {
+    apps::AddSeparator(ui::DOUBLE_SEPARATOR, menu_items);
+
+    for (const auto& dict : container_list->GetList()) {
+      crostini::ContainerId id(dict);
+      if (!id.vm_name.empty() && !id.container_name.empty()) {
+        std::string shortcut_id = ShortcutIdFromContainerId(id);
+        std::string label = base::StrCat({id.vm_name, ":", id.container_name});
+        apps::AddShortcutCommandItem(next_command_id++, shortcut_id, label,
+                                     gfx::ImageSkia(), menu_items);
+      }
+    }
+  }
+}
+
+bool ExecuteTerminalMenuShortcutCommand(Profile* profile,
+                                        const std::string& shortcut_id,
+                                        int64_t display_id) {
+  auto shortcut = base::JSONReader::Read(shortcut_id);
+  if (!shortcut || !shortcut->is_dict()) {
+    return false;
+  }
+  const std::string* shortcut_value = shortcut->FindStringKey(kShortcutKey);
+  if (!shortcut_value || *shortcut_value != kShortcutValueTerminal) {
+    return false;
+  }
+  apps::mojom::IntentPtr intent = apps::mojom::Intent::New();
+  intent->extras = ExtrasFromShortcutId(std::move(*shortcut));
+  // TODO(crbug.com/1028898): Implement LaunchTerminalWithIntent() and call it.
+  crostini::LaunchCrostiniAppWithIntent(profile,
+                                        crostini::kCrostiniTerminalSystemAppId,
+                                        display_id, std::move(intent));
+  return true;
+}
+
 }  // namespace crostini
diff --git a/chrome/browser/ash/crostini/crostini_terminal.h b/chrome/browser/ash/crostini/crostini_terminal.h
index 4da286ed..07b5225 100644
--- a/chrome/browser/ash/crostini/crostini_terminal.h
+++ b/chrome/browser/ash/crostini/crostini_terminal.h
@@ -9,6 +9,7 @@
 
 #include "chrome/browser/apps/app_service/app_launch_params.h"
 #include "chrome/browser/ash/crostini/crostini_util.h"
+#include "components/services/app_service/public/mojom/types.mojom.h"
 #include "ui/display/types/display_constants.h"
 #include "ui/gfx/geometry/point.h"
 
@@ -119,6 +120,22 @@
 
 // Returns terminal setting 'pass-ctrl-w'.
 bool GetTerminalSettingPassCtrlW(Profile* profile);
+
+// Add terminal menu items (Settings, Shut down Linux).
+void AddTerminalMenuItems(Profile* profile,
+                          apps::mojom::MenuItemsPtr* menu_items);
+
+// Add terminal shortcut items in menu.
+void AddTerminalMenuShortcuts(Profile* profile,
+                              apps::mojom::MenuItemsPtr* menu_items,
+                              int next_command_id);
+
+// Called when user clicks on terminal menu items. Returns true if |shortcut_id|
+// is recognized and handled.
+bool ExecuteTerminalMenuShortcutCommand(Profile* profile,
+                                        const std::string& shortcut_id,
+                                        int64_t display_id);
+
 }  // namespace crostini
 
 #endif  // CHROME_BROWSER_ASH_CROSTINI_CROSTINI_TERMINAL_H_
diff --git a/chrome/browser/ash/customization/customization_document.h b/chrome/browser/ash/customization/customization_document.h
index 6338c8c0..36283ee 100644
--- a/chrome/browser/ash/customization/customization_document.h
+++ b/chrome/browser/ash/customization/customization_document.h
@@ -11,7 +11,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/singleton.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/ash/dbus/chrome_features_service_provider.h b/chrome/browser/ash/dbus/chrome_features_service_provider.h
index 7b557e22..9023a48 100644
--- a/chrome/browser/ash/dbus/chrome_features_service_provider.h
+++ b/chrome/browser/ash/dbus/chrome_features_service_provider.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_DBUS_CHROME_FEATURES_SERVICE_PROVIDER_H_
 #define CHROME_BROWSER_ASH_DBUS_CHROME_FEATURES_SERVICE_PROVIDER_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/dbus/services/cros_dbus_service.h"
diff --git a/chrome/browser/ash/dbus/component_updater_service_provider.h b/chrome/browser/ash/dbus/component_updater_service_provider.h
index 32f6abe..e0cdb8b 100644
--- a/chrome/browser/ash/dbus/component_updater_service_provider.h
+++ b/chrome/browser/ash/dbus/component_updater_service_provider.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/ash/dbus/drive_file_stream_service_provider.h b/chrome/browser/ash/dbus/drive_file_stream_service_provider.h
index cc12cdc..54a4ce7 100644
--- a/chrome/browser/ash/dbus/drive_file_stream_service_provider.h
+++ b/chrome/browser/ash/dbus/drive_file_stream_service_provider.h
@@ -7,7 +7,6 @@
 
 #include <stdint.h>
 
-#include "base/compiler_specific.h"
 #include "base/files/scoped_file.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/ash/dbus/libvda_service_provider.h b/chrome/browser/ash/dbus/libvda_service_provider.h
index cd5bb12..e2dba7ff 100644
--- a/chrome/browser/ash/dbus/libvda_service_provider.h
+++ b/chrome/browser/ash/dbus/libvda_service_provider.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/dbus/services/cros_dbus_service.h"
diff --git a/chrome/browser/ash/dbus/screen_lock_service_provider.h b/chrome/browser/ash/dbus/screen_lock_service_provider.h
index 73181db8..d846295 100644
--- a/chrome/browser/ash/dbus/screen_lock_service_provider.h
+++ b/chrome/browser/ash/dbus/screen_lock_service_provider.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/dbus/services/cros_dbus_service.h"
diff --git a/chrome/browser/ash/dbus/vm/vm_disk_management_service_provider.h b/chrome/browser/ash/dbus/vm/vm_disk_management_service_provider.h
index a25434f..2a09a91 100644
--- a/chrome/browser/ash/dbus/vm/vm_disk_management_service_provider.h
+++ b/chrome/browser/ash/dbus/vm/vm_disk_management_service_provider.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_DBUS_VM_VM_DISK_MANAGEMENT_SERVICE_PROVIDER_H_
 #define CHROME_BROWSER_ASH_DBUS_VM_VM_DISK_MANAGEMENT_SERVICE_PROVIDER_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/borealis/borealis_disk_manager.h"
 #include "chromeos/dbus/services/cros_dbus_service.h"
diff --git a/chrome/browser/ash/dbus/vm/vm_sk_forwarding_service_provider.h b/chrome/browser/ash/dbus/vm/vm_sk_forwarding_service_provider.h
index b11e0832..42dad5e 100644
--- a/chrome/browser/ash/dbus/vm/vm_sk_forwarding_service_provider.h
+++ b/chrome/browser/ash/dbus/vm/vm_sk_forwarding_service_provider.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_DBUS_VM_VM_SK_FORWARDING_SERVICE_PROVIDER_H_
 #define CHROME_BROWSER_ASH_DBUS_VM_VM_SK_FORWARDING_SERVICE_PROVIDER_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/dbus/services/cros_dbus_service.h"
 #include "dbus/exported_object.h"
diff --git a/chrome/browser/ash/dbus/vm_applications_service_provider.h b/chrome/browser/ash/dbus/vm_applications_service_provider.h
index ba39cca..73e135b 100644
--- a/chrome/browser/ash/dbus/vm_applications_service_provider.h
+++ b/chrome/browser/ash/dbus/vm_applications_service_provider.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_DBUS_VM_APPLICATIONS_SERVICE_PROVIDER_H_
 #define CHROME_BROWSER_ASH_DBUS_VM_APPLICATIONS_SERVICE_PROVIDER_H_
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/dbus/services/cros_dbus_service.h"
diff --git a/chrome/browser/ash/external_metrics.h b/chrome/browser/ash/external_metrics.h
index e37e507..520aaab1 100644
--- a/chrome/browser/ash/external_metrics.h
+++ b/chrome/browser/ash/external_metrics.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/ash/file_manager/copy_or_move_io_task.cc b/chrome/browser/ash/file_manager/copy_or_move_io_task.cc
index 8c118213..d142f5de 100644
--- a/chrome/browser/ash/file_manager/copy_or_move_io_task.cc
+++ b/chrome/browser/ash/file_manager/copy_or_move_io_task.cc
@@ -144,8 +144,12 @@
       volume_manager->FindVolumeFromPath(destination_url.path());
 
   if (!(source_volume && destination_volume)) {
-    // Use the chosen copy/move operation.
-    return false;
+    // When either volume is unavailable, fallback to only checking the
+    // filesystem_id, which uniquely maps a URL to its ExternalMountPoints
+    // instance. NOTE: different volumes (e.g. for removables), might share the
+    // same ExternalMountPoints. NOTE 2: if either volume is unavailable, the
+    // operation itself is likely to fail.
+    return source_url.filesystem_id() != destination_url.filesystem_id();
   }
 
   if (source_volume->volume_id() != destination_volume->volume_id()) {
@@ -257,14 +261,12 @@
   }
 
   int64_t required_bytes = progress_.total_bytes;
+
+  // Move operations that are same-filesystem do not require disk space.
   if (progress_.type == OperationType::kMove) {
-    // Ignore source files that are on the same volume when calculating size for
-    // moves.
-    // TODO(crbug.com/1200251): This needs some special handling for moves
-    // between "Downloads" and "My Files" due to the bind mount.
     for (int i = 0; i < source_sizes_.size(); i++) {
-      if (progress_.sources[i].url.filesystem_id() ==
-          progress_.destination_folder.filesystem_id()) {
+      if (!IsCrossFileSystem(progress_.sources[i].url,
+                             progress_.destination_folder)) {
         required_bytes -= source_sizes_[i];
       }
     }
diff --git a/chrome/browser/ash/file_manager/copy_or_move_io_task_unittest.cc b/chrome/browser/ash/file_manager/copy_or_move_io_task_unittest.cc
index 30c1b608..f0d7a8a 100644
--- a/chrome/browser/ash/file_manager/copy_or_move_io_task_unittest.cc
+++ b/chrome/browser/ash/file_manager/copy_or_move_io_task_unittest.cc
@@ -403,10 +403,7 @@
         PathToFileSystemURL(destination_path);
     // Define a dummy CopyOrMoveOITask on which
     // CopyOrMoveIOTask::IsCrossFileSystem can be called.
-    CopyOrMoveIOTask task(OperationType::kCopy,
-                          std::vector<storage::FileSystemURL>(),
-                          storage::FileSystemURL(), &profile_,
-                          scoped_refptr<storage::FileSystemContext>());
+    CopyOrMoveIOTask task({}, {}, {}, &profile_, {});
     return task.IsCrossFileSystemForTesting(source_url, destination_url);
   }
 
@@ -419,15 +416,37 @@
       blink::StorageKey::CreateFromStringForTesting("chrome://abc");
 };
 
-TEST_F(CopyOrMoveIsCrossFileSystemTest, InvalidSourceOrDestination) {
-  // The profile path is not on any registered volume. For unrecognized paths,
-  // false is returned by default.
-  base::FilePath source_path = profile_.GetPath().Append("a.txt");
-  base::FilePath destination_path = test_volume_path_.Append("a.txt");
-  ASSERT_FALSE(IsCrossFileSystem(source_path, destination_path));
-  source_path = downloads_volume_path_.Append("a.txt");
-  destination_path = base::FilePath("invalid_path").Append("a.txt");
-  ASSERT_FALSE(IsCrossFileSystem(source_path, destination_path));
+TEST_F(CopyOrMoveIsCrossFileSystemTest, NoRegisteredVolume) {
+  // Define a dummy CopyOrMoveOITask on which
+  // CopyOrMoveIOTask::IsCrossFileSystem can be called.
+  CopyOrMoveIOTask task({}, {}, {}, &profile_, {});
+  // The profile path is not on any registered volume. When no volume is
+  // registered for a given path, the result of IsCrossFileSystem is based on
+  // the filesystem_ids of the source and the destination URLs.
+  base::FilePath path = profile_.GetPath().Append("a.txt");
+
+  // Define filesystem URLs with different filesystem_id().
+  std::string source_mount_name = "mount-name-a";
+  std::string destination_mount_name = "mount-name-b";
+  storage::FileSystemURL source_url = storage::FileSystemURL::CreateForTest(
+      {}, {}, /* virtual_path */ path, {}, {}, /* cracked_path */ path,
+      /* filesystem_id */ source_mount_name, {});
+  storage::FileSystemURL destination_url =
+      storage::FileSystemURL::CreateForTest(
+          {}, {}, /* virtual_path */ path, {}, {}, /* cracked_path */ path,
+          /* filesystem_id */ destination_mount_name, {});
+  ASSERT_TRUE(task.IsCrossFileSystemForTesting(source_url, destination_url));
+
+  // Define filesystem URLs with identical filesystem_id().
+  source_mount_name = "mount-name-c";
+  destination_mount_name = "mount-name-c";
+  source_url = storage::FileSystemURL::CreateForTest(
+      {}, {}, /* virtual_path */ path, {}, {}, /* cracked_path */ path,
+      /* filesystem_id */ source_mount_name, {});
+  destination_url = storage::FileSystemURL::CreateForTest(
+      {}, {}, /* virtual_path */ path, {}, {}, /* cracked_path */ path,
+      /* filesystem_id */ destination_mount_name, {});
+  ASSERT_FALSE(task.IsCrossFileSystemForTesting(source_url, destination_url));
 }
 
 TEST_F(CopyOrMoveIsCrossFileSystemTest, DifferentVolumes) {
diff --git a/chrome/browser/ash/file_manager/fake_disk_mount_manager.h b/chrome/browser/ash/file_manager/fake_disk_mount_manager.h
index 3e631a9e..1141ae2 100644
--- a/chrome/browser/ash/file_manager/fake_disk_mount_manager.h
+++ b/chrome/browser/ash/file_manager/fake_disk_mount_manager.h
@@ -11,7 +11,6 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/containers/queue.h"
 #include "base/observer_list.h"
 #include "chromeos/dbus/cros_disks/cros_disks_client.h"
diff --git a/chrome/browser/ash/file_manager/file_tasks_browsertest.cc b/chrome/browser/ash/file_manager/file_tasks_browsertest.cc
index 6a67b3bc..c377301e 100644
--- a/chrome/browser/ash/file_manager/file_tasks_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_tasks_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/test/bind.h"
+#include "base/test/scoped_feature_list.h"
 #include "build/branding_buildflags.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
 #include "chrome/browser/ash/file_manager/app_id.h"
@@ -26,6 +27,8 @@
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/browser/web_applications/web_app_id_constants.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/browser/web_applications/web_app_registry_update.h"
+#include "chrome/browser/web_applications/web_app_sync_bridge.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/services/app_service/public/cpp/intent_util.h"
@@ -153,6 +156,10 @@
     }
     EXPECT_EQ(0, remaining);
   }
+
+ private:
+  base::test::ScopedFeatureList feature_list_{
+      blink::features::kFileHandlingAPI};
 };
 
 class FileTasksBrowserTest : public FileTasksBrowserTestBase {
@@ -498,6 +505,11 @@
         web_app::test::InstallWebApp(profile, std::move(web_app_info));
     task_descriptor =
         TaskDescriptor(app_id, TaskType::TASK_TYPE_WEB_APP, "activity name");
+    // Skip past the permission dialog.
+    web_app::ScopedRegistryUpdate(
+        &web_app::WebAppProvider::GetForTest(profile)->sync_bridge())
+        ->UpdateApp(app_id)
+        ->SetFileHandlerApprovalState(web_app::ApiApprovalState::kAllowed);
   } else {
     // Use an existing SWA in ash - Media app.
     task_descriptor =
diff --git a/chrome/browser/ash/guest_os/guest_os_registry_service.cc b/chrome/browser/ash/guest_os/guest_os_registry_service.cc
index 912d86c..f0c38471 100644
--- a/chrome/browser/ash/guest_os/guest_os_registry_service.cc
+++ b/chrome/browser/ash/guest_os/guest_os_registry_service.cc
@@ -6,8 +6,10 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/files/file_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
@@ -562,12 +564,12 @@
       prefs_->GetDictionary(guest_os::prefs::kGuestOsRegistry);
   std::map<std::string, GuestOsRegistryService::Registration> result;
   // Register Terminal by merging optional prefs with app values.
-  // TODO(crbug.com/1028898): Register Terminal as a System App rather than a
-  // crostini app.
-  result.emplace(crostini::kCrostiniTerminalSystemAppId,
-                 GetTerminalRegistration(
-                     apps->FindKeyOfType(crostini::kCrostiniTerminalSystemAppId,
-                                         base::Value::Type::DICTIONARY)));
+  if (!base::FeatureList::IsEnabled(chromeos::features::kTerminalSSH)) {
+    result.emplace(crostini::kCrostiniTerminalSystemAppId,
+                   GetTerminalRegistration(apps->FindKeyOfType(
+                       crostini::kCrostiniTerminalSystemAppId,
+                       base::Value::Type::DICTIONARY)));
+  }
   for (const auto item : apps->DictItems()) {
     if (item.first != crostini::kCrostiniTerminalSystemAppId) {
       result.emplace(item.first, Registration(item.first, item.second.Clone()));
diff --git a/chrome/browser/ash/hats/hats_dialog.cc b/chrome/browser/ash/hats/hats_dialog.cc
index 3544736..dd9ef09 100644
--- a/chrome/browser/ash/hats/hats_dialog.cc
+++ b/chrome/browser/ash/hats/hats_dialog.cc
@@ -256,7 +256,7 @@
 }
 
 bool HatsDialog::ShouldShowCloseButton() const {
-  return false;
+  return true;
 }
 
 bool HatsDialog::HandleContextMenu(content::RenderFrameHost& render_frame_host,
diff --git a/chrome/browser/ash/input_method/assistive_suggester_unittest.cc b/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
index 3165883..53999d5 100644
--- a/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
+++ b/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
@@ -515,6 +515,7 @@
                      .text = "hello there"}};
 
   assistive_suggester_->OnFocus(5);
+  assistive_suggester_->OnSurroundingTextChanged(u"", 0, 0);
   assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
 
   histogram_tester_.ExpectTotalCount("InputMethod.Assistive.Coverage", 1);
diff --git a/chrome/browser/ash/input_method/input_method_delegate_impl.h b/chrome/browser/ash/input_method/input_method_delegate_impl.h
index e9b3605..624cb14a 100644
--- a/chrome/browser/ash/input_method/input_method_delegate_impl.h
+++ b/chrome/browser/ash/input_method/input_method_delegate_impl.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "ui/base/ime/ash/input_method_delegate.h"
 
 namespace ash {
diff --git a/chrome/browser/ash/input_method/input_method_settings.cc b/chrome/browser/ash/input_method/input_method_settings.cc
index bfe743f..e9eea61 100644
--- a/chrome/browser/ash/input_method/input_method_settings.cc
+++ b/chrome/browser/ash/input_method/input_method_settings.cc
@@ -36,6 +36,30 @@
 constexpr char kPinyinPrefsLayoutDvorak[] = "Dvorak";
 constexpr char kPinyinPrefsLayoutColemak[] = "Colemak";
 
+// The values here should be kept in sync with
+// chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js
+constexpr char kZhuyinPrefsLayoutStandard[] = "Default";
+constexpr char kZhuyinPrefsLayoutIbm[] = "IBM";
+constexpr char kZhuyinPrefsLayoutEten[] = "Eten";
+
+// The values here should be kept in sync with
+// chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js
+constexpr char kZhuyinPrefsSelectionKeys1234567890[] = "1234567890";
+constexpr char kZhuyinPrefsSelectionKeysAsdfghjkl[] = "asdfghjkl;";
+constexpr char kZhuyinPrefsSelectionKeysAsdfzxcv89[] = "asdfzxcv89";
+constexpr char kZhuyinPrefsSelectionKeysAsdfjkl789[] = "asdfjkl789";
+constexpr char kZhuyinPrefsSelectionKeys1234Qweras[] = "1234qweras";
+
+// The values here should be kept in sync with
+// chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js
+constexpr char kZhuyinPrefsPageSize10[] = "10";
+constexpr char kZhuyinPrefsPageSize9[] = "9";
+constexpr char kZhuyinPrefsPageSize8[] = "8";
+
+std::string ValueOrEmpty(const std::string* str) {
+  return str ? *str : "";
+}
+
 bool IsUsEnglishEngine(const std::string& engine_id) {
   return engine_id == "xkb:us::eng";
 }
@@ -52,10 +76,17 @@
   return engine_id == "zh-t-i0-pinyin" || engine_id == "zh-hant-t-i0-pinyin";
 }
 
+bool IsZhuyinEngine(const std::string& engine_id) {
+  return engine_id == "zh-hant-t-i0-und";
+}
+
 std::string GetPrefKeyForEngineId(const std::string& engine_id) {
   if (engine_id == "zh-t-i0-pinyin") {
     return "pinyin";
   }
+  if (engine_id == "zh-hant-t-i0-und") {
+    return "zhuyin";
+  }
   return engine_id;
 }
 
@@ -160,6 +191,53 @@
   return settings;
 }
 
+mojom::ZhuyinLayout ZhuyinLayoutToMojom(const std::string& layout) {
+  if (layout == kZhuyinPrefsLayoutStandard)
+    return mojom::ZhuyinLayout::kStandard;
+  if (layout == kZhuyinPrefsLayoutIbm)
+    return mojom::ZhuyinLayout::kIbm;
+  if (layout == kZhuyinPrefsLayoutEten)
+    return mojom::ZhuyinLayout::kEten;
+  return mojom::ZhuyinLayout::kStandard;
+}
+
+mojom::ZhuyinSelectionKeys ZhuyinSelectionKeysToMojom(
+    const std::string& selection_keys) {
+  if (selection_keys == kZhuyinPrefsSelectionKeys1234567890)
+    return mojom::ZhuyinSelectionKeys::k1234567890;
+  if (selection_keys == kZhuyinPrefsSelectionKeysAsdfghjkl)
+    return mojom::ZhuyinSelectionKeys::kAsdfghjkl;
+  if (selection_keys == kZhuyinPrefsSelectionKeysAsdfzxcv89)
+    return mojom::ZhuyinSelectionKeys::kAsdfzxcv89;
+  if (selection_keys == kZhuyinPrefsSelectionKeysAsdfjkl789)
+    return mojom::ZhuyinSelectionKeys::kAsdfjkl789;
+  if (selection_keys == kZhuyinPrefsSelectionKeys1234Qweras)
+    return mojom::ZhuyinSelectionKeys::k1234Qweras;
+  return mojom::ZhuyinSelectionKeys::k1234567890;
+}
+
+uint32_t ZhuyinPageSizeToInt(const std::string& page_size) {
+  if (page_size == kZhuyinPrefsPageSize10)
+    return 10;
+  if (page_size == kZhuyinPrefsPageSize9)
+    return 9;
+  if (page_size == kZhuyinPrefsPageSize8)
+    return 8;
+  return 10;
+}
+
+mojom::ZhuyinSettingsPtr CreateZhuyinSettings(
+    const base::Value& input_method_specific_pref) {
+  auto settings = mojom::ZhuyinSettings::New();
+  settings->layout = ZhuyinLayoutToMojom(ValueOrEmpty(
+      input_method_specific_pref.FindStringKey("zhuyinKeyboardLayout")));
+  settings->selection_keys = ZhuyinSelectionKeysToMojom(ValueOrEmpty(
+      input_method_specific_pref.FindStringKey("zhuyinSelectKeys")));
+  settings->page_size = ZhuyinPageSizeToInt(
+      ValueOrEmpty(input_method_specific_pref.FindStringKey("zhuyinPageSize")));
+  return settings;
+}
+
 }  // namespace
 
 mojom::InputMethodSettingsPtr CreateSettingsFromPrefs(
@@ -199,6 +277,10 @@
     return mojom::InputMethodSettings::NewPinyinSettings(
         CreatePinyinSettings(input_method_specific_pref));
   }
+  if (IsZhuyinEngine(engine_id)) {
+    return mojom::InputMethodSettings::NewZhuyinSettings(
+        CreateZhuyinSettings(input_method_specific_pref));
+  }
 
   return nullptr;
 }
diff --git a/chrome/browser/ash/input_method/input_method_settings_unittest.cc b/chrome/browser/ash/input_method/input_method_settings_unittest.cc
index 9eac1c2..e620cea 100644
--- a/chrome/browser/ash/input_method/input_method_settings_unittest.cc
+++ b/chrome/browser/ash/input_method/input_method_settings_unittest.cc
@@ -24,6 +24,7 @@
 constexpr char kUsEnglishEngineId[] = "xkb:us::eng";
 constexpr char kKoreanEngineId[] = "ko-t-i0-und";
 constexpr char kPinyinEngineId[] = "zh-t-i0-pinyin";
+constexpr char kZhuyinEngineId[] = "zh-hant-t-i0-und";
 
 void RegisterTestingPrefs(TestingPrefServiceSimple& prefs,
                           const base::DictionaryValue& dict) {
@@ -259,6 +260,41 @@
   EXPECT_FALSE(pinyin_settings.default_to_full_width_punctuation);
 }
 
+TEST(CreateSettingsFromPrefsTest, CreateZhuyinSettingsDefault) {
+  base::DictionaryValue dict;
+  TestingPrefServiceSimple prefs;
+  RegisterTestingPrefs(prefs, dict);
+
+  const auto settings =
+      CreateSettingsFromPrefs(prefs, kZhuyinEngineId, InputFieldContext{});
+
+  ASSERT_TRUE(settings->is_zhuyin_settings());
+  const auto& zhuyin_settings = *settings->get_zhuyin_settings();
+  EXPECT_EQ(zhuyin_settings.layout, mojom::ZhuyinLayout::kStandard);
+  EXPECT_EQ(zhuyin_settings.selection_keys,
+            mojom::ZhuyinSelectionKeys::k1234567890);
+  EXPECT_EQ(zhuyin_settings.page_size, 10);
+}
+
+TEST(CreateSettingsFromPrefsTest, CreateZhuyinSettings) {
+  base::DictionaryValue dict;
+  dict.SetStringPath("zhuyin.zhuyinKeyboardLayout", "IBM");
+  dict.SetStringPath("zhuyin.zhuyinSelectKeys", "asdfghjkl;");
+  dict.SetStringPath("zhuyin.zhuyinPageSize", "8");
+  TestingPrefServiceSimple prefs;
+  RegisterTestingPrefs(prefs, dict);
+
+  const auto settings =
+      CreateSettingsFromPrefs(prefs, kZhuyinEngineId, InputFieldContext{});
+
+  ASSERT_TRUE(settings->is_zhuyin_settings());
+  const auto& zhuyin_settings = *settings->get_zhuyin_settings();
+  EXPECT_EQ(zhuyin_settings.layout, mojom::ZhuyinLayout::kIbm);
+  EXPECT_EQ(zhuyin_settings.selection_keys,
+            mojom::ZhuyinSelectionKeys::kAsdfghjkl);
+  EXPECT_EQ(zhuyin_settings.page_size, 8);
+}
+
 }  // namespace
 }  // namespace input_method
 }  // namespace ash
diff --git a/chrome/browser/ash/input_method/multi_word_suggester.cc b/chrome/browser/ash/input_method/multi_word_suggester.cc
index d8d30ffd1..6704778 100644
--- a/chrome/browser/ash/input_method/multi_word_suggester.cc
+++ b/chrome/browser/ash/input_method/multi_word_suggester.cc
@@ -8,6 +8,7 @@
 
 #include "ash/services/ime/public/cpp/suggestions.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ash/input_method/ui/suggestion_details.h"
 #include "ui/events/keycodes/dom/dom_code.h"
@@ -39,33 +40,18 @@
   return absl::nullopt;
 }
 
-int CalculateNumberMatchingChars(const std::u16string& first,
-                                 const std::u16string& second) {
-  int matching_character_count = 0;
-  for (int i = 0; i < first.size() && i < second.size(); i++) {
-    if (first[i] != second[i])
-      break;
-    matching_character_count++;
+size_t CalculateConfirmedLength(const std::u16string& surrounding_text,
+                                const std::u16string& suggestion_text) {
+  if (surrounding_text.empty() || suggestion_text.empty())
+    return 0;
+
+  for (size_t i = suggestion_text.length(); i >= 1; i--) {
+    if (base::EndsWith(surrounding_text, suggestion_text.substr(0, i))) {
+      return i;
+    }
   }
-  return matching_character_count;
-}
 
-std::u16string ExtractFinalWord(const std::u16string& text) {
-  size_t last_space_index = text.rfind(u' ');
-  size_t offset =
-      last_space_index == std::u16string::npos ? 0 : last_space_index + 1;
-  return text.substr(offset);
-}
-
-int CalculateDismissedAccuracy(const LastKnownSuggestionState& state) {
-  size_t confirmed_text_end_pos = state.start_pos + state.confirmed_length;
-  size_t num_chars_accurately_predicted =
-      confirmed_text_end_pos >= state.predicted_text_start_pos
-          ? confirmed_text_end_pos - state.predicted_text_start_pos
-          : 0;
-  double accuracy = static_cast<double>(num_chars_accurately_predicted) /
-                    state.predicted_text_length;
-  return std::round(accuracy * 100);
+  return 0;
 }
 
 void RecordTimeToAccept(base::TimeDelta delta) {
@@ -78,10 +64,7 @@
                           delta);
 }
 
-void RecordDismissedAccuracy(int percentage) {
-  base::UmaHistogramPercentage(
-      "InputMethod.Assistive.DismissedAccuracy.MultiWord", percentage);
-}
+// TODO(crbug/1146266): Add DismissedAccuracy metric back in.
 
 }  // namespace
 
@@ -93,29 +76,28 @@
 
 void MultiWordSuggester::OnFocus(int context_id) {
   focused_context_id_ = context_id;
-  ResetSuggestionState();
-  ResetTextState();
+  state_.ResetSuggestion();
 }
 
 void MultiWordSuggester::OnBlur() {
   focused_context_id_ = 0;
-  ResetSuggestionState();
-  ResetTextState();
+  state_.ResetSuggestion();
 }
 
 void MultiWordSuggester::OnSurroundingTextChanged(const std::u16string& text,
                                                   size_t cursor_pos,
                                                   size_t anchor_pos) {
-  bool cursor_at_end_of_text =
-      cursor_pos == anchor_pos && cursor_pos == text.length();
-
-  text_state_ = LastKnownTextState{
-      .text = text, .cursor_at_end_of_text = cursor_at_end_of_text};
+  auto surrounding_text = SuggestionState::SurroundingText{
+      .text = text,
+      .cursor_at_end_of_text =
+          (cursor_pos == anchor_pos && cursor_pos == text.length())};
+  state_.UpdateSurroundingText(surrounding_text);
+  DisplaySuggestionIfAvailable();
 }
 
 void MultiWordSuggester::OnExternalSuggestionsUpdated(
     const std::vector<TextSuggestion>& suggestions) {
-  if (suggestion_state_ || !text_state_.cursor_at_end_of_text)
+  if (state_.IsSuggestionShowing() || !state_.IsCursorAtEndOfText())
     return;
 
   absl::optional<TextSuggestion> multi_word_suggestion =
@@ -126,37 +108,16 @@
     return;
   }
 
-  auto suggestion = multi_word_suggestion.value();
-  auto suggestion_text = base::UTF8ToUTF16(suggestion.text);
-  auto final_word = ExtractFinalWord(text_state_.text);
-  int confirmed_length =
-      suggestion.mode == TextSuggestionMode::kCompletion
-          ? CalculateNumberMatchingChars(suggestion_text, final_word)
-          : 0;
-
-  DisplaySuggestion(suggestion_text, confirmed_length);
-  state_.UpdateState(suggestion.mode == TextSuggestionMode::kCompletion
-                         ? SuggestionState::kCompletionSuggestionShown
-                         : SuggestionState::kPredictionSuggestionShown);
-
-  size_t start_pos = text_state_.text.length() >= confirmed_length
-                         ? text_state_.text.length() - confirmed_length
-                         : 0;
-  size_t predicted_text_start_pos = start_pos + confirmed_length;
-  size_t predicted_text_length = suggestion_text.length() - confirmed_length;
-
-  suggestion_state_ = LastKnownSuggestionState{
-      .start_pos = start_pos,
-      .text = suggestion_text,
-      .confirmed_length = static_cast<size_t>(confirmed_length),
-      .predicted_text_start_pos = predicted_text_start_pos,
-      .predicted_text_length = predicted_text_length,
-      .suggestion_mode = suggestion.mode,
-      .time_shown_to_user = base::TimeTicks::Now()};
+  auto suggestion = SuggestionState::Suggestion{
+      .mode = multi_word_suggestion->mode,
+      .text = base::UTF8ToUTF16(multi_word_suggestion->text),
+      .time_first_shown = base::TimeTicks::Now()};
+  state_.UpdateSuggestion(suggestion);
+  DisplaySuggestionIfAvailable();
 }
 
 SuggestionStatus MultiWordSuggester::HandleKeyEvent(const ui::KeyEvent& event) {
-  if (!suggestion_state_)
+  if (!state_.IsSuggestionShowing())
     return SuggestionStatus::kNotHandled;
 
   switch (event.code()) {
@@ -171,30 +132,7 @@
 bool MultiWordSuggester::Suggest(const std::u16string& text,
                                  size_t cursor_pos,
                                  size_t anchor_pos) {
-  if (!suggestion_state_ || cursor_pos != text.length() ||
-      suggestion_state_->start_pos > text.length())
-    return false;
-
-  auto last_suggestion_shown = suggestion_state_.value();
-  auto possibly_confirmed_text =
-      last_suggestion_shown.start_pos < text.length() &&
-              last_suggestion_shown.start_pos >= 0
-          ? text.substr(last_suggestion_shown.start_pos)
-          : base::EmptyString16();
-  bool matches_last_suggestion =
-      base::StartsWith(last_suggestion_shown.text, possibly_confirmed_text,
-                       base::CompareCase::INSENSITIVE_ASCII);
-
-  if (matches_last_suggestion) {
-    int confirmed_length = possibly_confirmed_text.length();
-    DisplaySuggestion(last_suggestion_shown.text, confirmed_length);
-    state_.UpdateState(SuggestionState::kTrackingLastSuggestionShown);
-    suggestion_state_->confirmed_length = confirmed_length;
-    return true;
-  }
-
-  state_.UpdateState(SuggestionState::State::kNoSuggestionShown);
-  return false;
+  return state_.IsSuggestionShowing();
 }
 
 bool MultiWordSuggester::AcceptSuggestion(size_t index) {
@@ -205,13 +143,13 @@
     return false;
   }
 
-  if (suggestion_state_) {
-    RecordTimeToAccept(base::TimeTicks::Now() -
-                       suggestion_state_->time_shown_to_user);
+  auto suggestion = state_.GetSuggestion();
+  if (suggestion) {
+    RecordTimeToAccept(base::TimeTicks::Now() - suggestion->time_first_shown);
   }
 
   state_.UpdateState(SuggestionState::State::kSuggestionAccepted);
-  ResetSuggestionState();
+  state_.ResetSuggestion();
   return true;
 }
 
@@ -223,15 +161,13 @@
     return;
   }
 
-  if (suggestion_state_) {
-    RecordTimeToDismiss(base::TimeTicks::Now() -
-                        suggestion_state_->time_shown_to_user);
-    RecordDismissedAccuracy(
-        CalculateDismissedAccuracy(suggestion_state_.value()));
+  auto suggestion = state_.GetSuggestion();
+  if (suggestion) {
+    RecordTimeToDismiss(base::TimeTicks::Now() - suggestion->time_first_shown);
   }
 
   state_.UpdateState(SuggestionState::State::kSuggestionDismissed);
-  ResetSuggestionState();
+  state_.ResetSuggestion();
 }
 
 AssistiveType MultiWordSuggester::GetProposeActionType() {
@@ -246,13 +182,19 @@
   return {};
 }
 
-void MultiWordSuggester::DisplaySuggestion(const std::u16string& text,
-                                           int confirmed_length) {
+void MultiWordSuggester::DisplaySuggestionIfAvailable() {
+  auto suggestion_to_display = state_.GetSuggestion();
+  if (suggestion_to_display.has_value())
+    DisplaySuggestion(*suggestion_to_display);
+}
+
+void MultiWordSuggester::DisplaySuggestion(
+    const SuggestionState::Suggestion& suggestion) {
   ui::ime::SuggestionDetails details;
-  details.text = text;
+  details.text = suggestion.text;
   details.show_accept_annotation = false;
   details.show_quick_accept_annotation = true;
-  details.confirmed_length = confirmed_length;
+  details.confirmed_length = suggestion.confirmed_length;
   details.show_setting_link = false;
 
   std::string error;
@@ -263,17 +205,6 @@
   }
 }
 
-void MultiWordSuggester::ResetSuggestionState() {
-  suggestion_state_ = absl::nullopt;
-}
-
-void MultiWordSuggester::ResetTextState() {
-  text_state_ = LastKnownTextState{
-      .text = u"",
-      .cursor_at_end_of_text = true,
-  };
-}
-
 void MultiWordSuggester::Announce(const std::u16string& message) {
   if (suggestion_handler_) {
     suggestion_handler_->Announce(message);
@@ -302,13 +233,15 @@
   }
 
   if ((state_ == State::kPredictionSuggestionShown ||
-       state_ == State::kCompletionSuggestionShown) &&
+       state_ == State::kCompletionSuggestionShown ||
+       state_ == State::kTrackingLastSuggestionShown) &&
       state == State::kSuggestionAccepted) {
     suggester_->Announce(kSuggestionAcceptedMessage);
   }
 
   if ((state_ == State::kPredictionSuggestionShown ||
-       state_ == State::kCompletionSuggestionShown) &&
+       state_ == State::kCompletionSuggestionShown ||
+       state_ == State::kTrackingLastSuggestionShown) &&
       state == State::kSuggestionDismissed) {
     suggester_->Announce(kSuggestionDismissedMessage);
   }
@@ -316,6 +249,76 @@
   state_ = state;
 }
 
+void MultiWordSuggester::SuggestionState::UpdateSurroundingText(
+    const MultiWordSuggester::SuggestionState::SurroundingText&
+        surrounding_text) {
+  surrounding_text_ = surrounding_text;
+  ReconcileSuggestionWithText();
+}
+
+void MultiWordSuggester::SuggestionState::UpdateSuggestion(
+    const MultiWordSuggester::SuggestionState::Suggestion& suggestion) {
+  suggestion_ = suggestion;
+  UpdateState(suggestion.mode == TextSuggestionMode::kCompletion
+                  ? State::kCompletionSuggestionShown
+                  : State::kPredictionSuggestionShown);
+  if (suggestion.mode == TextSuggestionMode::kCompletion)
+    ReconcileSuggestionWithText();
+}
+
+void MultiWordSuggester::SuggestionState::ReconcileSuggestionWithText() {
+  if (!suggestion_)
+    return;
+
+  size_t new_confirmed_length =
+      CalculateConfirmedLength(surrounding_text_.text, suggestion_->text);
+
+  // Save the calculated confirmed length on first showing of a completion
+  // suggestion. This will be used later when determining if a suggestion
+  // should be dismissed or not.
+  auto initial_confirmed_length = state_ == State::kCompletionSuggestionShown
+                                      ? new_confirmed_length
+                                      : suggestion_->initial_confirmed_length;
+
+  if (state_ == State::kTrackingLastSuggestionShown &&
+      (new_confirmed_length == 0 ||
+       new_confirmed_length < suggestion_->initial_confirmed_length)) {
+    UpdateState(State::kSuggestionDismissed);
+    ResetSuggestion();
+    return;
+  }
+
+  if (state_ == State::kPredictionSuggestionShown ||
+      state_ == State::kCompletionSuggestionShown) {
+    UpdateState(State::kTrackingLastSuggestionShown);
+  }
+
+  suggestion_ = Suggestion{.text = suggestion_->text,
+                           .confirmed_length = new_confirmed_length,
+                           .initial_confirmed_length = initial_confirmed_length,
+                           .time_first_shown = suggestion_->time_first_shown};
+}
+
+bool MultiWordSuggester::SuggestionState::IsSuggestionShowing() {
+  return (state_ == State::kPredictionSuggestionShown ||
+          state_ == State::kCompletionSuggestionShown ||
+          state_ == State::kTrackingLastSuggestionShown);
+}
+
+bool MultiWordSuggester::SuggestionState::IsCursorAtEndOfText() {
+  return surrounding_text_.cursor_at_end_of_text;
+}
+
+absl::optional<MultiWordSuggester::SuggestionState::Suggestion>
+MultiWordSuggester::SuggestionState::GetSuggestion() {
+  return suggestion_;
+}
+
+void MultiWordSuggester::SuggestionState::ResetSuggestion() {
+  suggestion_ = absl::nullopt;
+  UpdateState(State::kNoSuggestionShown);
+}
+
 AssistiveType MultiWordSuggester::SuggestionState::GetLastSuggestionType() {
   return last_suggestion_type_;
 }
diff --git a/chrome/browser/ash/input_method/multi_word_suggester.h b/chrome/browser/ash/input_method/multi_word_suggester.h
index 313e58d1..ae7b6ca 100644
--- a/chrome/browser/ash/input_method/multi_word_suggester.h
+++ b/chrome/browser/ash/input_method/multi_word_suggester.h
@@ -15,23 +15,6 @@
 namespace ash {
 namespace input_method {
 
-// TODO(crbug/1146266): move these to an internal state class / struct
-struct LastKnownTextState {
-  std::u16string text;
-  bool cursor_at_end_of_text;
-};
-
-// TODO(crbug/1146266): move these to the internal SuggestionState class
-struct LastKnownSuggestionState {
-  size_t start_pos;
-  std::u16string text;
-  size_t confirmed_length;
-  size_t predicted_text_start_pos;
-  size_t predicted_text_length;
-  ime::TextSuggestionMode suggestion_mode;
-  base::TimeTicks time_shown_to_user;
-};
-
 // Integrates multi word suggestions produced by the system with the assistive
 // framework. Handles showing / accepting / dismissing any multi word
 // suggestions generated by the system.
@@ -57,6 +40,7 @@
   bool HasSuggestions() override;
   std::vector<ime::TextSuggestion> GetSuggestions() override;
 
+  // Used to capture any changes to the current input text.
   void OnSurroundingTextChanged(const std::u16string& text,
                                 size_t cursor_pos,
                                 size_t anchor_pos);
@@ -75,6 +59,19 @@
       kSuggestionAccepted,
     };
 
+    struct Suggestion {
+      ime::TextSuggestionMode mode;
+      std::u16string text;
+      size_t confirmed_length;
+      size_t initial_confirmed_length;
+      base::TimeTicks time_first_shown;
+    };
+
+    struct SurroundingText {
+      std::u16string text;
+      bool cursor_at_end_of_text;
+    };
+
     explicit SuggestionState(MultiWordSuggester* suggester);
     ~SuggestionState();
 
@@ -82,22 +79,52 @@
     // any actions required during a transition.
     void UpdateState(const State& state);
 
+    // Captures surrounding text context.
+    void UpdateSurroundingText(const SurroundingText& surrounding_text);
+
+    // Captures new suggestion context.
+    void UpdateSuggestion(const Suggestion& suggestion);
+
+    // Takes the current suggestion and surrounding text state, and ensures the
+    // confirmed length or any other suggestion details are correct.
+    void ReconcileSuggestionWithText();
+
+    // As the name suggests, is there a suggestion currently shown to the user?
+    bool IsSuggestionShowing();
+
+    // Is the user's cursor located at the end of the text they are currently
+    // editing?
+    bool IsCursorAtEndOfText();
+
+    // Returns the current suggestion state if there is any available.
+    absl::optional<Suggestion> GetSuggestion();
+
     // Returns the last suggestion type shown to the user. This suggestion may,
     // or may not, be currently showing to the user.
     AssistiveType GetLastSuggestionType();
 
+    // Resets the current suggestion context, and any other related state.
+    void ResetSuggestion();
+
    private:
     // Not owned by this class
     MultiWordSuggester* suggester_;
 
-    // Current state
+    // The current state of the suggester (eg is a suggestion shown or not).
     State state_ = State::kNoSuggestionShown;
 
+    // Last known surrounding text context captured by the suggester.
+    SurroundingText surrounding_text_;
+
+    // The current suggestion shown to the user by the suggester.
+    absl::optional<Suggestion> suggestion_;
+
     // The last suggestion type shown to the user.
     AssistiveType last_suggestion_type_ = AssistiveType::kGenericAction;
   };
 
-  void DisplaySuggestion(const std::u16string& text, int confirmed_length);
+  void DisplaySuggestionIfAvailable();
+  void DisplaySuggestion(const SuggestionState::Suggestion& suggestion);
   void ResetSuggestionState();
   void ResetTextState();
 
@@ -107,14 +134,6 @@
   // The currently focused input (zero if none are focused)
   int focused_context_id_ = 0;
 
-  // Previous suggestion details
-  //
-  // TODO(crbug/1146266): replace this with the new SuggestionState class
-  absl::optional<LastKnownSuggestionState> suggestion_state_;
-
-  // The last known state of text in the focused text input
-  LastKnownTextState text_state_;
-
   // Not owned by this class
   SuggestionHandlerInterface* suggestion_handler_;
 
diff --git a/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc b/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc
index 43b26302..c62bd43 100644
--- a/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc
+++ b/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc
@@ -41,6 +41,7 @@
                      .text = "my name is John Wayne"}};
 
   suggester.OnFocus(kFocusedContextId);
+  suggester.OnSurroundingTextChanged(u"", 0, 0);
   suggester.OnExternalSuggestionsUpdated(suggestions);
 
   EXPECT_FALSE(suggestion_handler.GetShowingSuggestion());
@@ -53,6 +54,7 @@
   MultiWordSuggester suggester(&suggestion_handler);
 
   suggester.OnFocus(kFocusedContextId);
+  suggester.OnSurroundingTextChanged(u"", 0, 0);
   suggester.OnExternalSuggestionsUpdated({});
 
   EXPECT_FALSE(suggestion_handler.GetShowingSuggestion());
@@ -70,6 +72,7 @@
                      .text = "hello there!"}};
 
   suggester.OnFocus(kFocusedContextId);
+  suggester.OnSurroundingTextChanged(u"", 0, 0);
   suggester.OnExternalSuggestionsUpdated(suggestions);
 
   EXPECT_TRUE(suggestion_handler.GetShowingSuggestion());
@@ -88,6 +91,7 @@
   };
 
   suggester.OnFocus(kFocusedContextId);
+  suggester.OnSurroundingTextChanged(u"", 0, 0);
   suggester.OnExternalSuggestionsUpdated(suggestions);
   SendKeyEvent(&suggester, ui::DomCode::TAB);
 
@@ -108,6 +112,7 @@
   };
 
   suggester.OnFocus(kFocusedContextId);
+  suggester.OnSurroundingTextChanged(u"", 0, 0);
   suggester.OnExternalSuggestionsUpdated(suggestions);
   SendKeyEvent(&suggester, ui::DomCode::ARROW_DOWN);
 
@@ -155,6 +160,67 @@
   EXPECT_EQ(suggestion_handler.GetConfirmedLength(), 3);  // whe
 }
 
+TEST(MultiWordSuggesterTest, CalculatesConfirmedLengthGreedily) {
+  FakeSuggestionHandler suggestion_handler;
+  MultiWordSuggester suggester(&suggestion_handler);
+
+  std::vector<TextSuggestion> suggestions = {
+      TextSuggestion{.mode = TextSuggestionMode::kCompletion,
+                     .type = TextSuggestionType::kMultiWord,
+                     .text = "hohohohoho"},
+  };
+
+  suggester.OnFocus(kFocusedContextId);
+  suggester.OnSurroundingTextChanged(u"merry christmas hohoho",
+                                     /*cursor_pos=*/22,
+                                     /*anchor_pos=*/22);
+  suggester.OnExternalSuggestionsUpdated(suggestions);
+
+  EXPECT_TRUE(suggestion_handler.GetShowingSuggestion());
+  EXPECT_EQ(suggestion_handler.GetSuggestionText(), u"hohohohoho");
+  EXPECT_EQ(suggestion_handler.GetConfirmedLength(), 6);  // hohoho
+}
+
+TEST(MultiWordSuggesterTest, CalculatesConfirmedLengthForPredictions) {
+  FakeSuggestionHandler suggestion_handler;
+  MultiWordSuggester suggester(&suggestion_handler);
+
+  std::vector<TextSuggestion> suggestions = {
+      TextSuggestion{.mode = TextSuggestionMode::kPrediction,
+                     .type = TextSuggestionType::kMultiWord,
+                     .text = "is the next task"},
+  };
+
+  suggester.OnFocus(kFocusedContextId);
+  suggester.OnSurroundingTextChanged(u"this ",
+                                     /*cursor_pos=*/5, /*anchor_pos=*/5);
+  suggester.OnExternalSuggestionsUpdated(suggestions);
+
+  EXPECT_TRUE(suggestion_handler.GetShowingSuggestion());
+  EXPECT_EQ(suggestion_handler.GetSuggestionText(), u"is the next task");
+  EXPECT_EQ(suggestion_handler.GetConfirmedLength(), 0);
+}
+
+TEST(MultiWordSuggesterTest, HandlesNewlinesWhenCalculatingConfirmedLength) {
+  FakeSuggestionHandler suggestion_handler;
+  MultiWordSuggester suggester(&suggestion_handler);
+
+  std::vector<TextSuggestion> suggestions = {
+      TextSuggestion{.mode = TextSuggestionMode::kCompletion,
+                     .type = TextSuggestionType::kMultiWord,
+                     .text = "how are you"},
+  };
+
+  suggester.OnFocus(kFocusedContextId);
+  suggester.OnSurroundingTextChanged(u"\nh",
+                                     /*cursor_pos=*/2, /*anchor_pos=*/2);
+  suggester.OnExternalSuggestionsUpdated(suggestions);
+
+  EXPECT_TRUE(suggestion_handler.GetShowingSuggestion());
+  EXPECT_EQ(suggestion_handler.GetSuggestionText(), u"how are you");
+  EXPECT_EQ(suggestion_handler.GetConfirmedLength(), 1);  // h
+}
+
 TEST(MultiWordSuggesterTest, TracksLastSuggestionOnSurroundingTextChange) {
   FakeSuggestionHandler suggestion_handler;
   MultiWordSuggester suggester(&suggestion_handler);
@@ -261,7 +327,7 @@
   MultiWordSuggester suggester(&suggestion_handler);
 
   std::vector<TextSuggestion> suggestions = {
-      TextSuggestion{.mode = TextSuggestionMode::kCompletion,
+      TextSuggestion{.mode = TextSuggestionMode::kPrediction,
                      .type = TextSuggestionType::kMultiWord,
                      .text = " for the example"},
   };
@@ -269,7 +335,6 @@
   suggester.OnFocus(kFocusedContextId);
   suggester.OnSurroundingTextChanged(u"this is some text", 17, 17);
   suggester.OnExternalSuggestionsUpdated(suggestions);
-
   suggester.OnSurroundingTextChanged(u"this is some text ", 18, 18);
   suggester.Suggest(u"this is some text ", 18, 18);
   suggester.OnSurroundingTextChanged(u"this is some text f", 19, 19);
@@ -282,8 +347,32 @@
   suggester.Suggest(u"this is some text ", 18, 18);
   suggester.OnSurroundingTextChanged(u"this is some text", 17, 17);
 
-  EXPECT_TRUE(suggester.Suggest(u"this is some text", 17, 17));
-  EXPECT_FALSE(suggester.Suggest(u"this is some tex", 16, 16));
+  EXPECT_FALSE(suggester.Suggest(u"this is some text", 17, 17));
+}
+
+TEST(MultiWordSuggesterTest, DoesNotTrackSuggestionPastSuggestionPoint) {
+  FakeSuggestionHandler suggestion_handler;
+  MultiWordSuggester suggester(&suggestion_handler);
+
+  std::vector<TextSuggestion> suggestions = {
+      TextSuggestion{.mode = TextSuggestionMode::kCompletion,
+                     .type = TextSuggestionType::kMultiWord,
+                     .text = " for the example"},
+  };
+
+  suggester.OnFocus(kFocusedContextId);
+  suggester.OnSurroundingTextChanged(u"this is some text fo", 20, 20);
+  suggester.OnExternalSuggestionsUpdated(suggestions);
+  suggester.OnSurroundingTextChanged(u"this is some text for", 21, 21);
+  suggester.Suggest(u"this is some text for", 21, 21);
+  suggester.OnSurroundingTextChanged(u"this is some text fo", 20, 20);
+  bool at_suggestion_point = suggester.Suggest(u"this is some text fo", 20, 20);
+  suggester.OnSurroundingTextChanged(u"this is some text f", 19, 19);
+  bool before_suggestion_point =
+      suggester.Suggest(u"this is some text f", 19, 19);
+
+  EXPECT_TRUE(at_suggestion_point);
+  EXPECT_FALSE(before_suggestion_point);
 }
 
 TEST(MultiWordSuggesterTest, ReturnsGenericActionIfNoSuggestionHasBeenShown) {
@@ -423,92 +512,6 @@
       "InputMethod.Assistive.TimeToDismiss.MultiWord", 1);
 }
 
-TEST(MultiWordSuggesterTest, RecordsDismissedAccuracyMetric) {
-  FakeSuggestionHandler suggestion_handler;
-  MultiWordSuggester suggester(&suggestion_handler);
-
-  std::vector<TextSuggestion> suggestions = {
-      TextSuggestion{.mode = TextSuggestionMode::kPrediction,
-                     .type = TextSuggestionType::kMultiWord,
-                     .text = "are you"},
-  };
-
-  base::HistogramTester histogram_tester;
-  histogram_tester.ExpectUniqueSample(
-      "InputMethod.Assistive.DismissedAccuracy.MultiWord", 43, 0);
-
-  suggester.OnFocus(kFocusedContextId);
-  suggester.OnSurroundingTextChanged(u"how ", 4, 4);
-  suggester.OnExternalSuggestionsUpdated(suggestions);
-  suggester.Suggest(u"how a", 5, 5);
-  suggester.Suggest(u"how ar", 6, 6);
-  suggester.Suggest(u"how are", 7, 7);
-  suggester.Suggest(u"how aren", 8, 8);
-  suggester.DismissSuggestion();
-
-  // Correctly predicted "are" which is three of the seven chars in "are you",
-  // thus accuracy is 3/7 ~= 0.428 which comes to a rounded percentage int val
-  // of 43.
-  histogram_tester.ExpectUniqueSample(
-      "InputMethod.Assistive.DismissedAccuracy.MultiWord", 43, 1);
-}
-
-TEST(MultiWordSuggesterTest, RecordsZeroValuedDismissedAccuracy) {
-  FakeSuggestionHandler suggestion_handler;
-  MultiWordSuggester suggester(&suggestion_handler);
-
-  std::vector<TextSuggestion> suggestions = {
-      TextSuggestion{.mode = TextSuggestionMode::kPrediction,
-                     .type = TextSuggestionType::kMultiWord,
-                     .text = "are you"},
-  };
-
-  base::HistogramTester histogram_tester;
-  histogram_tester.ExpectUniqueSample(
-      "InputMethod.Assistive.DismissedAccuracy.MultiWord", 0, 0);
-
-  suggester.OnFocus(kFocusedContextId);
-  suggester.OnSurroundingTextChanged(u"how ", 4, 4);
-  suggester.OnExternalSuggestionsUpdated(suggestions);
-  suggester.Suggest(u"how d", 5, 5);
-  suggester.DismissSuggestion();
-
-  // Zero predicted chars
-  histogram_tester.ExpectUniqueSample(
-      "InputMethod.Assistive.DismissedAccuracy.MultiWord", 0, 1);
-}
-
-TEST(MultiWordSuggesterTest, RecordsCompletionCandidateDismissedAccuracy) {
-  FakeSuggestionHandler suggestion_handler;
-  MultiWordSuggester suggester(&suggestion_handler);
-
-  std::vector<TextSuggestion> suggestions = {
-      TextSuggestion{.mode = TextSuggestionMode::kCompletion,
-                     .type = TextSuggestionType::kMultiWord,
-                     .text = "aren\'t you"},
-  };
-
-  base::HistogramTester histogram_tester;
-  histogram_tester.ExpectUniqueSample(
-      "InputMethod.Assistive.DismissedAccuracy.MultiWord", 63, 0);
-
-  suggester.OnFocus(kFocusedContextId);
-  suggester.OnSurroundingTextChanged(u"why ar", 6, 6);
-  suggester.OnExternalSuggestionsUpdated(suggestions);
-  suggester.Suggest(u"why are", 7, 7);
-  suggester.Suggest(u"why aren", 8, 8);
-  suggester.Suggest(u"why aren\'", 9, 9);
-  suggester.Suggest(u"why aren\'t", 10, 10);
-  suggester.Suggest(u"why aren\'t ", 11, 11);
-  suggester.Suggest(u"why aren\'t w", 12, 12);
-  suggester.DismissSuggestion();
-
-  // Predicted the cars "en\'t " which is 5 of the 8 chars in "en\'t you",
-  // thus accuracy is 5/8 or approx 62 percent
-  histogram_tester.ExpectUniqueSample(
-      "InputMethod.Assistive.DismissedAccuracy.MultiWord", 63, 1);
-}
-
 TEST(MultiWordSuggesterTest, SurroundingTextChangesDoNotTriggerAnnouncements) {
   FakeSuggestionHandler suggestion_handler;
   MultiWordSuggester suggester(&suggestion_handler);
diff --git a/chrome/browser/ash/locale_change_guard.h b/chrome/browser/ash/locale_change_guard.h
index 5bf78549..fe51b583 100644
--- a/chrome/browser/ash/locale_change_guard.h
+++ b/chrome/browser/ash/locale_change_guard.h
@@ -11,7 +11,6 @@
 #include <string>
 
 #include "ash/public/cpp/locale_update_controller.h"
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/lazy_instance.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/ash/login/auth/cryptohome_authenticator_unittest.cc b/chrome/browser/ash/login/auth/cryptohome_authenticator_unittest.cc
index d88de16..539a79dd 100644
--- a/chrome/browser/ash/login/auth/cryptohome_authenticator_unittest.cc
+++ b/chrome/browser/ash/login/auth/cryptohome_authenticator_unittest.cc
@@ -299,7 +299,8 @@
     SystemSaltGetter::Initialize();
 
     auth_ = new ChromeCryptohomeAuthenticator(&consumer_);
-    state_ = std::make_unique<TestAttemptState>(user_context_);
+    state_ = std::make_unique<TestAttemptState>(
+        std::make_unique<UserContext>(user_context_));
   }
 
   // Tears down the test fixture.
@@ -580,7 +581,8 @@
   // verification.
   content::RunAllTasksUntilIdle();
 
-  state_ = std::make_unique<TestAttemptState>(user_context_);
+  state_ = std::make_unique<TestAttemptState>(
+      std::make_unique<UserContext>(user_context_));
   state_->PresetCryptohomeStatus(cryptohome::MOUNT_ERROR_NONE);
 
   // The owner key util should not have found the owner key, so login should
@@ -630,7 +632,8 @@
   // verification.
   content::RunAllTasksUntilIdle();
 
-  state_ = std::make_unique<TestAttemptState>(user_context_);
+  state_ = std::make_unique<TestAttemptState>(
+      std::make_unique<UserContext>(user_context_));
   state_->PresetCryptohomeStatus(cryptohome::MOUNT_ERROR_NONE);
 
   // The owner key util should find the owner key, so login should succeed.
diff --git a/chrome/browser/ash/login/configuration_based_oobe_browsertest.cc b/chrome/browser/ash/login/configuration_based_oobe_browsertest.cc
index f22a679..6bd84b7 100644
--- a/chrome/browser/ash/login/configuration_based_oobe_browsertest.cc
+++ b/chrome/browser/ash/login/configuration_based_oobe_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/components/attestation/attestation_flow_utils.h"
 #include "ash/constants/ash_switches.h"
 #include "base/test/scoped_chromeos_version_info.h"
 #include "build/build_config.h"
@@ -24,7 +25,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/update_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h"
-#include "chromeos/attestation/attestation_flow_utils.h"
 #include "chromeos/dbus/attestation/fake_attestation_client.h"
 #include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
diff --git a/chrome/browser/ash/login/demo_mode/demo_session.cc b/chrome/browser/ash/login/demo_mode/demo_session.cc
index 7fbdedf4..f063faeb 100644
--- a/chrome/browser/ash/login/demo_mode/demo_session.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_session.cc
@@ -41,6 +41,7 @@
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
+#include "chromeos/system/statistics_provider.h"
 #include "chromeos/tpm/install_attributes.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -346,6 +347,18 @@
          app_id != extensions::kWebStoreAppId;
 }
 
+// Static function to default region from VPD.
+static std::string GetDefaultRegion() {
+  std::string region_code;
+  bool found_region_code =
+      chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
+          chromeos::system::kRegionKey, &region_code);
+  if (found_region_code) {
+    return region_code.substr(0, region_code.find("."));
+  }
+  return "";
+}
+
 // static
 bool DemoSession::ShouldShowWebApp(const std::string& app_id) {
   if (IsDeviceInDemoMode() &&
@@ -360,9 +373,10 @@
 // static
 base::Value DemoSession::GetCountryList() {
   base::Value country_list(base::Value::Type::LIST);
-  const std::string current_country =
-      g_browser_process->local_state()->GetString(prefs::kDemoModeCountry);
+  std::string region(GetDefaultRegion());
   const std::string current_locale = g_browser_process->GetApplicationLocale();
+  bool country_selected = false;
+
   // TODO(b/203105588): Use the new way of base::Value to create the country
   // list.
   for (const std::string country : kSupportedCountries) {
@@ -370,17 +384,27 @@
     dict.SetString("value", country);
     dict.SetString(
         "title", l10n_util::GetDisplayNameForCountry(country, current_locale));
-    dict.SetBoolean("selected", false);
+    if (country == region) {
+      dict.SetBoolean("selected", true);
+      g_browser_process->local_state()->SetString(prefs::kDemoModeCountry,
+                                                  country);
+      country_selected = true;
+    } else {
+      dict.SetBoolean("selected", false);
+    }
     country_list.Append(std::move(dict));
   }
-  base::DictionaryValue countryNotSelectedDict;
-  countryNotSelectedDict.SetString("value", DemoSession::kCountryNotSelectedId);
-  countryNotSelectedDict.SetString(
-      "title",
-      l10n_util::GetStringUTF16(
-          IDS_OOBE_DEMO_SETUP_PREFERENCES_SCREEN_COUNTRY_NOT_SELECTED_TITLE));
-  countryNotSelectedDict.SetBoolean("selected", true);
-  country_list.Append(std::move(countryNotSelectedDict));
+  if (!country_selected) {
+    base::DictionaryValue countryNotSelectedDict;
+    countryNotSelectedDict.SetString("value",
+                                     DemoSession::kCountryNotSelectedId);
+    countryNotSelectedDict.SetString(
+        "title",
+        l10n_util::GetStringUTF16(
+            IDS_OOBE_DEMO_SETUP_PREFERENCES_SCREEN_COUNTRY_NOT_SELECTED_TITLE));
+    countryNotSelectedDict.SetBoolean("selected", true);
+    country_list.Append(std::move(countryNotSelectedDict));
+  }
   return country_list;
 }
 
diff --git a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
index 64555c6..973ed5e 100644
--- a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
@@ -310,7 +310,10 @@
 
 class DemoSetupArcSupportedTest : public DemoSetupTestBase {
  public:
-  DemoSetupArcSupportedTest() = default;
+  DemoSetupArcSupportedTest() {
+    statistics_provider_.SetMachineStatistic(chromeos::system::kRegionKey,
+                                             "us");
+  }
   ~DemoSetupArcSupportedTest() override = default;
 
   // DemoSetupTestBase:
@@ -376,6 +379,50 @@
                          ".shadowRoot.querySelector('option[value=\"",
                          country_code, "\"]').innerHTML"});
   }
+
+ protected:
+  // Verify the country names are displayed correctly. Regression test for
+  // potential country code changes.
+  const base::flat_map<std::string, std::string> kCountryCodeToNameMap = {
+      {"us", "United States"},
+      {"be", "Belgium"},
+      {"ca", "Canada"},
+      {"dk", "Denmark"},
+      {"fi", "Finland"},
+      {"fr", "France"},
+      {"de", "Germany"},
+      {"ie", "Ireland"},
+      {"it", "Italy"},
+      {"jp", "Japan"},
+      {"lu", "Luxembourg"},
+      {"nl", "Netherlands"},
+      {"no", "Norway"},
+      {"es", "Spain"},
+      {"se", "Sweden"},
+      {"gb", "United Kingdom"},
+      {"N/A", "Please select a country"}};
+
+  system::ScopedFakeStatisticsProvider statistics_provider_;
+
+  void SelectFranceAndFinishSetup() {
+    // Select France as the Demo Mode country.
+    test::OobeJS().SelectElementInPath("fr", kDemoPreferencesCountrySelect);
+    test::OobeJS().ExpectEnabledPath(kDemoPreferencesNext);
+    test::OobeJS().ClickOnPath(kDemoPreferencesNext);
+
+    UseOnlineModeOnNetworkScreen();
+
+    AcceptTermsAndExpectDemoSetupProgress();
+
+    // Verify the email corresponds to France.
+    EXPECT_EQ("admin-fr@cros-demo-mode.com",
+              DemoSetupController::GetSubOrganizationEmail());
+
+    OobeScreenWaiter(GetFirstSigninScreen()).Wait();
+
+    EXPECT_TRUE(StartupUtils::IsOobeCompleted());
+    EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
+  }
 };
 
 IN_PROC_BROWSER_TEST_F(DemoSetupArcSupportedTest,
@@ -491,26 +538,6 @@
 
   TriggerDemoModeOnWelcomeScreen();
 
-  // Verify the country names are displayed correctly. Regression test for
-  // potential country code changes.
-  const base::flat_map<std::string, std::string> kCountryCodeToNameMap(
-      {{"N/A", "Please select a country"},
-       {"us", "United States"},
-       {"be", "Belgium"},
-       {"ca", "Canada"},
-       {"dk", "Denmark"},
-       {"fi", "Finland"},
-       {"fr", "France"},
-       {"de", "Germany"},
-       {"ie", "Ireland"},
-       {"it", "Italy"},
-       {"jp", "Japan"},
-       {"lu", "Luxembourg"},
-       {"nl", "Netherlands"},
-       {"no", "Norway"},
-       {"es", "Spain"},
-       {"se", "Sweden"},
-       {"gb", "United Kingdom"}});
   for (const std::string country_code : DemoSession::kSupportedCountries) {
     const auto it = kCountryCodeToNameMap.find(country_code);
     ASSERT_NE(kCountryCodeToNameMap.end(), it);
@@ -519,35 +546,11 @@
     EXPECT_EQ(it->second, test::OobeJS().GetString(query));
   }
 
-  // Check if default value "N/A" and value exists.
-  // Will update to use locale to determine the country.
-  const auto it =
-      kCountryCodeToNameMap.find(DemoSession::kCountryNotSelectedId);
-  ASSERT_NE(kCountryCodeToNameMap.end(), it);
-  const std::string query =
-      GetQueryForCountrySelectOptionFromCountryCode("N/A");
-  EXPECT_EQ(it->second, test::OobeJS().GetString(query));
-  test::OobeJS().ExpectDisabledPath(kDemoPreferencesNext);
-
-  test::OobeJS().ClickOnPath(kDemoPreferencesNext);
-
-  // Select France as the Demo Mode country.
-  test::OobeJS().SelectElementInPath("fr", kDemoPreferencesCountrySelect);
+  // Expect active "OK" button with "us" selected as country.
   test::OobeJS().ExpectEnabledPath(kDemoPreferencesNext);
-  test::OobeJS().ClickOnPath(kDemoPreferencesNext);
+  test::OobeJS().ExpectElementValue("us", kDemoPreferencesCountrySelect);
 
-  UseOnlineModeOnNetworkScreen();
-
-  AcceptTermsAndExpectDemoSetupProgress();
-
-  // Verify the email corresponds to France.
-  EXPECT_EQ("admin-fr@cros-demo-mode.com",
-            DemoSetupController::GetSubOrganizationEmail());
-
-  OobeScreenWaiter(GetFirstSigninScreen()).Wait();
-
-  EXPECT_TRUE(StartupUtils::IsOobeCompleted());
-  EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
+  SelectFranceAndFinishSetup();
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupArcSupportedTest, OnlineSetupFlowErrorDefault) {
@@ -1217,5 +1220,129 @@
   EXPECT_FALSE(StartupUtils::IsDeviceRegistered());
 }
 
+/**
+ * Test case of device variant region code, e.g. ca.fr etc.
+ */
+class DemoSetupVariantCountryCodeRegionTest : public DemoSetupArcSupportedTest {
+ public:
+  ~DemoSetupVariantCountryCodeRegionTest() override = default;
+
+  DemoSetupVariantCountryCodeRegionTest() {
+    statistics_provider_.SetMachineStatistic(chromeos::system::kRegionKey,
+                                             "ca.fr");
+  }
+};
+
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_VariantCountryCodeRegionDefaultCountryIsSet \
+  DISABLED_VariantCountryCodeRegionDefaultCountryIsSet
+#else
+#define MAYBE_VariantCountryCodeRegionDefaultCountryIsSet \
+  VariantCountryCodeRegionDefaultCountryIsSet
+#endif
+IN_PROC_BROWSER_TEST_F(DemoSetupVariantCountryCodeRegionTest,
+                       MAYBE_VariantCountryCodeRegionDefaultCountryIsSet) {
+  // Simulate successful online setup.
+  enrollment_helper_.ExpectEnrollmentMode(
+      policy::EnrollmentConfig::MODE_ATTESTATION);
+  enrollment_helper_.ExpectAttestationEnrollmentSuccess();
+  SimulateNetworkConnected();
+
+  TriggerDemoModeOnWelcomeScreen();
+
+  // Expect active "OK" button when entering the preference screen.
+  test::OobeJS().ExpectEnabledPath(kDemoPreferencesNext);
+  test::OobeJS().ExpectElementValue("ca", kDemoPreferencesCountrySelect);
+  test::OobeJS().ClickOnPath(kDemoPreferencesNext);
+
+  UseOnlineModeOnNetworkScreen();
+
+  AcceptTermsAndExpectDemoSetupProgress();
+
+  // Verify the email corresponds to France.
+  EXPECT_EQ("admin-ca@cros-demo-mode.com",
+            DemoSetupController::GetSubOrganizationEmail());
+
+  OobeScreenWaiter(GetFirstSigninScreen()).Wait();
+
+  EXPECT_TRUE(StartupUtils::IsOobeCompleted());
+  EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
+}
+
+/**
+ * Test case of device virtual set region code, e.g. nordic etc.
+ */
+class DemoSetupVirtualSetRegionCodeTest : public DemoSetupArcSupportedTest {
+ public:
+  ~DemoSetupVirtualSetRegionCodeTest() override = default;
+
+  DemoSetupVirtualSetRegionCodeTest() {
+    statistics_provider_.SetMachineStatistic(chromeos::system::kRegionKey,
+                                             "nordic");
+  }
+};
+
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_VirtualSetCountryCodeRegionPlaceholderIsSet \
+  DISABLED_VirtualSetCountryCodeRegionPlaceholderIsSet
+#else
+#define MAYBE_VirtualSetCountryCodeRegionPlaceholderIsSet \
+  VirtualSetCountryCodeRegionPlaceholderIsSet
+#endif
+IN_PROC_BROWSER_TEST_F(DemoSetupVirtualSetRegionCodeTest,
+                       MAYBE_VirtualSetCountryCodeRegionPlaceholderIsSet) {
+  // Simulate successful online setup.
+  enrollment_helper_.ExpectEnrollmentMode(
+      policy::EnrollmentConfig::MODE_ATTESTATION);
+  enrollment_helper_.ExpectAttestationEnrollmentSuccess();
+  SimulateNetworkConnected();
+
+  TriggerDemoModeOnWelcomeScreen();
+
+  // Expect inactive "OK" button when entering the preference screen.
+  test::OobeJS().ExpectDisabledPath(kDemoPreferencesNext);
+  test::OobeJS().ExpectElementValue("N/A", kDemoPreferencesCountrySelect);
+  test::OobeJS().ClickOnPath(kDemoPreferencesNext);
+
+  SelectFranceAndFinishSetup();
+}
+
+/**
+ * Test case of device with VPD region not set.
+ */
+class DemoSetupRegionCodeNotExistTest : public DemoSetupArcSupportedTest {
+ public:
+  ~DemoSetupRegionCodeNotExistTest() override = default;
+
+  DemoSetupRegionCodeNotExistTest() {
+    statistics_provider_.ClearMachineStatistic(chromeos::system::kRegionKey);
+  }
+};
+
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_RegionCodeNotExistPlaceholderIsSet \
+  DISABLED_RegionCodeNotExistPlaceholderIsSet
+#else
+#define MAYBE_RegionCodeNotExistPlaceholderIsSet \
+  RegionCodeNotExistPlaceholderIsSet
+#endif
+IN_PROC_BROWSER_TEST_F(DemoSetupRegionCodeNotExistTest,
+                       MAYBE_RegionCodeNotExistPlaceholderIsSet) {
+  // Simulate successful online setup.
+  enrollment_helper_.ExpectEnrollmentMode(
+      policy::EnrollmentConfig::MODE_ATTESTATION);
+  enrollment_helper_.ExpectAttestationEnrollmentSuccess();
+  SimulateNetworkConnected();
+
+  TriggerDemoModeOnWelcomeScreen();
+
+  // Expect inactive "OK" button when entering the preference screen.
+  test::OobeJS().ExpectDisabledPath(kDemoPreferencesNext);
+  test::OobeJS().ExpectElementValue("N/A", kDemoPreferencesCountrySelect);
+  test::OobeJS().ClickOnPath(kDemoPreferencesNext);
+
+  SelectFranceAndFinishSetup();
+}
+
 }  // namespace
 }  // namespace ash
diff --git a/chrome/browser/ash/login/enrollment/auto_enrollment_check_screen.h b/chrome/browser/ash/login/enrollment/auto_enrollment_check_screen.h
index 227343c..16868c3 100644
--- a/chrome/browser/ash/login/enrollment/auto_enrollment_check_screen.h
+++ b/chrome/browser/ash/login/enrollment/auto_enrollment_check_screen.h
@@ -8,7 +8,6 @@
 #include <memory>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/login/enrollment/auto_enrollment_check_screen_view.h"
 #include "chrome/browser/ash/login/enrollment/auto_enrollment_controller.h"
diff --git a/chrome/browser/ash/login/enrollment/enrollment_local_policy_server_browsertest.cc b/chrome/browser/ash/login/enrollment/enrollment_local_policy_server_browsertest.cc
index c11ff0d..c831132 100644
--- a/chrome/browser/ash/login/enrollment/enrollment_local_policy_server_browsertest.cc
+++ b/chrome/browser/ash/login/enrollment/enrollment_local_policy_server_browsertest.cc
@@ -4,6 +4,8 @@
 
 #include <string>
 
+#include "ash/components/attestation/attestation_flow_utils.h"
+#include "ash/components/attestation/mock_attestation_flow.h"
 #include "ash/constants/ash_switches.h"
 #include "ash/public/cpp/login_screen_test_api.h"
 #include "base/bind.h"
@@ -45,8 +47,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/attestation/attestation_flow_utils.h"
-#include "chromeos/attestation/mock_attestation_flow.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/system/fake_statistics_provider.h"
@@ -86,7 +86,7 @@
       ->GetTestInterface()
       ->AllowlistSignSimpleChallengeKey(
           /*username=*/"",
-          chromeos::attestation::GetKeyNameForProfile(
+          attestation::GetKeyNameForProfile(
               chromeos::attestation::PROFILE_ENTERPRISE_ENROLLMENT_CERTIFICATE,
               ""));
 }
diff --git a/chrome/browser/ash/login/enrollment/enrollment_screen.h b/chrome/browser/ash/login/enrollment/enrollment_screen.h
index 792fc31..dc6f299a 100644
--- a/chrome/browser/ash/login/enrollment/enrollment_screen.h
+++ b/chrome/browser/ash/login/enrollment/enrollment_screen.h
@@ -10,7 +10,6 @@
 
 #include "base/callback.h"
 #include "base/cancelable_callback.h"
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/authpolicy/authpolicy_helper.h"
diff --git a/chrome/browser/ash/login/enrollment/enterprise_enrollment_helper_impl.cc b/chrome/browser/ash/login/enrollment/enterprise_enrollment_helper_impl.cc
index 53899bc7..3caa0b2 100644
--- a/chrome/browser/ash/login/enrollment/enterprise_enrollment_helper_impl.cc
+++ b/chrome/browser/ash/login/enrollment/enterprise_enrollment_helper_impl.cc
@@ -202,7 +202,7 @@
       connector->GetDeviceCloudPolicyManager();
   // Obtain attestation_flow from the connector because it can be fake
   // attestation flow for testing.
-  chromeos::attestation::AttestationFlow* attestation_flow =
+  attestation::AttestationFlow* attestation_flow =
       connector->GetAttestationFlow();
   auto signing_service =
       std::make_unique<policy::TpmEnrollmentKeySigningService>();
diff --git a/chrome/browser/ash/login/existing_user_controller.h b/chrome/browser/ash/login/existing_user_controller.h
index 932a513..46cb2ad5 100644
--- a/chrome/browser/ash/login/existing_user_controller.h
+++ b/chrome/browser/ash/login/existing_user_controller.h
@@ -11,7 +11,6 @@
 #include <string>
 
 #include "base/callback_forward.h"
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
diff --git a/chrome/browser/ash/login/helper.h b/chrome/browser/ash/login/helper.h
index b36aeec8..6a1850a 100644
--- a/chrome/browser/ash/login/helper.h
+++ b/chrome/browser/ash/login/helper.h
@@ -9,7 +9,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "chromeos/network/network_handler_callbacks.h"
 #include "third_party/skia/include/core/SkColor.h"
diff --git a/chrome/browser/ash/login/lock/screen_locker.cc b/chrome/browser/ash/login/lock/screen_locker.cc
index 28c18f4..142ce34 100644
--- a/chrome/browser/ash/login/lock/screen_locker.cc
+++ b/chrome/browser/ash/login/lock/screen_locker.cc
@@ -191,7 +191,7 @@
       fingerprint_observer_receiver_.BindNewPipeAndPassRemote());
 
   GetLoginScreenCertProviderService()->pin_dialog_manager()->AddPinDialogHost(
-      &security_token_pin_dialog_host_impl_);
+      &security_token_pin_dialog_host_login_impl_);
   user_manager::UserManager::Get()->AddSessionStateObserver(this);
 
   if (g_clock_for_testing_ && g_tick_clock_for_testing_) {
@@ -721,7 +721,7 @@
 
   GetLoginScreenCertProviderService()
       ->pin_dialog_manager()
-      ->RemovePinDialogHost(&security_token_pin_dialog_host_impl_);
+      ->RemovePinDialogHost(&security_token_pin_dialog_host_login_impl_);
 
   if (authenticator_)
     authenticator_->SetConsumer(nullptr);
diff --git a/chrome/browser/ash/login/lock/screen_locker.h b/chrome/browser/ash/login/lock/screen_locker.h
index 497c9a6..6ff1853 100644
--- a/chrome/browser/ash/login/lock/screen_locker.h
+++ b/chrome/browser/ash/login/lock/screen_locker.h
@@ -19,7 +19,7 @@
 #include "base/timer/wall_clock_timer.h"
 #include "chrome/browser/ash/login/challenge_response_auth_keys_loader.h"
 #include "chrome/browser/ash/login/help_app_launcher.h"
-#include "chrome/browser/ash/login/security_token_pin_dialog_host_impl.h"
+#include "chrome/browser/ash/login/security_token_pin_dialog_host_login_impl.h"
 #include "chrome/browser/ash/login/ui/login_display.h"
 #include "chromeos/login/auth/auth_status_consumer.h"
 // TODO(https://crbug.com/1164001): move to forward declaration.
@@ -328,7 +328,8 @@
 
   ChallengeResponseAuthKeysLoader challenge_response_auth_keys_loader_;
 
-  SecurityTokenPinDialogHostImpl security_token_pin_dialog_host_impl_;
+  SecurityTokenPinDialogHostLoginImpl
+      security_token_pin_dialog_host_login_impl_;
 
   std::unique_ptr<PrefChangeRegistrar> fingerprint_pref_change_registrar_;
 
diff --git a/chrome/browser/ash/login/oobe_interactive_ui_test.cc b/chrome/browser/ash/login/oobe_interactive_ui_test.cc
index 0dcee73b..7160e26 100644
--- a/chrome/browser/ash/login/oobe_interactive_ui_test.cc
+++ b/chrome/browser/ash/login/oobe_interactive_ui_test.cc
@@ -6,6 +6,7 @@
 
 #include "ash/components/arc/test/arc_util_test_support.h"
 #include "ash/components/arc/test/fake_arc_session.h"
+#include "ash/components/attestation/attestation_flow_utils.h"
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
 #include "ash/constants/ash_switches.h"
@@ -56,7 +57,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h"
 #include "chromeos/assistant/buildflags.h"
-#include "chromeos/attestation/attestation_flow_utils.h"
 #include "chromeos/dbus/update_engine/update_engine_client.h"
 #include "chromeos/system/fake_statistics_provider.h"
 #include "components/arc/session/arc_service_manager.h"
@@ -783,7 +783,7 @@
     chromeos::AttestationClient::Get()
         ->GetTestInterface()
         ->AllowlistSignSimpleChallengeKey(
-            /*username=*/"", chromeos::attestation::GetKeyNameForProfile(
+            /*username=*/"", attestation::GetKeyNameForProfile(
                                  chromeos::attestation::
                                      PROFILE_ENTERPRISE_ENROLLMENT_CERTIFICATE,
                                  ""));
diff --git a/chrome/browser/ash/login/saml/in_session_password_sync_manager_factory.h b/chrome/browser/ash/login/saml/in_session_password_sync_manager_factory.h
index c52f127b6..e49b3f00 100644
--- a/chrome/browser/ash/login/saml/in_session_password_sync_manager_factory.h
+++ b/chrome/browser/ash/login/saml/in_session_password_sync_manager_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_LOGIN_SAML_IN_SESSION_PASSWORD_SYNC_MANAGER_FACTORY_H_
 #define CHROME_BROWSER_ASH_LOGIN_SAML_IN_SESSION_PASSWORD_SYNC_MANAGER_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.cc b/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.cc
index 67120c5..cb1f7d39e 100644
--- a/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.cc
+++ b/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.cc
@@ -13,6 +13,8 @@
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_dialog.h"
+#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h"
 #include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h"
 #include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h"
 #include "chrome/browser/ui/webui/signin/signin_utils.h"
@@ -23,11 +25,16 @@
 namespace ash {
 
 namespace {
+// Main dialog
 const test::UIPath kSamlContainer = {"main-element", "body"};
 const test::UIPath kMainVerifyButton = {"main-element",
                                         "nextButtonVerifyScreen"};
 const test::UIPath kMainScreen = {"main-element", "verifyAccountScreen"};
 const char kSigninFrame[] = "signin-frame";
+
+// Network dialog
+const test::UIPath kNetworkDialog = {"network-ui", "dialog"};
+const test::UIPath kNetworkCancelButton = {"network-ui", "cancelButton"};
 }  // namespace
 
 LockScreenReauthDialogTestHelper::LockScreenReauthDialogTestHelper() = default;
@@ -151,6 +158,11 @@
   return test::JSChecker(DialogWebContents());
 }
 
+test::JSChecker LockScreenReauthDialogTestHelper::NetworkJS() {
+  CHECK(network_dialog_);
+  return test::JSChecker(network_dialog_->GetWebUIForTest()->GetWebContents());
+}
+
 test::JSChecker LockScreenReauthDialogTestHelper::SigninFrameJS() {
   content::RenderFrameHost* frame =
       signin::GetAuthFrame(DialogWebContents(), kSigninFrame);
@@ -174,4 +186,55 @@
   }
 }
 
+void LockScreenReauthDialogTestHelper::WaitForNetworkDialogToLoad() {
+  CHECK(reauth_dialog_);
+  base::RunLoop run_loop;
+  if (!reauth_dialog_->IsNetworkDialogLoadedForTesting(
+          run_loop.QuitClosure())) {
+    run_loop.Run();
+  }
+}
+
+void LockScreenReauthDialogTestHelper::WaitForNetworkDialogAndSetHandlers() {
+  WaitForNetworkDialogToLoad();
+
+  network_dialog_ = reauth_dialog_->get_network_dialog_for_testing();
+  if (!network_dialog_ || !network_dialog_->GetWebUIForTest()) {
+    ADD_FAILURE() << "Could not retrieve LockScreenNetworkDialog";
+  }
+  network_webui_controller_ = static_cast<chromeos::LockScreenNetworkUI*>(
+      network_dialog_->GetWebUIForTest()->GetController());
+  if (!network_webui_controller_) {
+    ADD_FAILURE() << "Could not retrieve LockScreenNetworkUI";
+  }
+  network_handler_ = network_webui_controller_->GetMainHandlerForTests();
+  if (!network_handler_) {
+    ADD_FAILURE() << "Could not retrieve LockScreenNetworkHandler";
+  }
+}
+
+// Makes the main dialog show its inner 'network' dialog and fetches
+// pointers to the Dialog, WebUI Controller and Message Handler.
+void LockScreenReauthDialogTestHelper::ShowNetworkScreenAndWait() {
+  reauth_dialog_->ShowLockScreenNetworkDialog();
+  WaitForNetworkDialogAndSetHandlers();
+}
+
+void LockScreenReauthDialogTestHelper::CloseNetworkScreen() {
+  reauth_dialog_->DismissLockScreenNetworkDialog();
+}
+
+void LockScreenReauthDialogTestHelper::ExpectNetworkDialogVisible() {
+  NetworkJS().CreateVisibilityWaiter(true, kNetworkDialog)->Wait();
+  NetworkJS().ExpectVisiblePath(kNetworkDialog);
+}
+
+void LockScreenReauthDialogTestHelper::ExpectNetworkDialogHidden() {
+  EXPECT_FALSE(reauth_dialog_->is_network_dialog_visible_for_testing());
+}
+
+void LockScreenReauthDialogTestHelper::ClickCloseNetworkButton() {
+  NetworkJS().TapOnPath(kNetworkCancelButton);
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.h b/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.h
index 9fcfb67..5b8778dd 100644
--- a/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.h
+++ b/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.h
@@ -12,6 +12,9 @@
 class LockScreenStartReauthDialog;
 class LockScreenStartReauthUI;
 class LockScreenReauthHandler;
+class LockScreenNetworkDialog;
+class LockScreenNetworkUI;
+class NetworkConfigMessageHandler;
 }  // namespace chromeos
 
 namespace content {
@@ -62,6 +65,14 @@
   void ExpectVerifyAccountScreenHidden();
   void ExpectSamlScreenVisible();
 
+  void ShowNetworkScreenAndWait();
+  void WaitForNetworkDialogAndSetHandlers();
+  void CloseNetworkScreen();
+
+  void ExpectNetworkDialogVisible();
+  void ExpectNetworkDialogHidden();
+  void ClickCloseNetworkButton();
+
   // Wait for the SAML IdP page to load.
   // Precondition: The SAML container is visible.
   void WaitForIdpPageLoad();
@@ -71,6 +82,9 @@
   // Returns a JSChecker for the WebContents of the dialog's WebUI.
   test::JSChecker DialogJS();
 
+  // Returns a JSChecker for the WebContents of the network dialog's WebUI.
+  test::JSChecker NetworkJS();
+
   // Returns a JSChecker for the WebContents of the signin frame webview.
   // Precondition: The SAML container is visible.
   test::JSChecker SigninFrameJS();
@@ -84,10 +98,20 @@
   void WaitForAuthenticatorToLoad();
   void WaitForReauthDialogToLoad();
 
+  // Waits for the network dialog to load.
+  // Precondition: Main dialog must exist, since it owns the network dialog.
+  void WaitForNetworkDialogToLoad();
+
+  // Main Dialog
   InSessionPasswordSyncManager* password_sync_manager_ = nullptr;
   chromeos::LockScreenStartReauthDialog* reauth_dialog_ = nullptr;
   chromeos::LockScreenStartReauthUI* reauth_webui_controller_ = nullptr;
   chromeos::LockScreenReauthHandler* main_handler_ = nullptr;
+
+  // Network dialog which is owned by the main dialog.
+  chromeos::LockScreenNetworkDialog* network_dialog_ = nullptr;
+  chromeos::LockScreenNetworkUI* network_webui_controller_ = nullptr;
+  chromeos::NetworkConfigMessageHandler* network_handler_ = nullptr;
 };
 
 }  // namespace ash
diff --git a/chrome/browser/ash/login/saml/saml_browsertest.cc b/chrome/browser/ash/login/saml/saml_browsertest.cc
index 8f8c7575..6148980 100644
--- a/chrome/browser/ash/login/saml/saml_browsertest.cc
+++ b/chrome/browser/ash/login/saml/saml_browsertest.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/components/attestation/mock_attestation_flow.h"
 #include "ash/components/settings/cros_settings_names.h"
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_switches.h"
@@ -64,7 +65,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "chromeos/attestation/mock_attestation_flow.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
 #include "chromeos/dbus/attestation/fake_attestation_client.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
@@ -1545,7 +1545,7 @@
   StubCrosSettingsProvider* settings_provider_ = nullptr;
 
   attestation::MockMachineCertificateUploader mock_cert_uploader_;
-  NiceMock<chromeos::attestation::MockAttestationFlow> mock_attestation_flow_;
+  NiceMock<attestation::MockAttestationFlow> mock_attestation_flow_;
   chromeos::ScopedStubInstallAttributes stub_install_attributes_;
 };
 
diff --git a/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc b/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc
index c4520573..d724dcfb 100644
--- a/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc
+++ b/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/ash/login/users/test_users.h"
 #include "chrome/test/base/mixin_based_in_process_browser_test.h"
 #include "chromeos/dbus/shill/fake_shill_manager_client.h"
+#include "chromeos/network/network_state_test_helper.h"
 #include "components/account_id/account_id.h"
 #include "components/network_session_configurator/common/network_switches.h"
 #include "content/public/test/browser_test.h"
@@ -29,6 +30,22 @@
 constexpr char kTestAuthSIDCookie1[] = "fake-auth-SID-cookie-1";
 constexpr char kTestAuthLSIDCookie1[] = "fake-auth-LSID-cookie-1";
 constexpr char kTestRefreshToken[] = "fake-refresh-token";
+constexpr char kWifiServicePath[] = "/service/wifi1";
+
+void ErrorCallbackFunction(base::OnceClosure run_loop_quit_closure,
+                           const std::string& error_name,
+                           const std::string& error_message) {
+  std::move(run_loop_quit_closure).Run();
+  FAIL() << "Shill Error: " << error_name << " : " << error_message;
+}
+
+void SetConnected(const std::string& service_path) {
+  base::RunLoop run_loop;
+  ShillServiceClient::Get()->Connect(
+      dbus::ObjectPath(service_path), run_loop.QuitWhenIdleClosure(),
+      base::BindOnce(&ErrorCallbackFunction, run_loop.QuitClosure()));
+  run_loop.Run();
+}
 
 }  // namespace
 
@@ -71,9 +88,19 @@
     fake_gaia_mixin()->SetupFakeGaiaForLogin(FakeGaiaMixin::kEnterpriseUser1,
                                              "", kTestRefreshToken);
 
+    // Set up fake networks.
+    network_state_test_helper_ =
+        std::make_unique<chromeos::NetworkStateTestHelper>(
+            true /*use_default_devices_and_services*/);
+    network_state_test_helper_->manager_test()->SetupDefaultEnvironment();
+    // Fake networks have been set up. Connect to WiFi network.
+    SetConnected(kWifiServicePath);
+
     MixinBasedInProcessBrowserTest::SetUpOnMainThread();
   }
 
+  void TearDownOnMainThread() override { network_state_test_helper_.reset(); }
+
   void Login() { logged_in_user_mixin_.LogInUser(); }
 
   FakeSamlIdpMixin* fake_saml_idp() { return &fake_saml_idp_; }
@@ -84,6 +111,7 @@
 
  protected:
   base::test::ScopedFeatureList feature_list_;
+  std::unique_ptr<NetworkStateTestHelper> network_state_test_helper_;
 
  private:
   LoggedInUserMixin logged_in_user_mixin_{
@@ -107,23 +135,23 @@
   // Lock the screen and trigger the lock screen SAML reauth dialog.
   ScreenLockerTester().Lock();
 
-  absl::optional<LockScreenReauthDialogTestHelper> lock_screen_reauth_dialog =
+  absl::optional<LockScreenReauthDialogTestHelper> reauth_dialog_helper =
       LockScreenReauthDialogTestHelper::ShowDialogAndWait();
-  ASSERT_TRUE(lock_screen_reauth_dialog);
-  lock_screen_reauth_dialog->ForceSamlRedirect();
+  ASSERT_TRUE(reauth_dialog_helper);
+  reauth_dialog_helper->ForceSamlRedirect();
 
   // Expect the 'Verify Account' screen (the first screen the dialog shows) to
   // be visible and proceed to the SAML page.
-  lock_screen_reauth_dialog->WaitForVerifyAccountScreen();
-  lock_screen_reauth_dialog->ClickVerifyButton();
+  reauth_dialog_helper->WaitForVerifyAccountScreen();
+  reauth_dialog_helper->ClickVerifyButton();
 
-  lock_screen_reauth_dialog->WaitForSamlScreen();
-  lock_screen_reauth_dialog->ExpectVerifyAccountScreenHidden();
+  reauth_dialog_helper->WaitForSamlScreen();
+  reauth_dialog_helper->ExpectVerifyAccountScreenHidden();
 
-  lock_screen_reauth_dialog->WaitForIdpPageLoad();
+  reauth_dialog_helper->WaitForIdpPageLoad();
 
   // Fill-in the SAML IdP form and submit.
-  test::JSChecker signin_frame_js = lock_screen_reauth_dialog->SigninFrameJS();
+  test::JSChecker signin_frame_js = reauth_dialog_helper->SigninFrameJS();
   signin_frame_js.CreateVisibilityWaiter(true, {"Email"})->Wait();
   signin_frame_js.TypeIntoPath(FakeGaiaMixin::kEnterpriseUser1, {"Email"});
   signin_frame_js.TypeIntoPath("actual_password", {"Password"});
@@ -132,4 +160,84 @@
   ScreenLockerTester().WaitForUnlock();
 }
 
+IN_PROC_BROWSER_TEST_F(LockscreenWebUiTest, ShowNetworkDialog) {
+  Login();
+
+  // Lock the screen and trigger the lock screen SAML reauth dialog.
+  ScreenLockerTester().Lock();
+
+  absl::optional<LockScreenReauthDialogTestHelper> reauth_dialog_helper =
+      LockScreenReauthDialogTestHelper::ShowDialogAndWait();
+  ASSERT_TRUE(reauth_dialog_helper);
+
+  reauth_dialog_helper->ShowNetworkScreenAndWait();
+
+  // Ensures that the web element 'cr-dialog' is really visible.
+  reauth_dialog_helper->ExpectNetworkDialogVisible();
+
+  // Click on the actual button to close the dialog.
+  reauth_dialog_helper->ClickCloseNetworkButton();
+}
+
+IN_PROC_BROWSER_TEST_F(LockscreenWebUiTest, TriggerDialogOnNetworkOff) {
+  Login();
+
+  // Lock the screen and trigger the lock screen SAML reauth dialog.
+  ScreenLockerTester().Lock();
+
+  absl::optional<LockScreenReauthDialogTestHelper> reauth_dialog_helper =
+      LockScreenReauthDialogTestHelper::ShowDialogAndWait();
+  ASSERT_TRUE(reauth_dialog_helper);
+
+  // Disconnect from all networks in order to trigger the network screen.
+  network_state_test_helper_->service_test()->ClearServices();
+  base::RunLoop().RunUntilIdle();
+  network_state_test_helper_->service_test()->AddService(
+      /*service_path=*/kWifiServicePath, /*guid=*/kWifiServicePath,
+      /*name=*/kWifiServicePath, /*type=*/shill::kTypeWifi,
+      /*state=*/shill::kStateOffline, /*visible=*/true);
+
+  reauth_dialog_helper->WaitForNetworkDialogAndSetHandlers();
+
+  // Ensures that the web element 'cr-dialog' is visible.
+  reauth_dialog_helper->ExpectNetworkDialogVisible();
+
+  // Click on the actual button to close the dialog.
+  reauth_dialog_helper->ClickCloseNetworkButton();
+}
+
+IN_PROC_BROWSER_TEST_F(LockscreenWebUiTest, TriggerAndHideNetworkDialog) {
+  Login();
+
+  // Lock the screen and trigger the lock screen SAML reauth dialog.
+  ScreenLockerTester().Lock();
+
+  absl::optional<LockScreenReauthDialogTestHelper> reauth_dialog_helper =
+      LockScreenReauthDialogTestHelper::ShowDialogAndWait();
+  ASSERT_TRUE(reauth_dialog_helper);
+
+  // Disconnect from all networks in order to trigger the network screen.
+  network_state_test_helper_->service_test()->ClearServices();
+  base::RunLoop().RunUntilIdle();
+  network_state_test_helper_->service_test()->AddService(
+      /*service_path=*/kWifiServicePath, /*guid=*/kWifiServicePath,
+      /*name=*/kWifiServicePath, /*type=*/shill::kTypeWifi,
+      /*state=*/shill::kStateOffline, /*visible=*/true);
+
+  reauth_dialog_helper->WaitForNetworkDialogAndSetHandlers();
+
+  // Ensures that the web element 'cr-dialog' is visible.
+  reauth_dialog_helper->ExpectNetworkDialogVisible();
+
+  // Reconnect network.
+  network_state_test_helper_->service_test()->AddService(
+      /*service_path=*/kWifiServicePath, /*guid=*/kWifiServicePath,
+      /*name=*/kWifiServicePath, /*type=*/shill::kTypeWifi,
+      /*state=*/shill::kStateOnline, /*visible=*/true);
+  base::RunLoop().RunUntilIdle();
+
+  // Ensures that the re-auth dialog is visible.
+  reauth_dialog_helper->ExpectNetworkDialogHidden();
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ash/login/screens/chrome_user_selection_screen.h b/chrome/browser/ash/login/screens/chrome_user_selection_screen.h
index e0af2ed..9938788 100644
--- a/chrome/browser/ash/login/screens/chrome_user_selection_screen.h
+++ b/chrome/browser/ash/login/screens/chrome_user_selection_screen.h
@@ -9,7 +9,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/login/screens/user_selection_screen.h"
 #include "chrome/browser/ash/policy/core/device_local_account_policy_service.h"
diff --git a/chrome/browser/ash/login/screens/error_screen.h b/chrome/browser/ash/login/screens/error_screen.h
index ee84369c..696a9220 100644
--- a/chrome/browser/ash/login/screens/error_screen.h
+++ b/chrome/browser/ash/login/screens/error_screen.h
@@ -8,7 +8,6 @@
 #include <memory>
 
 #include "base/callback_list.h"
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/login/screens/base_screen.h"
 #include "chrome/browser/ash/login/screens/network_error.h"
diff --git a/chrome/browser/ash/login/screens/eula_screen.h b/chrome/browser/ash/login/screens/eula_screen.h
index 8e124116..82c1b841 100644
--- a/chrome/browser/ash/login/screens/eula_screen.h
+++ b/chrome/browser/ash/login/screens/eula_screen.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/login/screens/base_screen.h"
 // TODO(https://crbug.com/1164001): move to forward declaration.
 #include "chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h"
diff --git a/chrome/browser/ash/login/screens/hid_detection_screen.h b/chrome/browser/ash/login/screens/hid_detection_screen.h
index be3822f..d519e81 100644
--- a/chrome/browser/ash/login/screens/hid_detection_screen.h
+++ b/chrome/browser/ash/login/screens/hid_detection_screen.h
@@ -13,7 +13,6 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/login/demo_mode/demo_mode_detector.h"
 #include "chrome/browser/ash/login/screens/base_screen.h"
diff --git a/chrome/browser/ash/login/screens/kiosk_autolaunch_screen.h b/chrome/browser/ash/login/screens/kiosk_autolaunch_screen.h
index 139a3a5..e23e63a 100644
--- a/chrome/browser/ash/login/screens/kiosk_autolaunch_screen.h
+++ b/chrome/browser/ash/login/screens/kiosk_autolaunch_screen.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/login/screens/base_screen.h"
 // TODO(https://crbug.com/1164001): move to forward declaration.
 #include "chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h"
diff --git a/chrome/browser/ash/login/screens/kiosk_enable_screen.h b/chrome/browser/ash/login/screens/kiosk_enable_screen.h
index 067652e..071bd825 100644
--- a/chrome/browser/ash/login/screens/kiosk_enable_screen.h
+++ b/chrome/browser/ash/login/screens/kiosk_enable_screen.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/ash/login/screens/base_screen.h"
 // TODO(https://crbug.com/1164001): move to forward declaration.
diff --git a/chrome/browser/ash/login/screens/reset_screen.h b/chrome/browser/ash/login/screens/reset_screen.h
index 9bd6845..4236390 100644
--- a/chrome/browser/ash/login/screens/reset_screen.h
+++ b/chrome/browser/ash/login/screens/reset_screen.h
@@ -10,7 +10,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/login/help_app_launcher.h"
diff --git a/chrome/browser/ash/login/screens/terms_of_service_screen.h b/chrome/browser/ash/login/screens/terms_of_service_screen.h
index 2bc4abf..2c3d9ef6 100644
--- a/chrome/browser/ash/login/screens/terms_of_service_screen.h
+++ b/chrome/browser/ash/login/screens/terms_of_service_screen.h
@@ -8,7 +8,6 @@
 #include <memory>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
diff --git a/chrome/browser/ash/login/screens/update_required_screen.h b/chrome/browser/ash/login/screens/update_required_screen.h
index bf95231..8d92040 100644
--- a/chrome/browser/ash/login/screens/update_required_screen.h
+++ b/chrome/browser/ash/login/screens/update_required_screen.h
@@ -10,7 +10,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 // TODO(https://crbug.com/1164001): move to forward declaration.
 #include "chrome/browser/ash/login/error_screens_histogram_helper.h"
diff --git a/chrome/browser/ash/login/screens/user_selection_screen.h b/chrome/browser/ash/login/screens/user_selection_screen.h
index 63be7c9..801e455 100644
--- a/chrome/browser/ash/login/screens/user_selection_screen.h
+++ b/chrome/browser/ash/login/screens/user_selection_screen.h
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "ash/public/cpp/session/user_info.h"
-#include "base/compiler_specific.h"
 #include "base/scoped_observation.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
diff --git a/chrome/browser/ash/login/screens/wrong_hwid_screen.h b/chrome/browser/ash/login/screens/wrong_hwid_screen.h
index f3750ae..a41de86 100644
--- a/chrome/browser/ash/login/screens/wrong_hwid_screen.h
+++ b/chrome/browser/ash/login/screens/wrong_hwid_screen.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/login/screens/base_screen.h"
 // TODO(https://crbug.com/1164001): move to forward declaration.
 #include "chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h"
diff --git a/chrome/browser/ash/login/security_token_pin_dialog_host_impl.cc b/chrome/browser/ash/login/security_token_pin_dialog_host_login_impl.cc
similarity index 78%
rename from chrome/browser/ash/login/security_token_pin_dialog_host_impl.cc
rename to chrome/browser/ash/login/security_token_pin_dialog_host_login_impl.cc
index 654a405..1931da7 100644
--- a/chrome/browser/ash/login/security_token_pin_dialog_host_impl.cc
+++ b/chrome/browser/ash/login/security_token_pin_dialog_host_login_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ash/login/security_token_pin_dialog_host_impl.h"
+#include "chrome/browser/ash/login/security_token_pin_dialog_host_login_impl.h"
 
 #include <utility>
 
@@ -14,11 +14,13 @@
 
 namespace ash {
 
-SecurityTokenPinDialogHostImpl::SecurityTokenPinDialogHostImpl() = default;
+SecurityTokenPinDialogHostLoginImpl::SecurityTokenPinDialogHostLoginImpl() =
+    default;
 
-SecurityTokenPinDialogHostImpl::~SecurityTokenPinDialogHostImpl() = default;
+SecurityTokenPinDialogHostLoginImpl::~SecurityTokenPinDialogHostLoginImpl() =
+    default;
 
-void SecurityTokenPinDialogHostImpl::ShowSecurityTokenPinDialog(
+void SecurityTokenPinDialogHostLoginImpl::ShowSecurityTokenPinDialog(
     const std::string& /*caller_extension_name*/,
     security_token_pin::CodeType code_type,
     bool enable_user_input,
@@ -52,23 +54,23 @@
   request.error_label = error_label;
   request.attempts_left = attempts_left;
   request.pin_entered_callback =
-      base::BindOnce(&SecurityTokenPinDialogHostImpl::OnUserInputReceived,
+      base::BindOnce(&SecurityTokenPinDialogHostLoginImpl::OnUserInputReceived,
                      weak_ptr_factory_.GetWeakPtr());
   request.pin_ui_closed_callback =
-      base::BindOnce(&SecurityTokenPinDialogHostImpl::OnClosedByUser,
+      base::BindOnce(&SecurityTokenPinDialogHostLoginImpl::OnClosedByUser,
                      weak_ptr_factory_.GetWeakPtr());
 
   LoginScreen::Get()->RequestSecurityTokenPin(std::move(request));
 }
 
-void SecurityTokenPinDialogHostImpl::CloseSecurityTokenPinDialog() {
+void SecurityTokenPinDialogHostLoginImpl::CloseSecurityTokenPinDialog() {
   DCHECK(is_request_running());
 
   Reset();
   LoginScreen::Get()->ClearSecurityTokenPinRequest();
 }
 
-void SecurityTokenPinDialogHostImpl::OnUserInputReceived(
+void SecurityTokenPinDialogHostLoginImpl::OnUserInputReceived(
     const std::string& user_input) {
   DCHECK(is_request_running());
   DCHECK(!user_input.empty());
@@ -76,7 +78,7 @@
   std::move(pin_entered_callback_).Run(user_input);
 }
 
-void SecurityTokenPinDialogHostImpl::OnClosedByUser() {
+void SecurityTokenPinDialogHostLoginImpl::OnClosedByUser() {
   DCHECK(is_request_running());
 
   auto closed_callback = std::move(pin_dialog_closed_callback_);
@@ -84,7 +86,7 @@
   std::move(closed_callback).Run();
 }
 
-void SecurityTokenPinDialogHostImpl::Reset() {
+void SecurityTokenPinDialogHostLoginImpl::Reset() {
   pin_entered_callback_.Reset();
   pin_dialog_closed_callback_.Reset();
   weak_ptr_factory_.InvalidateWeakPtrs();
diff --git a/chrome/browser/ash/login/security_token_pin_dialog_host_impl.h b/chrome/browser/ash/login/security_token_pin_dialog_host_login_impl.h
similarity index 79%
rename from chrome/browser/ash/login/security_token_pin_dialog_host_impl.h
rename to chrome/browser/ash/login/security_token_pin_dialog_host_login_impl.h
index a9c6264..db576f5 100644
--- a/chrome/browser/ash/login/security_token_pin_dialog_host_impl.h
+++ b/chrome/browser/ash/login/security_token_pin_dialog_host_login_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ASH_LOGIN_SECURITY_TOKEN_PIN_DIALOG_HOST_IMPL_H_
-#define CHROME_BROWSER_ASH_LOGIN_SECURITY_TOKEN_PIN_DIALOG_HOST_IMPL_H_
+#ifndef CHROME_BROWSER_ASH_LOGIN_SECURITY_TOKEN_PIN_DIALOG_HOST_LOGIN_IMPL_H_
+#define CHROME_BROWSER_ASH_LOGIN_SECURITY_TOKEN_PIN_DIALOG_HOST_LOGIN_IMPL_H_
 
 #include <string>
 
@@ -15,14 +15,15 @@
 
 // The Ash Login/Lock screen implementation of the security token PIN dialog
 // host. It displays the PIN request embedded into the user pod.
-class SecurityTokenPinDialogHostImpl final : public SecurityTokenPinDialogHost {
+class SecurityTokenPinDialogHostLoginImpl final
+    : public SecurityTokenPinDialogHost {
  public:
-  SecurityTokenPinDialogHostImpl();
-  SecurityTokenPinDialogHostImpl(const SecurityTokenPinDialogHostImpl&) =
-      delete;
-  SecurityTokenPinDialogHostImpl& operator=(
-      const SecurityTokenPinDialogHostImpl&) = delete;
-  ~SecurityTokenPinDialogHostImpl() override;
+  SecurityTokenPinDialogHostLoginImpl();
+  SecurityTokenPinDialogHostLoginImpl(
+      const SecurityTokenPinDialogHostLoginImpl&) = delete;
+  SecurityTokenPinDialogHostLoginImpl& operator=(
+      const SecurityTokenPinDialogHostLoginImpl&) = delete;
+  ~SecurityTokenPinDialogHostLoginImpl() override;
 
   // SecurityTokenPinDialogHost:
   void ShowSecurityTokenPinDialog(
@@ -59,9 +60,10 @@
   // Is non-empty iff the dialog is active.
   SecurityTokenPinDialogClosedCallback pin_dialog_closed_callback_;
 
-  base::WeakPtrFactory<SecurityTokenPinDialogHostImpl> weak_ptr_factory_{this};
+  base::WeakPtrFactory<SecurityTokenPinDialogHostLoginImpl> weak_ptr_factory_{
+      this};
 };
 
 }  // namespace ash
 
-#endif  // CHROME_BROWSER_ASH_LOGIN_SECURITY_TOKEN_PIN_DIALOG_HOST_IMPL_H_
+#endif  // CHROME_BROWSER_ASH_LOGIN_SECURITY_TOKEN_PIN_DIALOG_HOST_LOGIN_IMPL_H_
diff --git a/chrome/browser/ash/login/signin/oauth2_login_verifier.h b/chrome/browser/ash/login/signin/oauth2_login_verifier.h
index ae24e110..141cbaa 100644
--- a/chrome/browser/ash/login/signin/oauth2_login_verifier.h
+++ b/chrome/browser/ash/login/signin/oauth2_login_verifier.h
@@ -9,7 +9,6 @@
 #include <utility>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
diff --git a/chrome/browser/ash/login/signin/oauth2_token_fetcher.h b/chrome/browser/ash/login/signin/oauth2_token_fetcher.h
index 40c102ba..93ddfa1 100644
--- a/chrome/browser/ash/login/signin/oauth2_token_fetcher.h
+++ b/chrome/browser/ash/login/signin/oauth2_token_fetcher.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/callback_forward.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
diff --git a/chrome/browser/ash/login/signin/offline_signin_limiter_factory.h b/chrome/browser/ash/login/signin/offline_signin_limiter_factory.h
index f4edd5b..430a97f5 100644
--- a/chrome/browser/ash/login/signin/offline_signin_limiter_factory.h
+++ b/chrome/browser/ash/login/signin/offline_signin_limiter_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_LOGIN_SIGNIN_OFFLINE_SIGNIN_LIMITER_FACTORY_H_
 #define CHROME_BROWSER_ASH_LOGIN_SIGNIN_OFFLINE_SIGNIN_LIMITER_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/ash/login/signin/signin_error_notifier.h b/chrome/browser/ash/login/signin/signin_error_notifier.h
index b424944f..4b7a5376 100644
--- a/chrome/browser/ash/login/signin/signin_error_notifier.h
+++ b/chrome/browser/ash/login/signin/signin_error_notifier.h
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "base/auto_reset.h"
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/login/signin/token_handle_util.h"
diff --git a/chrome/browser/ash/login/test/local_policy_test_server_mixin.cc b/chrome/browser/ash/login/test/local_policy_test_server_mixin.cc
index 2d627de3..ffb4617 100644
--- a/chrome/browser/ash/login/test/local_policy_test_server_mixin.cc
+++ b/chrome/browser/ash/login/test/local_policy_test_server_mixin.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/components/attestation/fake_attestation_flow.h"
 #include "base/guid.h"
 #include "base/json/values_util.h"
 #include "base/values.h"
@@ -15,7 +16,6 @@
 #include "chrome/browser/ash/policy/enrollment/device_cloud_policy_initializer.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
-#include "chromeos/attestation/fake_attestation_flow.h"
 #include "chromeos/system/fake_statistics_provider.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/test/policy_builder.h"
@@ -158,7 +158,7 @@
   g_browser_process->platform_part()
       ->browser_policy_connector_ash()
       ->SetAttestationFlowForTesting(
-          std::make_unique<chromeos::attestation::FakeAttestationFlow>());
+          std::make_unique<attestation::FakeAttestationFlow>());
 }
 
 void LocalPolicyTestServerMixin::SetExpectedPsmParamsInDeviceRegisterRequest(
diff --git a/chrome/browser/ash/login/ui/input_events_blocker.h b/chrome/browser/ash/login/ui/input_events_blocker.h
index 58d3a4f..97feb3b 100644
--- a/chrome/browser/ash/login/ui/input_events_blocker.h
+++ b/chrome/browser/ash/login/ui/input_events_blocker.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_LOGIN_UI_INPUT_EVENTS_BLOCKER_H_
 #define CHROME_BROWSER_ASH_LOGIN_UI_INPUT_EVENTS_BLOCKER_H_
 
-#include "base/compiler_specific.h"
 #include "ui/events/event_handler.h"
 
 namespace ash {
diff --git a/chrome/browser/ash/login/ui/login_display_host_mojo.cc b/chrome/browser/ash/login/ui/login_display_host_mojo.cc
index 7e7eaa0e..32c8c49 100644
--- a/chrome/browser/ash/login/ui/login_display_host_mojo.cc
+++ b/chrome/browser/ash/login/ui/login_display_host_mojo.cc
@@ -149,7 +149,7 @@
 
   GetLoginScreenCertProviderService()
       ->pin_dialog_manager()
-      ->RemovePinDialogHost(&security_token_pin_dialog_host_impl_);
+      ->RemovePinDialogHost(&security_token_pin_dialog_host_login_impl_);
   dialog_->GetOobeUI()->signin_screen_handler()->SetDelegate(nullptr);
   StopObservingOobeUI();
   dialog_->Close();
@@ -670,7 +670,7 @@
   wizard_controller_ = std::make_unique<WizardController>(GetWizardContext());
 
   GetLoginScreenCertProviderService()->pin_dialog_manager()->AddPinDialogHost(
-      &security_token_pin_dialog_host_impl_);
+      &security_token_pin_dialog_host_login_impl_);
 
   // Update status of add user button in the shelf.
   UpdateAddUserButtonStatus();
diff --git a/chrome/browser/ash/login/ui/login_display_host_mojo.h b/chrome/browser/ash/login/ui/login_display_host_mojo.h
index 559c6c3..25fa5dfb 100644
--- a/chrome/browser/ash/login/ui/login_display_host_mojo.h
+++ b/chrome/browser/ash/login/ui/login_display_host_mojo.h
@@ -15,7 +15,7 @@
 #include "base/scoped_observation.h"
 #include "chrome/browser/ash/login/challenge_response_auth_keys_loader.h"
 #include "chrome/browser/ash/login/screens/user_selection_screen.h"
-#include "chrome/browser/ash/login/security_token_pin_dialog_host_impl.h"
+#include "chrome/browser/ash/login/security_token_pin_dialog_host_login_impl.h"
 #include "chrome/browser/ash/login/ui/login_display_host_common.h"
 #include "chrome/browser/ash/login/ui/oobe_ui_dialog_delegate.h"
 #include "chrome/browser/ui/ash/login_screen_client_impl.h"
@@ -221,7 +221,8 @@
 
   ChallengeResponseAuthKeysLoader challenge_response_auth_keys_loader_;
 
-  SecurityTokenPinDialogHostImpl security_token_pin_dialog_host_impl_;
+  SecurityTokenPinDialogHostLoginImpl
+      security_token_pin_dialog_host_login_impl_;
 
   // Set if this has been added as a `OobeUI::Observer`.
   bool added_as_oobe_observer_ = false;
diff --git a/chrome/browser/ash/login/ui/login_display_webui.h b/chrome/browser/ash/login/ui/login_display_webui.h
index d8ef30a..ca56755 100644
--- a/chrome/browser/ash/login/ui/login_display_webui.h
+++ b/chrome/browser/ash/login/ui/login_display_webui.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_LOGIN_UI_LOGIN_DISPLAY_WEBUI_H_
 #define CHROME_BROWSER_ASH_LOGIN_UI_LOGIN_DISPLAY_WEBUI_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/login/signin_specifics.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
 #include "components/user_manager/user.h"
diff --git a/chrome/browser/ash/login/user_flow.h b/chrome/browser/ash/login/user_flow.h
index 613a82d..60dbcfe6 100644
--- a/chrome/browser/ash/login/user_flow.h
+++ b/chrome/browser/ash/login/user_flow.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_LOGIN_USER_FLOW_H_
 #define CHROME_BROWSER_ASH_LOGIN_USER_FLOW_H_
 
-#include "base/compiler_specific.h"
 #include "chromeos/login/auth/auth_status_consumer.h"
 // TODO(https://crbug.com/1164001): move to forward declaration.
 #include "chromeos/login/auth/user_context.h"
diff --git a/chrome/browser/ash/login/users/avatar/user_image_manager_impl.h b/chrome/browser/ash/login/users/avatar/user_image_manager_impl.h
index 899b6fd..e6d9350 100644
--- a/chrome/browser/ash/login/users/avatar/user_image_manager_impl.h
+++ b/chrome/browser/ash/login/users/avatar/user_image_manager_impl.h
@@ -10,7 +10,6 @@
 #include <set>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
diff --git a/chrome/browser/ash/login/users/avatar/user_image_manager_test_util.h b/chrome/browser/ash/login/users/avatar/user_image_manager_test_util.h
index e742bf6..97e49e06 100644
--- a/chrome/browser/ash/login/users/avatar/user_image_manager_test_util.h
+++ b/chrome/browser/ash/login/users/avatar/user_image_manager_test_util.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_LOGIN_USERS_AVATAR_USER_IMAGE_MANAGER_TEST_UTIL_H_
 #define CHROME_BROWSER_ASH_LOGIN_USERS_AVATAR_USER_IMAGE_MANAGER_TEST_UTIL_H_
 
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/run_loop.h"
 #include "chrome/browser/image_decoder/image_decoder.h"
diff --git a/chrome/browser/ash/login/users/fake_supervised_user_manager.h b/chrome/browser/ash/login/users/fake_supervised_user_manager.h
index 4440a303..56872d6 100644
--- a/chrome/browser/ash/login/users/fake_supervised_user_manager.h
+++ b/chrome/browser/ash/login/users/fake_supervised_user_manager.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_LOGIN_USERS_FAKE_SUPERVISED_USER_MANAGER_H_
 #define CHROME_BROWSER_ASH_LOGIN_USERS_FAKE_SUPERVISED_USER_MANAGER_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/login/users/supervised_user_manager.h"
 
 namespace ash {
diff --git a/chrome/browser/ash/login/users/supervised_user_manager_impl.h b/chrome/browser/ash/login/users/supervised_user_manager_impl.h
index 62cb430..82dc10c 100644
--- a/chrome/browser/ash/login/users/supervised_user_manager_impl.h
+++ b/chrome/browser/ash/login/users/supervised_user_manager_impl.h
@@ -7,7 +7,6 @@
 
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/login/users/supervised_user_manager.h"
 
 namespace ash {
diff --git a/chrome/browser/ash/login/wizard_controller.h b/chrome/browser/ash/login/wizard_controller.h
index 98f1aad..79cb190 100644
--- a/chrome/browser/ash/login/wizard_controller.h
+++ b/chrome/browser/ash/login/wizard_controller.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
diff --git a/chrome/browser/ash/net/network_portal_detector_impl.h b/chrome/browser/ash/net/network_portal_detector_impl.h
index 3c0c152..258b1d2 100644
--- a/chrome/browser/ash/net/network_portal_detector_impl.h
+++ b/chrome/browser/ash/net/network_portal_detector_impl.h
@@ -11,7 +11,6 @@
 
 #include "base/callback_forward.h"
 #include "base/cancelable_callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/ash/net/network_portal_detector_test_impl.h b/chrome/browser/ash/net/network_portal_detector_test_impl.h
index 0d88a36c..ef62e45 100644
--- a/chrome/browser/ash/net/network_portal_detector_test_impl.h
+++ b/chrome/browser/ash/net/network_portal_detector_test_impl.h
@@ -11,7 +11,6 @@
 #include <vector>
 
 #include "base/callback_forward.h"
-#include "base/compiler_specific.h"
 #include "base/observer_list.h"
 #include "chromeos/network/portal_detector/network_portal_detector.h"
 
diff --git a/chrome/browser/ash/note_taking_helper_unittest.cc b/chrome/browser/ash/note_taking_helper_unittest.cc
index 59f39126..b198ace 100644
--- a/chrome/browser/ash/note_taking_helper_unittest.cc
+++ b/chrome/browser/ash/note_taking_helper_unittest.cc
@@ -10,7 +10,6 @@
 #include "ash/components/arc/arc_prefs.h"
 #include "ash/components/arc/test/connection_holder_util.h"
 #include "ash/components/arc/test/fake_file_system_instance.h"
-#include "ash/components/arc/test/fake_intent_helper_instance.h"
 #include "ash/constants/ash_switches.h"
 #include "ash/public/cpp/note_taking_client.h"
 #include "base/bind.h"
@@ -56,6 +55,7 @@
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/session/arc_service_manager.h"
 #include "components/arc/session/connection_holder.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
 #include "components/crx_file/id_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync_preferences/pref_service_syncable.h"
diff --git a/chrome/browser/ash/notifications/echo_dialog_view.h b/chrome/browser/ash/notifications/echo_dialog_view.h
index 389e8a4a..0fe23929 100644
--- a/chrome/browser/ash/notifications/echo_dialog_view.h
+++ b/chrome/browser/ash/notifications/echo_dialog_view.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_NOTIFICATIONS_ECHO_DIALOG_VIEW_H_
 #define CHROME_BROWSER_ASH_NOTIFICATIONS_ECHO_DIALOG_VIEW_H_
 
-#include "base/compiler_specific.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/window/dialog_delegate.h"
diff --git a/chrome/browser/ash/ownership/owner_settings_service_ash_factory.h b/chrome/browser/ash/ownership/owner_settings_service_ash_factory.h
index d567936..b09eb2c9a 100644
--- a/chrome/browser/ash/ownership/owner_settings_service_ash_factory.h
+++ b/chrome/browser/ash/ownership/owner_settings_service_ash_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_ASH_FACTORY_H_
 #define CHROME_BROWSER_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_ASH_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
diff --git a/chrome/browser/ash/policy/core/browser_policy_connector_ash.cc b/chrome/browser/ash/policy/core/browser_policy_connector_ash.cc
index 348f36c..91ca790 100644
--- a/chrome/browser/ash/policy/core/browser_policy_connector_ash.cc
+++ b/chrome/browser/ash/policy/core/browser_policy_connector_ash.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/components/attestation/attestation_flow_adaptive.h"
 #include "ash/components/settings/cros_settings_names.h"
 #include "ash/components/settings/cros_settings_provider.h"
 #include "ash/components/settings/timezone_settings.h"
@@ -69,7 +70,6 @@
 #include "chrome/browser/policy/device_management_service_configuration.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/attestation/attestation_flow_adaptive.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
@@ -116,9 +116,8 @@
   return ash::AutoEnrollmentController::IsFREEnabled();
 }
 
-std::unique_ptr<chromeos::attestation::AttestationFlow>
-CreateAttestationFlow() {
-  return std::make_unique<chromeos::attestation::AttestationFlowAdaptive>(
+std::unique_ptr<ash::attestation::AttestationFlow> CreateAttestationFlow() {
+  return std::make_unique<ash::attestation::AttestationFlowAdaptive>(
       std::make_unique<ash::attestation::AttestationCAClient>());
 }
 
@@ -492,7 +491,7 @@
 }
 
 void BrowserPolicyConnectorAsh::SetAttestationFlowForTesting(
-    std::unique_ptr<chromeos::attestation::AttestationFlow> attestation_flow) {
+    std::unique_ptr<ash::attestation::AttestationFlow> attestation_flow) {
   attestation_flow_ = std::move(attestation_flow);
 }
 
diff --git a/chrome/browser/ash/policy/core/browser_policy_connector_ash.h b/chrome/browser/ash/policy/core/browser_policy_connector_ash.h
index 09f417d..5c3b8334 100644
--- a/chrome/browser/ash/policy/core/browser_policy_connector_ash.h
+++ b/chrome/browser/ash/policy/core/browser_policy_connector_ash.h
@@ -21,18 +21,18 @@
 class PrefRegistrySimple;
 class PrefService;
 
-namespace enterprise_management {
-class PolicyData;
-}
-
-namespace chromeos {
-
-class InstallAttributes;
-
+namespace ash {
 namespace attestation {
 class AttestationFlow;
-}
+}  // namespace attestation
+}  // namespace ash
 
+namespace enterprise_management {
+class PolicyData;
+}  // namespace enterprise_management
+
+namespace chromeos {
+class InstallAttributes;
 }  // namespace chromeos
 
 namespace policy {
@@ -208,13 +208,13 @@
   // attestation flow is needed for testing.
   // TODO(crbug.com/1235325): Remove AttestationFlow completely from the
   // connector and a fake one directly to |EnterpriseEnrollmentHelperImpl|.
-  chromeos::attestation::AttestationFlow* GetAttestationFlow() const {
+  ash::attestation::AttestationFlow* GetAttestationFlow() const {
     return attestation_flow_.get();
   }
 
   // Sets the attestation flow for testing.
   void SetAttestationFlowForTesting(
-      std::unique_ptr<chromeos::attestation::AttestationFlow> attestation_flow);
+      std::unique_ptr<ash::attestation::AttestationFlow> attestation_flow);
 
   // Returns device's market segment.
   MarketSegment GetEnterpriseMarketSegment() const;
@@ -333,7 +333,7 @@
   // needed for testing.
   // TODO(crbug.com/1235325): Remove AttestationFlow completely from the
   // connector and a fake one directly to |EnterpriseEnrollmentHelperImpl|.
-  std::unique_ptr<chromeos::attestation::AttestationFlow> attestation_flow_;
+  std::unique_ptr<ash::attestation::AttestationFlow> attestation_flow_;
 
   base::WeakPtrFactory<BrowserPolicyConnectorAsh> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/ash/policy/core/device_cloud_policy_manager_ash.h b/chrome/browser/ash/policy/core/device_cloud_policy_manager_ash.h
index 8a36502..3b6a3fcf 100644
--- a/chrome/browser/ash/policy/core/device_cloud_policy_manager_ash.h
+++ b/chrome/browser/ash/policy/core/device_cloud_policy_manager_ash.h
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/callback_forward.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
 #include "chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.h"
diff --git a/chrome/browser/ash/policy/core/device_cloud_policy_manager_ash_unittest.cc b/chrome/browser/ash/policy/core/device_cloud_policy_manager_ash_unittest.cc
index 58e37ad..0f4e9bc 100644
--- a/chrome/browser/ash/policy/core/device_cloud_policy_manager_ash_unittest.cc
+++ b/chrome/browser/ash/policy/core/device_cloud_policy_manager_ash_unittest.cc
@@ -10,6 +10,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/components/attestation/mock_attestation_flow.h"
 #include "ash/constants/ash_switches.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -34,7 +35,6 @@
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/attestation/mock_attestation_flow.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
 #include "chromeos/dbus/dbus_client_implementation_type.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -100,7 +100,7 @@
 }
 
 void CertCallbackSuccess(
-    chromeos::attestation::AttestationFlow::CertificateCallback callback) {
+    ash::attestation::AttestationFlow::CertificateCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(std::move(callback),
@@ -300,7 +300,7 @@
   chromeos::system::ScopedFakeStatisticsProvider fake_statistics_provider_;
   bool set_empty_system_salt_ = false;
   ServerBackedStateKeysBroker state_keys_broker_;
-  StrictMock<chromeos::attestation::MockAttestationFlow> mock_attestation_flow_;
+  StrictMock<ash::attestation::MockAttestationFlow> mock_attestation_flow_;
 
   DeviceCloudPolicyStoreAsh* store_;
   SchemaRegistry schema_registry_;
diff --git a/chrome/browser/ash/policy/core/device_cloud_policy_store_ash.h b/chrome/browser/ash/policy/core/device_cloud_policy_store_ash.h
index 6c0792a..547d5e6 100644
--- a/chrome/browser/ash/policy/core/device_cloud_policy_store_ash.h
+++ b/chrome/browser/ash/policy/core/device_cloud_policy_store_ash.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/policy/core/device_cloud_policy_validator.h"
diff --git a/chrome/browser/ash/policy/core/device_local_account_extension_tracker.h b/chrome/browser/ash/policy/core/device_local_account_extension_tracker.h
index a1dcb05..737181f 100644
--- a/chrome/browser/ash/policy/core/device_local_account_extension_tracker.h
+++ b/chrome/browser/ash/policy/core/device_local_account_extension_tracker.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_POLICY_CORE_DEVICE_LOCAL_ACCOUNT_EXTENSION_TRACKER_H_
 #define CHROME_BROWSER_ASH_POLICY_CORE_DEVICE_LOCAL_ACCOUNT_EXTENSION_TRACKER_H_
 
-#include "base/compiler_specific.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
 
 namespace policy {
diff --git a/chrome/browser/ash/policy/core/device_local_account_policy_provider.h b/chrome/browser/ash/policy/core/device_local_account_policy_provider.h
index 8d44abc..93f484f2 100644
--- a/chrome/browser/ash/policy/core/device_local_account_policy_provider.h
+++ b/chrome/browser/ash/policy/core/device_local_account_policy_provider.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/policy/core/device_local_account.h"
diff --git a/chrome/browser/ash/policy/core/device_local_account_policy_service.h b/chrome/browser/ash/policy/core/device_local_account_policy_service.h
index 3bb4a77..517d065 100644
--- a/chrome/browser/ash/policy/core/device_local_account_policy_service.h
+++ b/chrome/browser/ash/policy/core/device_local_account_policy_service.h
@@ -11,7 +11,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/ash/policy/core/device_local_account_policy_store.h b/chrome/browser/ash/policy/core/device_local_account_policy_store.h
index 66f9df49..90995636 100644
--- a/chrome/browser/ash/policy/core/device_local_account_policy_store.h
+++ b/chrome/browser/ash/policy/core/device_local_account_policy_store.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/settings/device_settings_service.h"
diff --git a/chrome/browser/ash/policy/core/device_policy_cros_browser_test.h b/chrome/browser/ash/policy/core/device_policy_cros_browser_test.h
index d97b95ab..af43d8972 100644
--- a/chrome/browser/ash/policy/core/device_policy_cros_browser_test.h
+++ b/chrome/browser/ash/policy/core/device_policy_cros_browser_test.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/login/test/device_state_mixin.h"
 #include "chrome/browser/ash/policy/core/device_policy_builder.h"
 #include "chrome/test/base/mixin_based_in_process_browser_test.h"
diff --git a/chrome/browser/ash/policy/core/user_cloud_policy_manager_ash.h b/chrome/browser/ash/policy/core/user_cloud_policy_manager_ash.h
index 67072d0..d1e11b60 100644
--- a/chrome/browser/ash/policy/core/user_cloud_policy_manager_ash.h
+++ b/chrome/browser/ash/policy/core/user_cloud_policy_manager_ash.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "base/bind.h"
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/scoped_observation.h"
diff --git a/chrome/browser/ash/policy/core/user_cloud_policy_store_ash.h b/chrome/browser/ash/policy/core/user_cloud_policy_store_ash.h
index f18ab9ba..7a053b4 100644
--- a/chrome/browser/ash/policy/core/user_cloud_policy_store_ash.h
+++ b/chrome/browser/ash/policy/core/user_cloud_policy_store_ash.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager.cc b/chrome/browser/ash/policy/dlp/dlp_content_manager.cc
index 0bb0d81d..592a730 100644
--- a/chrome/browser/ash/policy/dlp/dlp_content_manager.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_content_manager.cc
@@ -680,10 +680,14 @@
                 media_id.web_contents_id.render_process_id,
                 media_id.web_contents_id.main_render_frame_id));
     ConfidentialContentsInfo info;
-    info.restriction_info =
-        GetConfidentialRestrictions(web_contents)
-            .GetRestrictionLevelAndUrl(DlpContentRestriction::kScreenShare);
-    info.confidential_contents.Add(web_contents);
+    if (web_contents) {
+      info.restriction_info =
+          GetConfidentialRestrictions(web_contents)
+              .GetRestrictionLevelAndUrl(DlpContentRestriction::kScreenShare);
+      info.confidential_contents.Add(web_contents);
+    } else {
+      NOTREACHED();
+    }
     return info;
   }
   DCHECK_EQ(media_id.type, content::DesktopMediaID::Type::TYPE_WINDOW);
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_handler.cc b/chrome/browser/ash/policy/enrollment/enrollment_handler.cc
index 608b09c..74b6cee2 100644
--- a/chrome/browser/ash/policy/enrollment/enrollment_handler.cc
+++ b/chrome/browser/ash/policy/enrollment/enrollment_handler.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/components/attestation/attestation_flow.h"
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -28,7 +29,6 @@
 #include "chrome/browser/policy/enrollment_status.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/attestation/attestation_flow.h"
 #include "chromeos/dbus/authpolicy/authpolicy_client.h"
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -221,7 +221,7 @@
     DeviceCloudPolicyStoreAsh* store,
     chromeos::InstallAttributes* install_attributes,
     ServerBackedStateKeysBroker* state_keys_broker,
-    chromeos::attestation::AttestationFlow* attestation_flow,
+    ash::attestation::AttestationFlow* attestation_flow,
     std::unique_ptr<SigningService> signing_service,
     std::unique_ptr<CloudPolicyClient> client,
     scoped_refptr<base::SequencedTaskRunner> background_task_runner,
@@ -473,7 +473,7 @@
 }
 
 void EnrollmentHandler::StartAttestationBasedEnrollmentFlow() {
-  chromeos::attestation::AttestationFlow::CertificateCallback callback =
+  ash::attestation::AttestationFlow::CertificateCallback callback =
       base::BindOnce(&EnrollmentHandler::HandleRegistrationCertificateResult,
                      weak_ptr_factory_.GetWeakPtr());
   attestation_flow_->GetCertificate(
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_handler.h b/chrome/browser/ash/policy/enrollment/enrollment_handler.h
index 5889fb4..7c2a315 100644
--- a/chrome/browser/ash/policy/enrollment/enrollment_handler.h
+++ b/chrome/browser/ash/policy/enrollment/enrollment_handler.h
@@ -10,7 +10,6 @@
 
 #include "base/callback.h"
 #include "base/callback_forward.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/policy/core/device_cloud_policy_validator.h"
@@ -28,15 +27,15 @@
 #include "google_apis/gaia/gaia_oauth_client.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace base {
-class SequencedTaskRunner;
-}
-
-namespace chromeos {
+namespace ash {
 namespace attestation {
 class AttestationFlow;
-}
-}  // namespace chromeos
+}  // namespace attestation
+}  // namespace ash
+
+namespace base {
+class SequencedTaskRunner;
+}  // namespace base
 
 namespace policy {
 class ActiveDirectoryJoinDelegate;
@@ -69,7 +68,7 @@
       DeviceCloudPolicyStoreAsh* store,
       chromeos::InstallAttributes* install_attributes,
       ServerBackedStateKeysBroker* state_keys_broker,
-      chromeos::attestation::AttestationFlow* attestation_flow,
+      ash::attestation::AttestationFlow* attestation_flow,
       std::unique_ptr<SigningService> signing_service,
       std::unique_ptr<CloudPolicyClient> client,
       scoped_refptr<base::SequencedTaskRunner> background_task_runner,
@@ -216,7 +215,7 @@
   DeviceCloudPolicyStoreAsh* store_;
   chromeos::InstallAttributes* install_attributes_;
   ServerBackedStateKeysBroker* state_keys_broker_;
-  chromeos::attestation::AttestationFlow* attestation_flow_;
+  ash::attestation::AttestationFlow* attestation_flow_;
   // SigningService to be used by |client_| to register with.
   std::unique_ptr<SigningService> signing_service_;
   std::unique_ptr<CloudPolicyClient> client_;
diff --git a/chrome/browser/ash/policy/enrollment/tpm_enrollment_key_signing_service.cc b/chrome/browser/ash/policy/enrollment/tpm_enrollment_key_signing_service.cc
index 14182f9..cd62aa1 100644
--- a/chrome/browser/ash/policy/enrollment/tpm_enrollment_key_signing_service.cc
+++ b/chrome/browser/ash/policy/enrollment/tpm_enrollment_key_signing_service.cc
@@ -7,8 +7,8 @@
 #include <string>
 #include <utility>
 
+#include "ash/components/attestation/attestation_flow_utils.h"
 #include "base/bind.h"
-#include "chromeos/attestation/attestation_flow_utils.h"
 #include "chromeos/dbus/attestation/attestation.pb.h"
 #include "chromeos/dbus/attestation/attestation_client.h"
 #include "chromeos/dbus/attestation/interface.pb.h"
@@ -28,7 +28,7 @@
   ::attestation::SignSimpleChallengeRequest request;
   request.set_username("");
   request.set_key_label(
-      chromeos::attestation::GetKeyNameForProfile(cert_profile, ""));
+      ash::attestation::GetKeyNameForProfile(cert_profile, ""));
   request.set_challenge(data);
   chromeos::AttestationClient::Get()->SignSimpleChallenge(
       request, base::BindOnce(&TpmEnrollmentKeySigningService::OnDataSigned,
diff --git a/chrome/browser/ash/policy/enrollment/tpm_enrollment_key_signing_service_unittest.cc b/chrome/browser/ash/policy/enrollment/tpm_enrollment_key_signing_service_unittest.cc
index 53da039..6d8e7e62 100644
--- a/chrome/browser/ash/policy/enrollment/tpm_enrollment_key_signing_service_unittest.cc
+++ b/chrome/browser/ash/policy/enrollment/tpm_enrollment_key_signing_service_unittest.cc
@@ -6,12 +6,12 @@
 
 #include <utility>
 
+#include "ash/components/attestation/attestation_flow_utils.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_forward.h"
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
-#include "chromeos/attestation/attestation_flow_utils.h"
 #include "chromeos/dbus/attestation/attestation.pb.h"
 #include "chromeos/dbus/attestation/attestation_client.h"
 #include "components/policy/proto/device_management_backend.pb.h"
@@ -54,7 +54,7 @@
       ->GetTestInterface()
       ->AllowlistSignSimpleChallengeKey(
           /*username=*/"",
-          chromeos::attestation::GetKeyNameForProfile(
+          ash::attestation::GetKeyNameForProfile(
               chromeos::attestation::PROFILE_ENTERPRISE_ENROLLMENT_CERTIFICATE,
               ""));
 
diff --git a/chrome/browser/ash/policy/external_data/cloud_external_data_manager_base.h b/chrome/browser/ash/policy/external_data/cloud_external_data_manager_base.h
index 71401717..2e1a41547 100644
--- a/chrome/browser/ash/policy/external_data/cloud_external_data_manager_base.h
+++ b/chrome/browser/ash/policy/external_data/cloud_external_data_manager_base.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/sequence_checker.h"
 #include "components/policy/core/common/cloud/cloud_external_data_manager.h"
diff --git a/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer.h b/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer.h
index 1992d199..5db8462 100644
--- a/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer.h
+++ b/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
diff --git a/chrome/browser/ash/policy/external_data/device_local_account_external_data_manager.h b/chrome/browser/ash/policy/external_data/device_local_account_external_data_manager.h
index 397e04f..e6deb48 100644
--- a/chrome/browser/ash/policy/external_data/device_local_account_external_data_manager.h
+++ b/chrome/browser/ash/policy/external_data/device_local_account_external_data_manager.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/ash/policy/external_data/cloud_external_data_manager_base.h"
 #include "components/policy/core/common/policy_details.h"
diff --git a/chrome/browser/ash/policy/external_data/device_local_account_external_data_service.h b/chrome/browser/ash/policy/external_data/device_local_account_external_data_service.h
index eca6ea4..a7f88b9c 100644
--- a/chrome/browser/ash/policy/external_data/device_local_account_external_data_service.h
+++ b/chrome/browser/ash/policy/external_data/device_local_account_external_data_service.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/ash/policy/core/device_local_account_policy_service.h"
 #include "chrome/browser/ash/policy/external_data/device_local_account_external_data_manager.h"
diff --git a/chrome/browser/ash/policy/handlers/configuration_policy_handler_ash.h b/chrome/browser/ash/policy/handlers/configuration_policy_handler_ash.h
index 12750a0..7755a33 100644
--- a/chrome/browser/ash/policy/handlers/configuration_policy_handler_ash.h
+++ b/chrome/browser/ash/policy/handlers/configuration_policy_handler_ash.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/policy_handlers.h"
 #include "chromeos/network/network_ui_data.h"
diff --git a/chrome/browser/ash/policy/login/login_profile_policy_provider.h b/chrome/browser/ash/policy/login/login_profile_policy_provider.h
index 1445ac3bd6..efc03da8 100644
--- a/chrome/browser/ash/policy/login/login_profile_policy_provider.h
+++ b/chrome/browser/ash/policy/login/login_profile_policy_provider.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_POLICY_LOGIN_LOGIN_PROFILE_POLICY_PROVIDER_H_
 #define CHROME_BROWSER_ASH_POLICY_LOGIN_LOGIN_PROFILE_POLICY_PROVIDER_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "components/policy/core/common/configuration_policy_provider.h"
 #include "components/policy/core/common/policy_service.h"
diff --git a/chrome/browser/ash/policy/networking/device_network_configuration_updater.h b/chrome/browser/ash/policy/networking/device_network_configuration_updater.h
index b4f072c..fc88679 100644
--- a/chrome/browser/ash/policy/networking/device_network_configuration_updater.h
+++ b/chrome/browser/ash/policy/networking/device_network_configuration_updater.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "base/callback_list.h"
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/policy/networking/network_configuration_updater.h"
 #include "components/onc/onc_constants.h"
diff --git a/chrome/browser/ash/policy/networking/network_configuration_updater.h b/chrome/browser/ash/policy/networking/network_configuration_updater.h
index f45d79a..948388a 100644
--- a/chrome/browser/ash/policy/networking/network_configuration_updater.h
+++ b/chrome/browser/ash/policy/networking/network_configuration_updater.h
@@ -10,7 +10,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/observer_list.h"
 #include "base/sequence_checker.h"
 #include "chromeos/network/onc/certificate_scope.h"
diff --git a/chrome/browser/ash/policy/networking/policy_cert_service.h b/chrome/browser/ash/policy/networking/policy_cert_service.h
index d932a335..4528d05 100644
--- a/chrome/browser/ash/policy/networking/policy_cert_service.h
+++ b/chrome/browser/ash/policy/networking/policy_cert_service.h
@@ -9,7 +9,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/network/policy_certificate_provider.h"
diff --git a/chrome/browser/ash/policy/networking/policy_cert_service_factory.h b/chrome/browser/ash/policy/networking/policy_cert_service_factory.h
index 40598df5..c8bcab4 100644
--- a/chrome/browser/ash/policy/networking/policy_cert_service_factory.h
+++ b/chrome/browser/ash/policy/networking/policy_cert_service_factory.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
 namespace base {
diff --git a/chrome/browser/ash/policy/networking/user_network_configuration_updater.h b/chrome/browser/ash/policy/networking/user_network_configuration_updater.h
index d831bf2..9f6d03b 100644
--- a/chrome/browser/ash/policy/networking/user_network_configuration_updater.h
+++ b/chrome/browser/ash/policy/networking/user_network_configuration_updater.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/policy/networking/network_configuration_updater.h"
diff --git a/chrome/browser/ash/policy/networking/user_network_configuration_updater_factory.h b/chrome/browser/ash/policy/networking/user_network_configuration_updater_factory.h
index f76ff631..56ba025e 100644
--- a/chrome/browser/ash/policy/networking/user_network_configuration_updater_factory.h
+++ b/chrome/browser/ash/policy/networking/user_network_configuration_updater_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_POLICY_NETWORKING_USER_NETWORK_CONFIGURATION_UPDATER_FACTORY_H_
 #define CHROME_BROWSER_ASH_POLICY_NETWORKING_USER_NETWORK_CONFIGURATION_UPDATER_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
 namespace base {
diff --git a/chrome/browser/ash/policy/server_backed_state/active_directory_device_state_uploader_unittest.cc b/chrome/browser/ash/policy/server_backed_state/active_directory_device_state_uploader_unittest.cc
index 18f0eb8b..a25429d 100644
--- a/chrome/browser/ash/policy/server_backed_state/active_directory_device_state_uploader_unittest.cc
+++ b/chrome/browser/ash/policy/server_backed_state/active_directory_device_state_uploader_unittest.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/components/attestation/mock_attestation_flow.h"
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/task/post_task.h"
@@ -18,7 +19,6 @@
 #include "chrome/browser/ash/settings/device_settings_test_helper.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
-#include "chromeos/attestation/mock_attestation_flow.h"
 #include "chromeos/dbus/attestation/fake_attestation_client.h"
 #include "chromeos/dbus/constants/attestation_constants.h"
 #include "chromeos/dbus/session_manager/fake_session_manager_client.h"
diff --git a/chrome/browser/ash/policy/status_collector/app_info_generator_unittest.cc b/chrome/browser/ash/policy/status_collector/app_info_generator_unittest.cc
index 99769f7..74c7413 100644
--- a/chrome/browser/ash/policy/status_collector/app_info_generator_unittest.cc
+++ b/chrome/browser/ash/policy/status_collector/app_info_generator_unittest.cc
@@ -176,7 +176,9 @@
     auto clone = instance.instance()->Clone();
     clone->UpdateState(state, time);
 
-    GetInstanceRegistry().OnInstance(std::move(clone));
+    std::vector<std::unique_ptr<apps::Instance>> deltas;
+    deltas.push_back(std::move(clone));
+    GetInstanceRegistry().OnInstances(std::move(deltas));
   }
 
   std::unique_ptr<TestingProfile> CreateProfile(const AccountId& account_id,
diff --git a/chrome/browser/ash/policy/status_collector/child_status_collector.h b/chrome/browser/ash/policy/status_collector/child_status_collector.h
index d74aae6..43c9cd9c 100644
--- a/chrome/browser/ash/policy/status_collector/child_status_collector.h
+++ b/chrome/browser/ash/policy/status_collector/child_status_collector.h
@@ -12,7 +12,6 @@
 #include <string>
 
 #include "base/callback_forward.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector.cc b/chrome/browser/ash/policy/status_collector/device_status_collector.cc
index baf3a2b..f26aae0 100644
--- a/chrome/browser/ash/policy/status_collector/device_status_collector.cc
+++ b/chrome/browser/ash/policy/status_collector/device_status_collector.cc
@@ -741,13 +741,15 @@
       bool report_system_info,
       bool report_vpd_info,
       bool report_storage_status,
-      bool report_version_info) {
+      bool report_version_info,
+      bool report_network_configuration) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     cros_healthd_data_fetcher.Run(
         CrosHealthdCollectionMode::kFull,
         base::BindOnce(&DeviceStatusCollectorState::OnCrosHealthdDataReceived,
                        this, report_system_info, report_vpd_info,
-                       report_storage_status, report_version_info));
+                       report_storage_status, report_version_info,
+                       report_network_configuration));
   }
 
   void FetchEMMCLifeTime(
@@ -843,6 +845,7 @@
       bool report_vpd_info,
       bool report_storage_status,
       bool report_version_info,
+      bool report_network_configuration,
       chromeos::cros_healthd::mojom::TelemetryInfoPtr probe_result,
       const base::circular_deque<std::unique_ptr<SampledData>>& samples) {
     namespace cros_healthd = chromeos::cros_healthd::mojom;
@@ -1411,6 +1414,73 @@
         }
       }
     }
+
+    // Process Bus Result.
+    const auto& bus_result = probe_result->bus_result;
+    if (!bus_result.is_null() && report_network_configuration) {
+      switch (bus_result->which()) {
+        case cros_healthd::BusResult::Tag::ERROR: {
+          LOG(ERROR) << "cros_healthd: Error getting Bus info: "
+                     << bus_result->get_error()->msg;
+          break;
+        }
+
+        case cros_healthd::BusResult::Tag::BUS_DEVICES: {
+          for (const auto& bus_device : bus_result->get_bus_devices()) {
+            switch (bus_device->device_class) {
+              case cros_healthd::BusDeviceClass::kEthernetController:
+              case cros_healthd::BusDeviceClass::kWirelessController:
+              case cros_healthd::BusDeviceClass::kBluetoothAdapter: {
+                em::NetworkAdapterInfo* network_adapter_info_out =
+                    response_params_.device_status->add_network_adapter_info();
+                network_adapter_info_out->set_vendor_name(
+                    bus_device->vendor_name);
+                network_adapter_info_out->set_device_name(
+                    bus_device->product_name);
+                network_adapter_info_out->set_device_class(
+                    static_cast<em::BusDeviceClass>(bus_device->device_class));
+
+                if (bus_device->bus_info->is_pci_bus_info()) {
+                  network_adapter_info_out->set_bus_type(em::PCI_BUS);
+                  network_adapter_info_out->set_vendor_id(
+                      bus_device->bus_info->get_pci_bus_info()->vendor_id);
+                  network_adapter_info_out->set_device_id(
+                      bus_device->bus_info->get_pci_bus_info()->device_id);
+                  if (bus_device->bus_info->get_pci_bus_info()
+                          ->driver.has_value()) {
+                    network_adapter_info_out->add_driver(
+                        bus_device->bus_info->get_pci_bus_info()
+                            ->driver.value());
+                  }
+                }
+                if (bus_device->bus_info->is_usb_bus_info()) {
+                  network_adapter_info_out->set_bus_type(em::USB_BUS);
+                  network_adapter_info_out->set_vendor_id(
+                      bus_device->bus_info->get_usb_bus_info()->vendor_id);
+                  network_adapter_info_out->set_device_id(
+                      bus_device->bus_info->get_usb_bus_info()->product_id);
+                  for (const auto& usb_interface :
+                       bus_device->bus_info->get_usb_bus_info()->interfaces) {
+                    if (usb_interface->driver.has_value()) {
+                      network_adapter_info_out->add_driver(
+                          usb_interface->driver.value());
+                    }
+                  }
+                }
+
+                break;
+              }
+              default:
+                break;
+            }
+          }
+          if (response_params_.device_status->network_adapter_info_size() > 0) {
+            SetDeviceStatusReported();
+          }
+          break;
+        }
+      }
+    }
   }
 
   void OnEMMCLifetimeReceived(const em::DiskLifetimeEstimation& est) {
@@ -2097,6 +2167,8 @@
         categories_to_probe.push_back(ProbeCategoryEnum::kBluetooth);
       if (report_version_info_)
         categories_to_probe.push_back(ProbeCategoryEnum::kTpm);
+      if (report_network_configuration_)
+        categories_to_probe.push_back(ProbeCategoryEnum::kBus);
 
       completion_callback =
           base::BindOnce(&DeviceStatusCollector::OnProbeDataFetched,
@@ -2130,7 +2202,8 @@
   return report_vpd_info_ || report_power_status_ || report_storage_status_ ||
          report_cpu_info_ || report_timezone_info_ || report_memory_info_ ||
          report_backlight_info_ || report_fan_info_ || report_bluetooth_info_ ||
-         report_system_info_;
+         report_system_info_ || report_version_info_ ||
+         report_network_configuration_;
 }
 
 void DeviceStatusCollector::ReportingUsersChanged() {
@@ -2710,7 +2783,8 @@
   if (ShouldFetchCrosHealthdData())
     state->FetchCrosHealthdData(cros_healthd_data_fetcher_, report_system_info_,
                                 report_vpd_info_, report_storage_status_,
-                                report_version_info_);
+                                report_version_info_,
+                                report_network_configuration_);
 
   if (report_storage_status_) {
     state->FetchStatefulPartitionInfo(stateful_partition_info_fetcher_);
@@ -2891,7 +2965,6 @@
   std::string user_email = GetUserForActivityReporting();
   return !user_email.empty() && !IsDeviceLocalAccountUser(user_email, NULL);
 }
-// TODO(b/192252043): Remove this once management ui has been refactored.
 bool DeviceStatusCollector::IsReportingNetworkData() const {
   return report_network_configuration_ || report_network_status_;
 }
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector.h b/chrome/browser/ash/policy/status_collector/device_status_collector.h
index 1285808..78d32ab5 100644
--- a/chrome/browser/ash/policy/status_collector/device_status_collector.h
+++ b/chrome/browser/ash/policy/status_collector/device_status_collector.h
@@ -15,7 +15,6 @@
 
 #include "base/callback_forward.h"
 #include "base/callback_list.h"
-#include "base/compiler_specific.h"
 #include "base/containers/circular_deque.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
index bb046db..3229090a5 100644
--- a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
+++ b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
@@ -258,6 +258,17 @@
 constexpr uint32_t kFakeNumConnectedBluetoothDevices = 7;
 // Tpm test values:
 constexpr char kFakeTpmDidVid[] = "fake_tpm_did_vid";
+// Bus Device test values:
+constexpr uint8_t kFakeUnusedBusId = 1;
+constexpr char kFakePciVendor[] = "pci_vendor";
+constexpr char kFakePciProduct[] = "pci_product";
+constexpr char kFakePciDriver[] = "pci_driver";
+constexpr char kFakeUsbVendor[] = "usb_vendor";
+constexpr char kFakeUsbProduct[] = "usb_product";
+constexpr char kFakeUsbDriver0[] = "usb_driver_1";
+constexpr char kFakeUsbDriver1[] = "usb_driver_2";
+constexpr uint8_t kFakeUsbInterfaceNumber0 = 0;
+constexpr uint8_t kFakeUsbInterfaceNumber1 = 1;
 
 // Time delta representing 1 hour time interval.
 constexpr base::TimeDelta kHour = base::Hours(1);
@@ -689,6 +700,54 @@
       nullptr, nullptr, nullptr, nullptr, nullptr, nullptr));
 }
 
+cros_healthd::BusResultPtr CreateBusResult() {
+  std::vector<cros_healthd::BusDevicePtr> bus_devices;
+  // pci bus device
+  cros_healthd::PciBusInfoPtr pci_bus_info;
+  pci_bus_info = cros_healthd::PciBusInfo::New(kFakeUnusedBusId,  // class_id
+                                               kFakeUnusedBusId,  // subclass_id
+                                               kFakeUnusedBusId,  // prog_if_id
+                                               kFakeUnusedBusId,  // vendor_id
+                                               kFakeUnusedBusId,  // device_id
+                                               kFakePciDriver     // driver
+  );
+  bus_devices.push_back(cros_healthd::BusDevice::New(
+      kFakePciVendor,                                     // vendor_name
+      kFakePciProduct,                                    // product_name
+      cros_healthd::BusDeviceClass::kEthernetController,  // device_class
+      cros_healthd::BusInfo::NewPciBusInfo(std::move(pci_bus_info))));
+
+  // usb bus device
+  std::vector<cros_healthd::UsbBusInterfaceInfoPtr> usb_interfaces;
+  usb_interfaces.push_back(cros_healthd::UsbBusInterfaceInfo::New(
+      kFakeUsbInterfaceNumber0,  // interface_number
+      kFakeUnusedBusId,          // class_id
+      kFakeUnusedBusId,          // subclass_id
+      kFakeUnusedBusId,          // protocol_id
+      kFakeUsbDriver0            // driver
+      ));
+  usb_interfaces.push_back(cros_healthd::UsbBusInterfaceInfo::New(
+      kFakeUsbInterfaceNumber1,  // interface_number
+      kFakeUnusedBusId,          // class_id
+      kFakeUnusedBusId,          // subclass_id
+      kFakeUnusedBusId,          // protocol_id
+      kFakeUsbDriver1            // driver
+      ));
+  cros_healthd::UsbBusInfoPtr usb_bus_info;
+  usb_bus_info = cros_healthd::UsbBusInfo::New(kFakeUnusedBusId,  // class_id
+                                               kFakeUnusedBusId,  // subclass_id
+                                               kFakeUnusedBusId,  // protocol_id
+                                               kFakeUnusedBusId,  // vendor_id
+                                               kFakeUnusedBusId,  // product_id
+                                               std::move(usb_interfaces));
+  bus_devices.push_back(cros_healthd::BusDevice::New(
+      kFakeUsbVendor,                                     // vendor_name
+      kFakeUsbProduct,                                    // product_name
+      cros_healthd::BusDeviceClass::kWirelessController,  // device_class
+      cros_healthd::BusInfo::NewUsbBusInfo(std::move(usb_bus_info))));
+  return cros_healthd::BusResult::NewBusDevices(std::move(bus_devices));
+}
+
 base::circular_deque<std::unique_ptr<policy::SampledData>>
 CreateFakeSampleData() {
   em::CPUTempInfo fake_cpu_temp_sample;
@@ -747,6 +806,7 @@
       fake_info.stateful_partition_result = CreateStatefulPartitionResult();
       fake_info.bluetooth_result = CreateBluetoothResult();
       fake_info.tpm_result = CreateTpmResult();
+      fake_info.bus_result = CreateBusResult();
       std::move(receiver).Run(fake_info.Clone(), CreateFakeSampleData());
       return;
     }
@@ -3394,6 +3454,7 @@
   EXPECT_EQ(device_status_.fan_info_size(), 0);
   EXPECT_EQ(device_status_.bluetooth_adapter_info_size(), 0);
   EXPECT_FALSE(device_status_.has_tpm_version_info());
+  EXPECT_EQ(device_status_.network_adapter_info_size(), 0);
 
   // When all of the relevant policies are set to true, expect the protobuf to
   // have the corresponding data from cros_healthd.
@@ -3763,7 +3824,9 @@
   auto instance = std::make_unique<apps::Instance>(
       "id", apps::Instance::InstanceKey::ForWindowBasedApp(window.get()));
   instance->UpdateState(apps::InstanceState::kStarted, start_time);
-  app_proxy->InstanceRegistry().OnInstance(std::move(instance));
+  std::vector<std::unique_ptr<apps::Instance>> deltas;
+  deltas.push_back(std::move(instance));
+  app_proxy->InstanceRegistry().OnInstances(std::move(deltas));
 
   base::Time report_time;
   EXPECT_TRUE(base::Time::FromString("30-MAR-2020 2:30pm", &report_time));
@@ -4176,6 +4239,41 @@
   VerifyReporting();
 }
 
+TEST_F(DeviceStatusCollectorNetworkInterfacesTest, TestCrosHealthdBusInfo) {
+  // Create a fake response from cros_healthd and populate it with some
+  // test values.
+  // Because this data collection is gated by the
+  // kReportDeviceNetworkConfiguration policy, this test uses the
+  // DeviceStatusCollectorNetworkInterfacesTest class.
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->cros_healthd_data_fetcher =
+      base::BindRepeating(&FetchFakeFullCrosHealthdData);
+  RestartStatusCollector(std::move(options));
+  GetStatus();
+
+  // Verify the Network Adapter (bus device) info.
+  ASSERT_EQ(device_status_.network_adapter_info_size(), 2);
+  // Verify the PCI device.
+  const auto& network_adapter_0 = device_status_.network_adapter_info(0);
+  EXPECT_EQ(network_adapter_0.vendor_name(), kFakePciVendor);
+  EXPECT_EQ(network_adapter_0.device_name(), kFakePciProduct);
+  EXPECT_EQ(network_adapter_0.device_class(), em::ETHERNET_CONTROLLER);
+  EXPECT_EQ(network_adapter_0.bus_type(), em::PCI_BUS);
+  EXPECT_EQ(network_adapter_0.driver_size(), 1);
+  EXPECT_EQ(network_adapter_0.driver(0), kFakePciDriver);
+  // Verify the USB device.
+  const auto& network_adapter_1 = device_status_.network_adapter_info(1);
+  EXPECT_EQ(network_adapter_1.vendor_name(), kFakeUsbVendor);
+  EXPECT_EQ(network_adapter_1.device_name(), kFakeUsbProduct);
+  EXPECT_EQ(network_adapter_1.device_class(), em::WIRELESS_CONTROLLER);
+  EXPECT_EQ(network_adapter_1.bus_type(), em::USB_BUS);
+  EXPECT_EQ(network_adapter_1.driver_size(), 2);
+  EXPECT_EQ(network_adapter_1.driver(kFakeUsbInterfaceNumber0),
+            kFakeUsbDriver0);
+  EXPECT_EQ(network_adapter_1.driver(kFakeUsbInterfaceNumber1),
+            kFakeUsbDriver1);
+}
+
 class DeviceStatusCollectorNetworkStateTest
     : public DeviceStatusCollectorNetworkTest {
  protected:
diff --git a/chrome/browser/ash/policy/status_collector/legacy_device_status_collector.h b/chrome/browser/ash/policy/status_collector/legacy_device_status_collector.h
index d1b38a8..4eb15e1 100644
--- a/chrome/browser/ash/policy/status_collector/legacy_device_status_collector.h
+++ b/chrome/browser/ash/policy/status_collector/legacy_device_status_collector.h
@@ -15,7 +15,6 @@
 
 #include "base/callback_forward.h"
 #include "base/callback_list.h"
-#include "base/compiler_specific.h"
 #include "base/containers/circular_deque.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/ash/policy/status_collector/legacy_device_status_collector_browsertest.cc b/chrome/browser/ash/policy/status_collector/legacy_device_status_collector_browsertest.cc
index 0cf9750c..312d567 100644
--- a/chrome/browser/ash/policy/status_collector/legacy_device_status_collector_browsertest.cc
+++ b/chrome/browser/ash/policy/status_collector/legacy_device_status_collector_browsertest.cc
@@ -3771,7 +3771,9 @@
   auto instance = std::make_unique<apps::Instance>(
       "id", apps::Instance::InstanceKey::ForWindowBasedApp(window.get()));
   instance->UpdateState(apps::InstanceState::kStarted, start_time);
-  app_proxy->InstanceRegistry().OnInstance(std::move(instance));
+  std::vector<std::unique_ptr<apps::Instance>> deltas;
+  deltas.push_back(std::move(instance));
+  app_proxy->InstanceRegistry().OnInstances(std::move(deltas));
 
   base::Time report_time;
   EXPECT_TRUE(base::Time::FromString("30-MAR-2020 2:30pm", &report_time));
diff --git a/chrome/browser/ash/power/idle_action_warning_dialog_view.h b/chrome/browser/ash/power/idle_action_warning_dialog_view.h
index 8fe740d4..f1c3601 100644
--- a/chrome/browser/ash/power/idle_action_warning_dialog_view.h
+++ b/chrome/browser/ash/power/idle_action_warning_dialog_view.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_POWER_IDLE_ACTION_WARNING_DIALOG_VIEW_H_
 #define CHROME_BROWSER_ASH_POWER_IDLE_ACTION_WARNING_DIALOG_VIEW_H_
 
-#include "base/compiler_specific.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "ui/base/metadata/metadata_header_macros.h"
diff --git a/chrome/browser/ash/power/idle_action_warning_observer.h b/chrome/browser/ash/power/idle_action_warning_observer.h
index 94f75d8..a8148700 100644
--- a/chrome/browser/ash/power/idle_action_warning_observer.h
+++ b/chrome/browser/ash/power/idle_action_warning_observer.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_POWER_IDLE_ACTION_WARNING_OBSERVER_H_
 #define CHROME_BROWSER_ASH_POWER_IDLE_ACTION_WARNING_OBSERVER_H_
 
-#include "base/compiler_specific.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "ui/views/widget/widget_observer.h"
 
diff --git a/chrome/browser/ash/power/power_data_collector.h b/chrome/browser/ash/power/power_data_collector.h
index e1415ef..07a87b5 100644
--- a/chrome/browser/ash/power/power_data_collector.h
+++ b/chrome/browser/ash/power/power_data_collector.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_POWER_POWER_DATA_COLLECTOR_H_
 #define CHROME_BROWSER_ASH_POWER_POWER_DATA_COLLECTOR_H_
 
-#include "base/compiler_specific.h"
 #include "base/containers/circular_deque.h"
 #include "base/time/time.h"
 #include "chrome/browser/ash/power/cpu_data_collector.h"
diff --git a/chrome/browser/ash/remote_apps/remote_apps_manager_factory.cc b/chrome/browser/ash/remote_apps/remote_apps_manager_factory.cc
index bafbe9e..d681f19 100644
--- a/chrome/browser/ash/remote_apps/remote_apps_manager_factory.cc
+++ b/chrome/browser/ash/remote_apps/remote_apps_manager_factory.cc
@@ -24,8 +24,9 @@
 
 // static
 RemoteAppsManagerFactory* RemoteAppsManagerFactory::GetInstance() {
-  static base::NoDestructor<RemoteAppsManagerFactory> instance;
-  return instance.get();
+  // TODO(crbug.com/1269752): Restore use of base::NoDestructor when
+  // it no longer causes unit_test failures.
+  return base::Singleton<RemoteAppsManagerFactory>::get();
 }
 
 RemoteAppsManagerFactory::RemoteAppsManagerFactory()
diff --git a/chrome/browser/ash/remote_apps/remote_apps_manager_factory.h b/chrome/browser/ash/remote_apps/remote_apps_manager_factory.h
index feb3e20..5b689f8 100644
--- a/chrome/browser/ash/remote_apps/remote_apps_manager_factory.h
+++ b/chrome/browser/ash/remote_apps/remote_apps_manager_factory.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_ASH_REMOTE_APPS_REMOTE_APPS_MANAGER_FACTORY_H_
 #define CHROME_BROWSER_ASH_REMOTE_APPS_REMOTE_APPS_MANAGER_FACTORY_H_
 
-#include "base/no_destructor.h"
+#include "base/memory/singleton.h"
 #include "chrome/browser/ash/remote_apps/remote_apps_manager.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
@@ -27,7 +27,7 @@
   static RemoteAppsManagerFactory* GetInstance();
 
  private:
-  friend base::NoDestructor<RemoteAppsManagerFactory>;
+  friend struct base::DefaultSingletonTraits<RemoteAppsManagerFactory>;
 
   RemoteAppsManagerFactory();
   RemoteAppsManagerFactory(const RemoteAppsManagerFactory&) = delete;
diff --git a/chrome/browser/ash/session_length_limiter.h b/chrome/browser/ash/session_length_limiter.h
index cfd50ad..2a4be08 100644
--- a/chrome/browser/ash/session_length_limiter.h
+++ b/chrome/browser/ash/session_length_limiter.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/clock.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/ash/settings/about_flags.h b/chrome/browser/ash/settings/about_flags.h
index 016cb96..c404066 100644
--- a/chrome/browser/ash/settings/about_flags.h
+++ b/chrome/browser/ash/settings/about_flags.h
@@ -7,7 +7,6 @@
 
 #include <map>
 
-#include "base/compiler_specific.h"
 #include "components/flags_ui/pref_service_flags_storage.h"
 
 class PrefService;
diff --git a/chrome/browser/ash/settings/device_settings_service.h b/chrome/browser/ash/settings/device_settings_service.h
index 15826c3a..5289425 100644
--- a/chrome/browser/ash/settings/device_settings_service.h
+++ b/chrome/browser/ash/settings/device_settings_service.h
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/containers/circular_deque.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
diff --git a/chrome/browser/ash/settings/device_settings_test_helper.h b/chrome/browser/ash/settings/device_settings_test_helper.h
index 76cc5ec..fb2321f 100644
--- a/chrome/browser/ash/settings/device_settings_test_helper.h
+++ b/chrome/browser/ash/settings/device_settings_test_helper.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_util.h"
 #include "base/test/task_environment.h"
diff --git a/chrome/browser/ash/shimless_rma/OWNERS b/chrome/browser/ash/shimless_rma/OWNERS
new file mode 100644
index 0000000..a64b0d66
--- /dev/null
+++ b/chrome/browser/ash/shimless_rma/OWNERS
@@ -0,0 +1 @@
+file://ash/webui/shimless_rma/OWNERS
diff --git a/chrome/browser/ash/shimless_rma/chrome_shimless_rma_delegate.cc b/chrome/browser/ash/shimless_rma/chrome_shimless_rma_delegate.cc
new file mode 100644
index 0000000..a47d935
--- /dev/null
+++ b/chrome/browser/ash/shimless_rma/chrome_shimless_rma_delegate.cc
@@ -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.
+
+#include "chrome/browser/ash/shimless_rma/chrome_shimless_rma_delegate.h"
+
+#include "base/command_line.h"
+#include "chrome/browser/ash/login/chrome_restart_request.h"
+
+namespace ash {
+namespace shimless_rma {
+
+ChromeShimlessRmaDelegate::ChromeShimlessRmaDelegate() = default;
+ChromeShimlessRmaDelegate::~ChromeShimlessRmaDelegate() = default;
+
+void ChromeShimlessRmaDelegate::RestartChrome() {
+  // TODO(gavinwill): Add the option to pass the --no-rma flag when implemented.
+  ash::RestartChrome(*base::CommandLine::ForCurrentProcess(),
+                     ash::RestartChromeReason::kUserless);
+}
+
+}  // namespace shimless_rma
+}  // namespace ash
diff --git a/chrome/browser/ash/shimless_rma/chrome_shimless_rma_delegate.h b/chrome/browser/ash/shimless_rma/chrome_shimless_rma_delegate.h
new file mode 100644
index 0000000..61ccfa1d1
--- /dev/null
+++ b/chrome/browser/ash/shimless_rma/chrome_shimless_rma_delegate.h
@@ -0,0 +1,30 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_SHIMLESS_RMA_CHROME_SHIMLESS_RMA_DELEGATE_H_
+#define CHROME_BROWSER_ASH_SHIMLESS_RMA_CHROME_SHIMLESS_RMA_DELEGATE_H_
+
+#include "ash/webui/shimless_rma/backend/shimless_rma_delegate.h"
+
+namespace ash {
+namespace shimless_rma {
+
+class ChromeShimlessRmaDelegate : public ShimlessRmaDelegate {
+ public:
+  ChromeShimlessRmaDelegate();
+
+  ChromeShimlessRmaDelegate(const ChromeShimlessRmaDelegate&) = delete;
+  ChromeShimlessRmaDelegate& operator=(const ChromeShimlessRmaDelegate&) =
+      delete;
+
+  ~ChromeShimlessRmaDelegate() override;
+
+  // ShimlessRmaDelegate:
+  void RestartChrome() override;
+};
+
+}  // namespace shimless_rma
+}  // namespace ash
+
+#endif  // CHROME_BROWSER_ASH_SHIMLESS_RMA_CHROME_SHIMLESS_RMA_DELEGATE_H_
diff --git a/chrome/browser/ash/system/automatic_reboot_manager.h b/chrome/browser/ash/system/automatic_reboot_manager.h
index b331d68..bfbea53 100644
--- a/chrome/browser/ash/system/automatic_reboot_manager.h
+++ b/chrome/browser/ash/system/automatic_reboot_manager.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/scoped_observation.h"
diff --git a/chrome/browser/ash/system/fake_input_device_settings.h b/chrome/browser/ash/system/fake_input_device_settings.h
index 8f04761a..f31f1974 100644
--- a/chrome/browser/ash/system/fake_input_device_settings.h
+++ b/chrome/browser/ash/system/fake_input_device_settings.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_SYSTEM_FAKE_INPUT_DEVICE_SETTINGS_H_
 #define CHROME_BROWSER_ASH_SYSTEM_FAKE_INPUT_DEVICE_SETTINGS_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/system/input_device_settings.h"
 
 namespace ash {
diff --git a/chrome/browser/ash/web_applications/media_app/chrome_media_app_ui_delegate.cc b/chrome/browser/ash/web_applications/media_app/chrome_media_app_ui_delegate.cc
index 69caf43c..8d44db4 100644
--- a/chrome/browser/ash/web_applications/media_app/chrome_media_app_ui_delegate.cc
+++ b/chrome/browser/ash/web_applications/media_app/chrome_media_app_ui_delegate.cc
@@ -8,9 +8,12 @@
 #include "ash/webui/media_app_ui/url_constants.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/common/channel_info.h"
 #include "components/version_info/channel.h"
+#include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "url/gurl.h"
 
@@ -36,3 +39,11 @@
   // back to the client with an error string. For now assume dialog opened.
   return absl::nullopt;
 }
+
+void ChromeMediaAppUIDelegate::ToggleBrowserFullscreenMode() {
+  Browser* browser =
+      chrome::FindBrowserWithWebContents(web_ui_->GetWebContents());
+  if (browser) {
+    chrome::ToggleFullscreenMode(browser);
+  }
+}
diff --git a/chrome/browser/ash/web_applications/media_app/chrome_media_app_ui_delegate.h b/chrome/browser/ash/web_applications/media_app/chrome_media_app_ui_delegate.h
index 0e1b7611..8ebea56c 100644
--- a/chrome/browser/ash/web_applications/media_app/chrome_media_app_ui_delegate.h
+++ b/chrome/browser/ash/web_applications/media_app/chrome_media_app_ui_delegate.h
@@ -25,6 +25,7 @@
 
   // MediaAppUIDelegate:
   absl::optional<std::string> OpenFeedbackDialog() override;
+  void ToggleBrowserFullscreenMode() override;
 
  private:
   content::WebUI* web_ui_;  // Owns |this|.
diff --git a/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
index caa6b4fa..f44f69a 100644
--- a/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
+++ b/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_list_observer.h"
+#include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h"
 #include "chrome/browser/web_applications/system_web_apps/system_web_app_manager.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
@@ -208,6 +209,17 @@
       web_ui, base::ReplaceStringPlaceholders(kScript, {alt}, nullptr));
 }
 
+// Runs the provided `script` in a non-isolated JS world that can access
+// variables defined in global scope (otherwise only DOM queries are allowed).
+// The script must call `domAutomationController.send(result)` to return.
+std::string ExtractStringInGlobalScope(content::WebContents* web_ui,
+                                       const std::string& script) {
+  std::string result;
+  content::RenderFrameHost* app = MediaAppUiBrowserTest::GetAppFrame(web_ui);
+  EXPECT_TRUE(content::ExecuteScriptAndExtractString(app, script, &result));
+  return result;
+}
+
 // Waits for the "shownav" attribute to show up in the MediaApp's current
 // handler. Also checks the panel isn't open indicating an edit is not in
 // progress. This prevents trying to traverse a directory before other files are
@@ -1143,18 +1155,15 @@
   folder.Open(reserved_file);
 
   content::WebContents* web_ui = PrepareActiveBrowserForTest();
-  content::RenderFrameHost* app = MediaAppUiBrowserTest::GetAppFrame(web_ui);
 
   EXPECT_EQ("640x480", WaitForImageAlt(web_ui, "thumbs.db"));
 
-  std::string result;
   constexpr char kScript[] =
       "lastLoadedReceivedFileList().item(0).deleteOriginalFile()"
       ".then(() => domAutomationController.send('bad-success'))"
       ".catch(e => domAutomationController.send(e.name));";
-  EXPECT_EQ(true,
-            content::ExecuteScriptAndExtractString(app, kScript, &result));
-  EXPECT_EQ("InvalidModificationError", result);
+  EXPECT_EQ("InvalidModificationError",
+            ExtractStringInGlobalScope(web_ui, kScript));
 
   // The file should still be there.
   folder.Refresh();
@@ -1162,6 +1171,26 @@
   EXPECT_EQ("thumbs.db", folder.files()[0].BaseName().value());
 }
 
+IN_PROC_BROWSER_TEST_P(MediaAppIntegrationTest, ToggleBrowserFullscreen) {
+  content::WebContents* web_ui = LaunchWithOneTestFile(kFileVideoVP9);
+  Browser* app_browser = chrome::FindBrowserWithActiveWindow();
+
+  constexpr char kToggleFullscreen[] = R"(
+      (async function toggleFullscreen() {
+        await customLaunchData.delegate.toggleBrowserFullscreenMode();
+        domAutomationController.send("success");
+      })();
+  )";
+
+  EXPECT_FALSE(app_browser->window()->IsFullscreen());
+
+  EXPECT_EQ("success", ExtractStringInGlobalScope(web_ui, kToggleFullscreen));
+  EXPECT_TRUE(app_browser->window()->IsFullscreen());
+
+  EXPECT_EQ("success", ExtractStringInGlobalScope(web_ui, kToggleFullscreen));
+  EXPECT_FALSE(app_browser->window()->IsFullscreen());
+}
+
 INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_REGULAR_PROFILE_P(
     MediaAppIntegrationAudioEnabledTest);
 
diff --git a/chrome/browser/ash/web_applications/terminal_system_web_app_info.cc b/chrome/browser/ash/web_applications/terminal_system_web_app_info.cc
index e1f96241..7692387a 100644
--- a/chrome/browser/ash/web_applications/terminal_system_web_app_info.cc
+++ b/chrome/browser/ash/web_applications/terminal_system_web_app_info.cc
@@ -16,6 +16,7 @@
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/generated_resources.h"
+#include "extensions/browser/api/file_handlers/mime_util.h"
 #include "extensions/common/constants.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -33,7 +34,8 @@
 std::unique_ptr<WebApplicationInfo> CreateWebAppInfoForTerminalSystemWebApp() {
   auto info = std::make_unique<WebApplicationInfo>();
   // URL used for crostini::kCrostiniTerminalSystemAppId.
-  info->start_url = GURL("chrome-untrusted://terminal/html/terminal.html");
+  const GURL terminal_url("chrome-untrusted://terminal/html/terminal.html");
+  info->start_url = terminal_url;
   info->scope = GURL(chrome::kChromeUIUntrustedTerminalURL);
   info->title = l10n_util::GetStringUTF16(IDS_CROSTINI_TERMINAL_APP_NAME);
   web_app::CreateIconInfoForSystemWebApp(
@@ -41,6 +43,30 @@
       *info);
   info->background_color = 0xFF202124;
   info->display_mode = blink::mojom::DisplayMode::kStandalone;
+  {
+    apps::FileHandler handler;
+    handler.accept.emplace_back();
+    handler.accept.back().mime_type =
+        extensions::app_file_handler_util::kMimeTypeInodeDirectory;
+    info->file_handlers.push_back(std::move(handler));
+  }
+  info->additional_search_terms = {
+      "linux", "terminal", "crostini", "ssh",
+      l10n_util::GetStringUTF8(IDS_CROSTINI_TERMINAL_APP_SEARCH_TERMS)};
+  {
+    WebApplicationShortcutsMenuItemInfo shortcut_terminal;
+    shortcut_terminal.name =
+        l10n_util::GetStringUTF16(IDS_CROSTINI_TERMINAL_CONNECT_TO_LINUX);
+    shortcut_terminal.url = terminal_url;
+    info->shortcuts_menu_item_infos.push_back(std::move(shortcut_terminal));
+  }
+  {
+    WebApplicationShortcutsMenuItemInfo shortcut_ssh;
+    shortcut_ssh.name =
+        l10n_util::GetStringUTF16(IDS_CROSTINI_TERMINAL_CONNECT_TO_SSH);
+    shortcut_ssh.url = GURL("chrome-untrusted://terminal/html/nassh.html");
+    info->shortcuts_menu_item_infos.push_back(std::move(shortcut_ssh));
+  }
   return info;
 }
 
@@ -68,6 +94,11 @@
 bool TerminalSystemAppDelegate::ShouldReuseExistingWindow() const {
   return false;
 }
+
+bool TerminalSystemAppDelegate::ShouldShowNewWindowMenuOption() const {
+  return true;
+}
+
 bool TerminalSystemAppDelegate::ShouldHaveTabStrip() const {
   return true;
 }
diff --git a/chrome/browser/ash/web_applications/terminal_system_web_app_info.h b/chrome/browser/ash/web_applications/terminal_system_web_app_info.h
index 4ec8e61..37e7985 100644
--- a/chrome/browser/ash/web_applications/terminal_system_web_app_info.h
+++ b/chrome/browser/ash/web_applications/terminal_system_web_app_info.h
@@ -22,6 +22,7 @@
   // web_app::SystemWebAppDelegate overrides:
   std::unique_ptr<WebApplicationInfo> GetWebAppInfo() const override;
   bool ShouldReuseExistingWindow() const override;
+  bool ShouldShowNewWindowMenuOption() const override;
   bool ShouldHaveTabStrip() const override;
   bool HasTitlebarTerminalSelectNewTabButton() const override;
   gfx::Rect GetDefaultBounds(Browser* browser) const override;
diff --git a/chrome/browser/autocomplete/keyword_extensions_delegate_impl.h b/chrome/browser/autocomplete/keyword_extensions_delegate_impl.h
index d0d5a906..8d8a7794 100644
--- a/chrome/browser/autocomplete/keyword_extensions_delegate_impl.h
+++ b/chrome/browser/autocomplete/keyword_extensions_delegate_impl.h
@@ -10,7 +10,6 @@
 
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/autocomplete_provider_listener.h"
diff --git a/chrome/browser/autofill/autocomplete_history_manager_factory.h b/chrome/browser/autofill/autocomplete_history_manager_factory.h
index eca91420..29f6475b 100644
--- a/chrome/browser/autofill/autocomplete_history_manager_factory.h
+++ b/chrome/browser/autofill/autocomplete_history_manager_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_AUTOFILL_AUTOCOMPLETE_HISTORY_MANAGER_FACTORY_H_
 #define CHROME_BROWSER_AUTOFILL_AUTOCOMPLETE_HISTORY_MANAGER_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 #include "components/keyed_service/core/keyed_service.h"
 
diff --git a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
index 9be0145..51738273 100644
--- a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
@@ -270,15 +270,19 @@
     // First, automation should focus on the frame containg the autofill form.
     // Doing so ensures that Chrome scrolls the element into view if the
     // element is off the page.
+    test_delegate()->SetExpectations({ObservedUiEvents::kSuggestionShown},
+                                     autofill_wait_for_action_interval);
     if (!captured_sites_test_utils::TestRecipeReplayer::PlaceFocusOnElement(
-            target_element_xpath, iframe_path, frame))
+            target_element_xpath, iframe_path, frame)) {
       return false;
+    }
 
     gfx::Rect rect;
     if (!captured_sites_test_utils::TestRecipeReplayer::
             GetBoundingRectOfTargetElement(target_element_xpath, iframe_path,
-                                           frame, &rect))
+                                           frame, &rect)) {
       return false;
+    }
 
     test_delegate()->SetExpectations({ObservedUiEvents::kSuggestionShown},
                                      autofill_wait_for_action_interval);
diff --git a/chrome/browser/autofill/autofill_offer_manager_factory.h b/chrome/browser/autofill/autofill_offer_manager_factory.h
index 31e9c034..1af610b 100644
--- a/chrome/browser/autofill/autofill_offer_manager_factory.h
+++ b/chrome/browser/autofill/autofill_offer_manager_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_OFFER_MANAGER_FACTORY_H_
 #define CHROME_BROWSER_AUTOFILL_AUTOFILL_OFFER_MANAGER_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 #include "components/keyed_service/core/keyed_service.h"
 
diff --git a/chrome/browser/autofill/personal_data_manager_factory.h b/chrome/browser/autofill/personal_data_manager_factory.h
index 4f9108e..52ba0aa 100644
--- a/chrome/browser/autofill/personal_data_manager_factory.h
+++ b/chrome/browser/autofill/personal_data_manager_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_AUTOFILL_PERSONAL_DATA_MANAGER_FACTORY_H_
 #define CHROME_BROWSER_AUTOFILL_PERSONAL_DATA_MANAGER_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/autofill/autofill_profile_validator_factory.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 #include "components/keyed_service/core/keyed_service.h"
diff --git a/chrome/browser/autofill/strike_database_factory.h b/chrome/browser/autofill/strike_database_factory.h
index b7455e9..9bffc5c 100644
--- a/chrome/browser/autofill/strike_database_factory.h
+++ b/chrome/browser/autofill/strike_database_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_AUTOFILL_STRIKE_DATABASE_FACTORY_H_
 #define CHROME_BROWSER_AUTOFILL_STRIKE_DATABASE_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 #include "components/keyed_service/core/keyed_service.h"
 
diff --git a/chrome/browser/background/background_contents_service_factory.h b/chrome/browser/background/background_contents_service_factory.h
index 0bdc2ec..ddf5350d 100644
--- a/chrome/browser/background/background_contents_service_factory.h
+++ b/chrome/browser/background/background_contents_service_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_BACKGROUND_BACKGROUND_CONTENTS_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_BACKGROUND_BACKGROUND_CONTENTS_SERVICE_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/background_fetch/background_fetch_browsertest.cc b/chrome/browser/background_fetch/background_fetch_browsertest.cc
index 9b8b2e4..6b797a8 100644
--- a/chrome/browser/background_fetch/background_fetch_browsertest.cc
+++ b/chrome/browser/background_fetch/background_fetch_browsertest.cc
@@ -882,8 +882,9 @@
       "StartFetchFromServiceWorker()", "permissionerror"));
 }
 
+// TODO(crbug.com/1271962): Flaky on many platforms.
 IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest,
-                       FetchFromServiceWorkerWithAsk) {
+                       DISABLED_FetchFromServiceWorkerWithAsk) {
   auto* settings_map =
       HostContentSettingsMapFactory::GetForProfile(browser()->profile());
   DCHECK(settings_map);
@@ -899,8 +900,9 @@
             offline_items_collection::OfflineItemState::PAUSED);
 }
 
+// TODO(crbug.com/1271962): Flaky on many platforms.
 IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest,
-                       FetchFromChildFrameWithPermissions) {
+                       DISABLED_FetchFromChildFrameWithPermissions) {
   // Give the needed permissions. The fetch should still start in a paused
   // state.
   SetPermission(ContentSettingsType::AUTOMATIC_DOWNLOADS,
@@ -915,7 +917,9 @@
             offline_items_collection::OfflineItemState::PAUSED);
 }
 
-IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest, FetchFromChildFrameWithAsk) {
+// TODO(crbug.com/1271962): Flaky on many platforms.
+IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest,
+                       DISABLED_FetchFromChildFrameWithAsk) {
   SetPermission(ContentSettingsType::AUTOMATIC_DOWNLOADS, CONTENT_SETTING_ASK);
 
   // The fetch starts in a paused state.
diff --git a/chrome/browser/banners/app_banner_manager_browsertest.cc b/chrome/browser/banners/app_banner_manager_browsertest.cc
index 0fe60461..909401c7 100644
--- a/chrome/browser/banners/app_banner_manager_browsertest.cc
+++ b/chrome/browser/banners/app_banner_manager_browsertest.cc
@@ -833,8 +833,10 @@
   content::test::FencedFrameTestHelper fenced_frame_helper_;
 };
 
+// TODO(crbug.com/1270942): Re-enable this test once it works with
+// `FencedFrameTestHelper` again.
 IN_PROC_BROWSER_TEST_F(AppBannerManagerFencedFrameBrowserTest,
-                       FencedFrameShouldNotUpdateState) {
+                       DISABLED_FencedFrameShouldNotUpdateState) {
   // Navigate to an initial page.
   const GURL initial_url = embedded_test_server()->GetURL("/empty.html");
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), initial_url));
diff --git a/chrome/browser/banners/app_banner_manager_desktop.cc b/chrome/browser/banners/app_banner_manager_desktop.cc
index c3a1749..1e376c5 100644
--- a/chrome/browser/banners/app_banner_manager_desktop.cc
+++ b/chrome/browser/banners/app_banner_manager_desktop.cc
@@ -170,6 +170,13 @@
   if (!registrar().IsLocallyInstalled(app_id))
     return false;
 
+  // We prompt the user to re-install if the site wants to be in a standalone
+  // window but the user has opted for opening in browser tab. This is to
+  // support the situation where a site is not a PWA, users have installed it
+  // via Create Shortcut action, the site becomes a standalone PWA later and we
+  // want to prompt them to "install" the new PWA experience.
+  // TODO(crbug.com/1205529): Showing an install button when it's already
+  // installed is confusing.
   auto display_mode = registrar().GetAppUserDisplayMode(app_id);
   return display_mode == blink::mojom::DisplayMode::kBrowser;
 }
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h
index 972d5b8..2830385c 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h
@@ -8,7 +8,6 @@
 #include <vector>
 
 #include "base/callback_forward.h"
-#include "base/compiler_specific.h"
 #include "base/containers/lru_cache.h"
 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_delegate.h"
 #include "components/keyed_service/core/keyed_service.h"
diff --git a/chrome/browser/browser_process_platform_part_android.h b/chrome/browser/browser_process_platform_part_android.h
index 147ead3..9f644734 100644
--- a/chrome/browser/browser_process_platform_part_android.h
+++ b/chrome/browser/browser_process_platform_part_android.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_BROWSER_PROCESS_PLATFORM_PART_ANDROID_H_
 #define CHROME_BROWSER_BROWSER_PROCESS_PLATFORM_PART_ANDROID_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/browser_process_platform_part_base.h"
 
 class BrowserProcessPlatformPart : public BrowserProcessPlatformPartBase {
diff --git a/chrome/browser/browser_process_platform_part_chromeos.h b/chrome/browser/browser_process_platform_part_chromeos.h
index f7f1457..70e2772 100644
--- a/chrome/browser/browser_process_platform_part_chromeos.h
+++ b/chrome/browser/browser_process_platform_part_chromeos.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/sequence_checker.h"
 #include "chrome/browser/browser_process_platform_part_base.h"
 #include "chrome/browser/component_updater/cros_component_installer_chromeos.h"
diff --git a/chrome/browser/browser_process_platform_part_mac.h b/chrome/browser/browser_process_platform_part_mac.h
index 1ab597f..c957601c 100644
--- a/chrome/browser/browser_process_platform_part_mac.h
+++ b/chrome/browser/browser_process_platform_part_mac.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/apps/app_shim/app_shim_listener.h"
 #include "chrome/browser/browser_process_platform_part_base.h"
 #include "chrome/browser/mac/key_window_notifier.h"
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc
index 4f5abe47..c20c4fe 100644
--- a/chrome/browser/captive_portal/captive_portal_browsertest.cc
+++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -2825,8 +2825,9 @@
 // The second check finds no captive portal. The reloader triggers a reload at
 // the same time SSL error handler tries to show an interstitial. Should result
 // in an SSL interstitial.
+// TODO(crbug.com/1271739): Flaky on all platforms.
 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
-                       InterstitialTimerCertErrorAfterSlowLoad) {
+                       DISABLED_InterstitialTimerCertErrorAfterSlowLoad) {
   net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
 
   GURL cert_error_url;
diff --git a/chrome/browser/captive_portal/captive_portal_service_factory.h b/chrome/browser/captive_portal/captive_portal_service_factory.h
index 0a6cb80..4f3ed6e 100644
--- a/chrome/browser/captive_portal/captive_portal_service_factory.h
+++ b/chrome/browser/captive_portal/captive_portal_service_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_CAPTIVE_PORTAL_CAPTIVE_PORTAL_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_CAPTIVE_PORTAL_CAPTIVE_PORTAL_SERVICE_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/chrome_browser_main_linux.h b/chrome/browser/chrome_browser_main_linux.h
index 0121db2..a8fcedf 100644
--- a/chrome/browser/chrome_browser_main_linux.h
+++ b/chrome/browser/chrome_browser_main_linux.h
@@ -7,7 +7,6 @@
 #ifndef CHROME_BROWSER_CHROME_BROWSER_MAIN_LINUX_H_
 #define CHROME_BROWSER_CHROME_BROWSER_MAIN_LINUX_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/chrome_browser_main_posix.h"
 
 class ChromeBrowserMainPartsLinux : public ChromeBrowserMainPartsPosix {
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index fbda6f6..e0f50e0 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1481,13 +1481,6 @@
         /*in_memory=*/false);
   }
 
-  // The partition ID for webview guest processes is the string value of its
-  // SiteInstance URL - "chrome-guest://app_id/persist?partition".
-  if (extensions::WebViewGuest::GetGuestPartitionConfigForSite(
-          browser_context, site, &storage_partition_config)) {
-    return storage_partition_config;
-  }
-
   if (site.SchemeIs(extensions::kExtensionScheme)) {
     // The host in an extension site URL is the extension_id.
     CHECK(site.has_host());
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index d59bb5e..0008476 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -81,6 +81,7 @@
     "//ash",
     "//ash/components/account_manager",
     "//ash/components/arc/input_overlay/resources:resources_grit",
+    "//ash/components/attestation",
     "//ash/components/audio",
     "//ash/components/device_activity",
     "//ash/components/drivefs",
@@ -143,6 +144,7 @@
     "//ash/webui/scanning",
     "//ash/webui/scanning/mojom",
     "//ash/webui/shimless_rma",
+    "//ash/webui/shimless_rma/backend",
     "//ash/webui/shortcut_customization_ui",
     "//ash/webui/telemetry_extension_ui/mojom",
     "//base",
@@ -188,7 +190,6 @@
     "//chrome/services/wilco_dtc_supportd/public/mojom",
     "//chromeos",
     "//chromeos/assistant:buildflags",
-    "//chromeos/attestation",
     "//chromeos/components/cdm_factory_daemon:cdm_factory_daemon_browser",
     "//chromeos/components/chromebox_for_meetings/buildflags",
     "//chromeos/components/feature_usage",
@@ -199,6 +200,7 @@
     "//chromeos/components/multidevice/logging",
     "//chromeos/components/proximity_auth",
     "//chromeos/components/quick_answers",
+    "//chromeos/components/quick_answers/public/cpp:cpp",
     "//chromeos/components/quick_answers/public/cpp:prefs",
     "//chromeos/components/remote_apps/mojom",
     "//chromeos/components/sensors",
@@ -2006,8 +2008,8 @@
     "../ash/login/screens/welcome_screen.h",
     "../ash/login/screens/wrong_hwid_screen.cc",
     "../ash/login/screens/wrong_hwid_screen.h",
-    "../ash/login/security_token_pin_dialog_host_impl.cc",
-    "../ash/login/security_token_pin_dialog_host_impl.h",
+    "../ash/login/security_token_pin_dialog_host_login_impl.cc",
+    "../ash/login/security_token_pin_dialog_host_login_impl.h",
     "../ash/login/security_token_session_controller.cc",
     "../ash/login/security_token_session_controller.h",
     "../ash/login/security_token_session_controller_factory.cc",
@@ -2949,6 +2951,8 @@
     "../ash/sharesheet/copy_to_clipboard_share_action.h",
     "../ash/sharesheet/drive_share_action.cc",
     "../ash/sharesheet/drive_share_action.h",
+    "../ash/shimless_rma/chrome_shimless_rma_delegate.cc",
+    "../ash/shimless_rma/chrome_shimless_rma_delegate.h",
     "../ash/shortcut_mapping_pref_service.cc",
     "../ash/shortcut_mapping_pref_service.h",
     "../ash/smb_client/discovery/host_locator.h",
@@ -3774,6 +3778,7 @@
 
   deps = [
     ":chromeos",
+    "//ash/components/attestation:test_support",
     "//ash/components/drivefs",
     "//ash/components/drivefs:test_support",
     "//ash/components/settings",
@@ -3785,7 +3790,6 @@
     "//chrome/test:test_support",
     "//chrome/test:test_support_ui",
     "//chromeos",
-    "//chromeos/attestation:test_support",
     "//chromeos/cryptohome",
     "//chromeos/dbus:test_support",
     "//chromeos/dbus/chunneld",
@@ -4522,7 +4526,6 @@
     "../ash/wilco_dtc_supportd/wilco_dtc_supportd_messaging_unittest.cc",
     "../ash/wilco_dtc_supportd/wilco_dtc_supportd_notification_controller_unittest.cc",
     "../ash/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service_unittest.cc",
-    "../download/notification/download_item_notification_unittest.cc",
     "../download/notification/multi_profile_download_notifier_unittest.cc",
     "../extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc",
     "../extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc",
@@ -4646,6 +4649,7 @@
     "//ash:test_support",
     "//ash/components/arc:arc_test_support",
     "//ash/components/arc:notification_test_support",
+    "//ash/components/attestation:test_support",
     "//ash/components/audio",
     "//ash/components/phonehub:test_support",
     "//ash/components/settings",
@@ -4669,7 +4673,6 @@
     "//chrome/test:test_support_ui",
     "//chrome/test:test_support_unit",
     "//chromeos",
-    "//chromeos/attestation:test_support",
     "//chromeos/components/multidevice:test_support",
     "//chromeos/components/proximity_auth",
     "//chromeos/components/proximity_auth:test_support",
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
index 1b6b5c8..2b44def 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
@@ -12,7 +12,6 @@
 #include "ash/display/screen_orientation_controller.h"
 #include "ash/public/cpp/assistant/assistant_state.h"
 #include "ash/rotator/screen_rotation_animator_observer.h"
-#include "base/compiler_specific.h"
 #include "base/scoped_observation.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/chromeos/printing/cups_printers_manager.h"
diff --git a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h
index adfc376..306c3fa6 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h
+++ b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h
@@ -8,7 +8,6 @@
 #include <memory>
 
 #include "base/callback_forward.h"
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.h b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.h
index 92867188..134c65c 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.h
+++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/policy/core/device_local_account.h"
 #include "extensions/browser/management_policy.h"
 
diff --git a/chrome/browser/chromeos/extensions/dictionary_event_router.h b/chrome/browser/chromeos/extensions/dictionary_event_router.h
index b5e3fe2..3e4fa978 100644
--- a/chrome/browser/chromeos/extensions/dictionary_event_router.h
+++ b/chrome/browser/chromeos/extensions/dictionary_event_router.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_DICTIONARY_EVENT_ROUTER_H_
 #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_DICTIONARY_EVENT_ROUTER_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/spellchecker/spellcheck_custom_dictionary.h"
 #include "chrome/browser/spellchecker/spellcheck_service.h"
diff --git a/chrome/browser/chromeos/extensions/echo_private_api.h b/chrome/browser/chromeos/extensions/echo_private_api.h
index 063627ba..42334484 100644
--- a/chrome/browser/chromeos/extensions/echo_private_api.h
+++ b/chrome/browser/chromeos/extensions/echo_private_api.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/notifications/echo_dialog_listener.h"
 #include "extensions/browser/extension_function.h"
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.h b/chrome/browser/chromeos/extensions/file_manager/event_router.h
index 810a8b53..c2dbd036 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.h
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.h
@@ -14,7 +14,6 @@
 
 #include "ash/components/settings/timezone_settings.h"
 #include "ash/public/cpp/tablet_mode_observer.h"
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "chrome/browser/ash/drive/drive_integration_service.h"
 #include "chrome/browser/ash/file_manager/file_watcher.h"
diff --git a/chrome/browser/chromeos/extensions/info_private_api.h b/chrome/browser/chromeos/extensions/info_private_api.h
index c6096933..1e994ce 100644
--- a/chrome/browser/chromeos/extensions/info_private_api.h
+++ b/chrome/browser/chromeos/extensions/info_private_api.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "extensions/browser/extension_function.h"
 
 namespace base {
diff --git a/chrome/browser/chromeos/extensions/input_method_api.h b/chrome/browser/chromeos/extensions/input_method_api.h
index 26e97b98..b1c75c27 100644
--- a/chrome/browser/chromeos/extensions/input_method_api.h
+++ b/chrome/browser/chromeos/extensions/input_method_api.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "chrome/common/extensions/api/input_method_private.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
 #include "extensions/browser/event_router.h"
diff --git a/chrome/browser/chromeos/extensions/input_method_event_router.h b/chrome/browser/chromeos/extensions/input_method_event_router.h
index 37a697cb..11394bb7 100644
--- a/chrome/browser/chromeos/extensions/input_method_event_router.h
+++ b/chrome/browser/chromeos/extensions/input_method_event_router.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_INPUT_METHOD_EVENT_ROUTER_H_
 #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_INPUT_METHOD_EVENT_ROUTER_H_
 
-#include "base/compiler_specific.h"
 #include "ui/base/ime/ash/input_method_manager.h"
 
 namespace content {
diff --git a/chrome/browser/chromeos/extensions/install_limiter.h b/chrome/browser/chromeos/extensions/install_limiter.h
index bcc0199..2328951e 100644
--- a/chrome/browser/chromeos/extensions/install_limiter.h
+++ b/chrome/browser/chromeos/extensions/install_limiter.h
@@ -9,7 +9,6 @@
 
 #include <set>
 
-#include "base/compiler_specific.h"
 #include "base/containers/queue.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/chromeos/extensions/install_limiter_factory.h b/chrome/browser/chromeos/extensions/install_limiter_factory.h
index ee3e433ab..2e7acb1 100644
--- a/chrome/browser/chromeos/extensions/install_limiter_factory.h
+++ b/chrome/browser/chromeos/extensions/install_limiter_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_INSTALL_LIMITER_FACTORY_H_
 #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_INSTALL_LIMITER_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/chromeos/fileapi/file_system_backend.h b/chrome/browser/chromeos/fileapi/file_system_backend.h
index 9752084f..513a6fff 100644
--- a/chrome/browser/chromeos/fileapi/file_system_backend.h
+++ b/chrome/browser/chromeos/fileapi/file_system_backend.h
@@ -11,7 +11,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "components/account_id/account_id.h"
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.cc
index e3ef3d6..d0830b2 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.cc
@@ -106,8 +106,6 @@
 
   DlpContentRestrictionSet set;
 
-// TODO(crbug.com/1254329) Enable on LaCros once DlpRulesManager is available.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
   DlpRulesManager* dlp_rules_manager =
       DlpRulesManagerFactory::GetForPrimaryProfile();
   if (!dlp_rules_manager)
@@ -136,7 +134,6 @@
       continue;
     set.SetRestriction(restriction.second, level, url);
   }
-#endif
 
   return set;
 }
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set_browsertest.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set_browsertest.cc
index 3a696bd..47c4fef 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set_browsertest.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set_browsertest.cc
@@ -20,7 +20,7 @@
 
 namespace policy {
 
-// TODO(crbug.com/1254329) Enable on LaCros once DlpRulesManager is available.
+// TODO(crbug.com/1262948): Enable and modify for lacros.
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 
 const DlpContentRestrictionSet kScreenshotRestricted(
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper.cc
index 37a9b70..ee0299b5 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper.cc
@@ -26,14 +26,11 @@
   if (web_contents->GetBrowserContext()->IsOffTheRecord()) {
     return;
   }
-  // TODO(crbug.com/1254326): Check on LaCros once DlpRulesManager is available.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Do not observe non-managed users.
   if (!g_ignore_rules_manager_for_testing_ &&
       !DlpRulesManagerFactory::GetForPrimaryProfile()) {
     return;
   }
-#endif
   DlpContentTabHelper::CreateForWebContents(web_contents);
 }
 
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.cc b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.cc
index 9c5acaa..0e1e897 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.cc
@@ -46,6 +46,22 @@
   return is_main_profile && profile->GetProfilePolicyConnector()->IsManaged();
 }
 
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+// Returns the single main profile, or nullptr if none is found.
+Profile* GetMainProfile() {
+  // Might be not initialized in tests.
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  if (!profile_manager)
+    return nullptr;
+  auto profiles = profile_manager->GetLoadedProfiles();
+  const auto profile_it = base::ranges::find_if(
+      profiles, [](Profile* profile) { return profile->IsMainProfile(); });
+  if (profile_it == profiles.end())
+    return nullptr;
+  return *profile_it;
+}
+#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
+
 }  // namespace
 
 // static
@@ -56,7 +72,11 @@
 
 // static
 DlpRulesManager* DlpRulesManagerFactory::GetForPrimaryProfile() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   Profile* profile = ProfileManager::GetPrimaryUserProfile();
+#elif BUILDFLAG(IS_CHROMEOS_LACROS)
+  Profile* profile = GetMainProfile();
+#endif
   if (!profile)
     return nullptr;
   return static_cast<DlpRulesManager*>(
diff --git a/chrome/browser/commerce/merchant_viewer/android/BUILD.gn b/chrome/browser/commerce/merchant_viewer/android/BUILD.gn
index 8dfd0927..9055039c 100644
--- a/chrome/browser/commerce/merchant_viewer/android/BUILD.gn
+++ b/chrome/browser/commerce/merchant_viewer/android/BUILD.gn
@@ -166,6 +166,7 @@
     "//chrome/browser/optimization_guide/android:java",
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/tabmodel:java",
+    "//chrome/browser/ui/android/page_info:java",
     "//chrome/test/android:chrome_java_test_support",
     "//components/browser_ui/bottomsheet/android:java",
     "//components/embedder_support/android:content_view_java",
diff --git a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/PageInfoStoreInfoViewTest.java b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/PageInfoStoreInfoViewTest.java
index 2e48ca4..4af8121 100644
--- a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/PageInfoStoreInfoViewTest.java
+++ b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/PageInfoStoreInfoViewTest.java
@@ -52,6 +52,7 @@
 import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridge.OptimizationGuideCallback;
 import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridgeJni;
 import org.chromium.chrome.browser.page_info.ChromePageInfo;
+import org.chromium.chrome.browser.page_info.ChromePageInfoHighlight;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
@@ -129,7 +130,7 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             new ChromePageInfo(activity.getModalDialogManagerSupplier(), null,
                     PageInfoController.OpenedFromSource.TOOLBAR, () -> mMockStoreInfoActionHandler)
-                    .show(tab, PageInfoController.NO_HIGHLIGHTED_PERMISSION, fromStoreIcon);
+                    .show(tab, ChromePageInfoHighlight.forStoreInfo(fromStoreIcon));
         });
         onViewWaiting(allOf(withId(R.id.page_info_url_wrapper), isDisplayed()));
     }
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_factory.h b/chrome/browser/custom_handlers/protocol_handler_registry_factory.h
index 6d58ed7..5c5004c 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_factory.h
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_FACTORY_H_
 #define CHROME_BROWSER_CUSTOM_HANDLERS_PROTOCOL_HANDLER_REGISTRY_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
 class Profile;
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h
index 45333aa..fed32cc 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_DATA_REDUCTION_PROXY_DATA_REDUCTION_PROXY_CHROME_SETTINGS_FACTORY_H_
 #define CHROME_BROWSER_DATA_REDUCTION_PROXY_DATA_REDUCTION_PROXY_CHROME_SETTINGS_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_settings_android.h b/chrome/browser/data_reduction_proxy/data_reduction_proxy_settings_android.h
index 1191ad5..a56b9df1 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_settings_android.h
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_settings_android.h
@@ -11,7 +11,6 @@
 #include "base/android/jni_string.h"
 #include "base/android/jni_weak_ref.h"
 #include "base/android/scoped_java_ref.h"
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
 #include "components/data_reduction_proxy/proto/data_store.pb.h"
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.h b/chrome/browser/devtools/chrome_devtools_manager_delegate.h
index 3d43f4f3..9b6fd2a 100644
--- a/chrome/browser/devtools/chrome_devtools_manager_delegate.h
+++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.h
@@ -10,7 +10,6 @@
 #include <set>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/devtools/device/devtools_device_discovery.h"
 #include "chrome/browser/devtools/protocol/forward.h"
 #include "chrome/browser/devtools/protocol/protocol.h"
diff --git a/chrome/browser/diagnostics/diagnostics_test.h b/chrome/browser/diagnostics/diagnostics_test.h
index 37f71b1..f15adfb 100644
--- a/chrome/browser/diagnostics/diagnostics_test.h
+++ b/chrome/browser/diagnostics/diagnostics_test.h
@@ -7,7 +7,6 @@
 
 #include <stddef.h>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/diagnostics/diagnostics_metrics.h"
 #include "chrome/browser/diagnostics/diagnostics_model.h"
 
diff --git a/chrome/browser/dom_distiller/tab_utils_browsertest.cc b/chrome/browser/dom_distiller/tab_utils_browsertest.cc
index 8c6255b..e3c5dfe2e 100644
--- a/chrome/browser/dom_distiller/tab_utils_browsertest.cc
+++ b/chrome/browser/dom_distiller/tab_utils_browsertest.cc
@@ -242,8 +242,17 @@
   histogram_tester.ExpectTotalCount(kDistillablePageHistogram, 1);
 }
 
-IN_PROC_BROWSER_TEST_F(DomDistillerTabUtilsBrowserTest,
-                       DistillAndViewCreatesNewWebContentsAndPreservesOld) {
+// TODO(crbug.com/1272152): Flaky on linux.
+#if defined(OS_LINUX)
+#define MAYBE_DistillAndViewCreatesNewWebContentsAndPreservesOld \
+  DISABLED_DistillAndViewCreatesNewWebContentsAndPreservesOld
+#else
+#define MAYBE_DistillAndViewCreatesNewWebContentsAndPreservesOld \
+  DistillAndViewCreatesNewWebContentsAndPreservesOld
+#endif
+IN_PROC_BROWSER_TEST_F(
+    DomDistillerTabUtilsBrowserTest,
+    MAYBE_DistillAndViewCreatesNewWebContentsAndPreservesOld) {
   content::WebContents* source_web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
 
@@ -277,7 +286,14 @@
   destroyed_watcher.Wait();
 }
 
-IN_PROC_BROWSER_TEST_F(DomDistillerTabUtilsBrowserTest, ToggleOriginalPage) {
+// TODO(crbug.com/1271740): Flaky on linux.
+#if defined(OS_LINUX)
+#define MAYBE_ToggleOriginalPage DISABLED_ToggleOriginalPage
+#else
+#define MAYBE_ToggleOriginalPage ToggleOriginalPage
+#endif
+IN_PROC_BROWSER_TEST_F(DomDistillerTabUtilsBrowserTest,
+                       MAYBE_ToggleOriginalPage) {
   content::WebContents* source_web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
 
diff --git a/chrome/browser/download/chrome_download_manager_delegate.h b/chrome/browser/download/chrome_download_manager_delegate.h
index 1416e69..4bcfaa2 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.h
+++ b/chrome/browser/download/chrome_download_manager_delegate.h
@@ -12,7 +12,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/containers/flat_map.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index d392df5a..d0d39e14 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -427,7 +427,7 @@
   return item->GetFileExternallyRemoved();
 }
 
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !defined(OS_CHROMEOS)
 // Called when a download starts. Marks the download as hidden.
 void SetHiddenDownloadCallback(DownloadItem* item,
                                download::DownloadInterruptReason reason) {
@@ -5338,7 +5338,7 @@
 
 // The rest of these tests rely on the download shelf, which ChromeOS doesn't
 // use.
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !defined(OS_CHROMEOS)
 // Test that the download shelf is shown by starting a download.
 IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadAndWait) {
   embedded_test_server()->ServeFilesFromDirectory(GetTestDataDirectory());
@@ -5606,4 +5606,4 @@
   // Download shelf should close.
   EXPECT_FALSE(browser()->window()->IsDownloadShelfVisible());
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // defined(OS_CHROMEOS)
diff --git a/chrome/browser/download/download_core_service_factory.h b/chrome/browser/download/download_core_service_factory.h
index 281e09b0..2ffde2c 100644
--- a/chrome/browser/download/download_core_service_factory.h
+++ b/chrome/browser/download/download_core_service_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_CORE_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_CORE_SERVICE_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/download/download_dir_policy_handler.h b/chrome/browser/download/download_dir_policy_handler.h
index 4633a72..a55541b6 100644
--- a/chrome/browser/download/download_dir_policy_handler.h
+++ b/chrome/browser/download/download_dir_policy_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_DIR_POLICY_HANDLER_H_
 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_DIR_POLICY_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "components/policy/core/browser/configuration_policy_handler.h"
 
 class PrefValueMap;
diff --git a/chrome/browser/download/download_item_model.h b/chrome/browser/download/download_item_model.h
index e80196c..08de05e 100644
--- a/chrome/browser/download/download_item_model.h
+++ b/chrome/browser/download/download_item_model.h
@@ -9,7 +9,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "chrome/browser/download/download_ui_model.h"
 #include "components/download/public/common/download_item.h"
diff --git a/chrome/browser/download/download_shelf_context_menu.h b/chrome/browser/download/download_shelf_context_menu.h
index 1fbc30b..320c0f13 100644
--- a/chrome/browser/download/download_shelf_context_menu.h
+++ b/chrome/browser/download/download_shelf_context_menu.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/containers/flat_map.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/download/download_stats.cc b/chrome/browser/download/download_stats.cc
index 85ee90f..d14c5de1 100644
--- a/chrome/browser/download/download_stats.cc
+++ b/chrome/browser/download/download_stats.cc
@@ -101,11 +101,11 @@
 
 #endif  // defined(OS_ANDROID)
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if defined(OS_CHROMEOS)
 void RecordDownloadNotificationSuppressed() {
   base::UmaHistogramBoolean("Download.Notification.Suppressed", true);
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // defined(OS_CHROMEOS)
 
 DownloadShelfContextMenuAction DownloadCommandToShelfAction(
     DownloadCommands::Command download_command,
diff --git a/chrome/browser/download/download_stats.h b/chrome/browser/download/download_stats.h
index 9170993..bfa1d594f 100644
--- a/chrome/browser/download/download_stats.h
+++ b/chrome/browser/download/download_stats.h
@@ -178,10 +178,10 @@
 void RecordDownloadLaterPromptStatus(DownloadLaterPromptStatus status);
 #endif  // defined(OS_ANDROID)
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if defined(OS_CHROMEOS)
 // Records that a notification for a download was suppressed.
 void RecordDownloadNotificationSuppressed();
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // defined(OS_CHROMEOS)
 
 enum class DownloadShelfContextMenuAction {
   // Drop down button for download shelf context menu is visible
diff --git a/chrome/browser/download/download_ui_controller.cc b/chrome/browser/download/download_ui_controller.cc
index d13c066..f0aec7fc 100644
--- a/chrome/browser/download/download_ui_controller.cc
+++ b/chrome/browser/download/download_ui_controller.cc
@@ -33,9 +33,9 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if defined(OS_CHROMEOS)
 #include "chrome/browser/download/notification/download_notification_manager.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // defined(OS_CHROMEOS)
 
 namespace {
 
@@ -121,14 +121,14 @@
 #if defined(OS_ANDROID)
   if (!delegate_)
     delegate_ = std::make_unique<AndroidUIControllerDelegate>();
-#elif BUILDFLAG(IS_CHROMEOS_ASH)
+#elif defined(OS_CHROMEOS)
   if (!delegate_) {
     // The Profile is guaranteed to be valid since DownloadUIController is owned
     // by DownloadService, which in turn is a profile keyed service.
     delegate_ = std::make_unique<DownloadNotificationManager>(
         Profile::FromBrowserContext(manager->GetBrowserContext()));
   }
-#else   // BUILDFLAG(IS_CHROMEOS_ASH)
+#else   // defined(OS_CHROMEOS)
   if (!delegate_) {
     delegate_ = std::make_unique<DownloadShelfUIControllerDelegate>(
         Profile::FromBrowserContext(manager->GetBrowserContext()));
diff --git a/chrome/browser/download/notification/download_item_notification.cc b/chrome/browser/download/notification/download_item_notification.cc
index ab1d2da..ab3ce25 100644
--- a/chrome/browser/download/notification/download_item_notification.cc
+++ b/chrome/browser/download/notification/download_item_notification.cc
@@ -9,7 +9,11 @@
 
 #include <memory>
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/constants/ash_features.h"
+#include "chrome/browser/ash/note_taking_helper.h"
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
 #include "ash/public/cpp/notification_utils.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
@@ -21,7 +25,6 @@
 #include "base/task/thread_pool.h"
 #include "build/build_config.h"
 #include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/browser/ash/note_taking_helper.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_commands.h"
 #include "chrome/browser/download/download_crx_util.h"
@@ -452,6 +455,8 @@
 
   const bool was_suppressed = suppressed_;
 
+// TODO(crbug.com/1267463): Support suppression in Lacros.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // When holding space in-progress downloads notification suppression is
   // enabled, download in-progress notifications should be suppressed so long as
   // they do not `force_pop_up`, such as is done in the case of dangerous or
@@ -468,6 +473,7 @@
   } else {
     suppressed_ = false;
   }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   if (suppressed_) {
     if (!was_suppressed)
@@ -745,8 +751,11 @@
       actions->push_back(DownloadCommands::SHOW_IN_FOLDER);
       if (!notification_->image().IsEmpty()) {
         actions->push_back(DownloadCommands::COPY_TO_CLIPBOARD);
+// TODO(crbug.com/1267466): Support NoteTakingHelper in Lacros.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
         if (ash::NoteTakingHelper::Get()->IsAppAvailable(profile()))
           actions->push_back(DownloadCommands::ANNOTATE);
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
       }
       break;
     case download::DownloadItem::MAX_DOWNLOAD_STATE:
diff --git a/chrome/browser/download/notification/download_item_notification_unittest.cc b/chrome/browser/download/notification/download_item_notification_unittest.cc
index 000e4afe..e93980f 100644
--- a/chrome/browser/download/notification/download_item_notification_unittest.cc
+++ b/chrome/browser/download/notification/download_item_notification_unittest.cc
@@ -9,7 +9,10 @@
 #include <memory>
 #include <utility>
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/constants/ash_features.h"
+#endif
+
 #include "base/guid.h"
 #include "base/json/json_reader.h"
 #include "base/run_loop.h"
@@ -53,8 +56,12 @@
     FILE_PATH_LITERAL("/tmp/TITLE.bin");
 
 bool IsHoldingSpaceInProgressDownloadsNotificationSuppressionEnabled() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   return ash::features::
       IsHoldingSpaceInProgressDownloadsNotificationSuppressionEnabled();
+#else
+  return false;
+#endif
 }
 
 }  // anonymous namespace
@@ -67,9 +74,11 @@
       bool
           is_holding_space_in_progress_downloads_notification_suppression_enabled)
       : profile_(nullptr) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     scoped_feature_list_.InitWithFeatureState(
         ash::features::kHoldingSpaceInProgressDownloadsNotificationSuppression,
         is_holding_space_in_progress_downloads_notification_suppression_enabled);
+#endif
   }
 
   void SetUp() override {
diff --git a/chrome/browser/download/notification/download_notification_browsertest.cc b/chrome/browser/download/notification/download_notification_browsertest.cc
index 73d82a4..210b262 100644
--- a/chrome/browser/download/notification/download_notification_browsertest.cc
+++ b/chrome/browser/download/notification/download_notification_browsertest.cc
@@ -66,6 +66,7 @@
   SECONDARY_ACCOUNT_INDEX_START = 2,
 };
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Structure to describe an account info.
 struct TestAccountInfo {
   const char* const email;
@@ -81,6 +82,7 @@
     {"bob@invalid.domain", "10002", "hashbobbo", "Bob"},
     {"charlie@invalid.domain", "10003", "hashcharl", "Charlie"},
 };
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 class TestChromeDownloadManagerDelegate : public ChromeDownloadManagerDelegate {
  public:
@@ -288,9 +290,11 @@
           bool> {
  public:
   DownloadNotificationTestBase() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     scoped_feature_list_.InitWithFeatureState(
         ash::features::kHoldingSpaceInProgressDownloadsNotificationSuppression,
         IsHoldingSpaceInProgressDownloadsNotificationSuppressionEnabled());
+#endif
   }
 
   DownloadNotificationTestBase(const DownloadNotificationTestBase&) = delete;
@@ -332,7 +336,11 @@
   // Returns whether holding space in-progress downloads notification
   // suppression is enabled given test parameterization.
   bool IsHoldingSpaceInProgressDownloadsNotificationSuppressionEnabled() const {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     return GetParam();
+#else
+    return false;
+#endif
   }
 
   std::unique_ptr<NotificationDisplayServiceTester> display_service_;
@@ -1141,6 +1149,10 @@
   chrome::CloseWindow(incognito_browser());
 }
 
+// These tests have ash dependency so they are only available for ash.
+// TODO(crbug.com/1266950): Enable these tests for Lacros.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+
 //////////////////////////////////////////////////
 // Test with multi profiles
 //////////////////////////////////////////////////
@@ -1395,3 +1407,4 @@
               notification.type());
   }
 }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index d79aa86..7a8260e 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -465,7 +465,13 @@
   EXPECT_TRUE(base::ContentsEqual(kTestFile, full_file_name));
 }
 
-IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveHTMLOnlyCancel) {
+// TODO(crbug.com/1271463): Flaky on mac arm64.
+#if defined(OS_MAC) && defined(ARCH_CPU_ARM64)
+#define MAYBE_SaveHTMLOnlyCancel DISABLED_SaveHTMLOnlyCancel
+#else
+#define MAYBE_SaveHTMLOnlyCancel SaveHTMLOnlyCancel
+#endif
+IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveHTMLOnlyCancel) {
   GURL url = NavigateToMockURL("a");
   DownloadManager* manager = GetDownloadManager();
   std::vector<DownloadItem*> downloads;
@@ -1094,7 +1100,14 @@
 }
 
 // Test for crbug.com/538766.
-IN_PROC_BROWSER_TEST_F(SavePageSitePerProcessBrowserTest, SaveAsMHTML) {
+// Disabled on Mac due to excessive flakiness. https://crbug.com/1271741
+#if defined(OS_MAC)
+#define MAYBE_SaveAsMHTML DISABLED_SaveAsMHTML
+#else
+#define MAYBE_SaveAsMHTML SaveAsMHTML
+#endif
+IN_PROC_BROWSER_TEST_F(SavePageSitePerProcessBrowserTest,
+                       MAYBE_SaveAsMHTML) {
   GURL url(
       embedded_test_server()->GetURL("a.com", "/save_page/frames-xsite.htm"));
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation/common/attestation_utils.cc b/chrome/browser/enterprise/connectors/device_trust/attestation/common/attestation_utils.cc
index 8ac2a7e4..8ae3aaf 100644
--- a/chrome/browser/enterprise/connectors/device_trust/attestation/common/attestation_utils.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/attestation/common/attestation_utils.cc
@@ -13,18 +13,25 @@
 
 namespace enterprise_connectors {
 
-std::string JsonChallengeToProtobufChallenge(const std::string& challenge) {
+std::string JsonChallengeToProtobufChallenge(
+    const std::string& json_challenge) {
   absl::optional<base::Value> data = base::JSONReader::Read(
-      challenge, base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS);
+      json_challenge, base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS);
+  if (!data) {
+    LOG(ERROR) << "Error reading JSON challenge.";
+    return std::string();
+  }
 
   // If json is malformed or it doesn't include the needed field return
   // an empty string.
-  if (!data || !data.value().FindPath("challenge"))
+  const std::string* challenge = data.value().FindStringPath("challenge");
+  if (!challenge) {
+    LOG(ERROR) << "JSON challenge does not have required field.";
     return std::string();
+  }
 
   std::string serialized_signed_challenge;
-  if (!base::Base64Decode(data.value().FindPath("challenge")->GetString(),
-                          &serialized_signed_challenge)) {
+  if (!base::Base64Decode(*challenge, &serialized_signed_challenge)) {
     LOG(ERROR) << "Error during decoding base64 challenge.";
     return std::string();
   }
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation/common/attestation_utils.h b/chrome/browser/enterprise/connectors/device_trust/attestation/common/attestation_utils.h
index 96a6bd6..ead02dafe 100644
--- a/chrome/browser/enterprise/connectors/device_trust/attestation/common/attestation_utils.h
+++ b/chrome/browser/enterprise/connectors/device_trust/attestation/common/attestation_utils.h
@@ -14,7 +14,8 @@
 // The expected format of the challenge is the following:
 // {
 //    "challenge": base64 encoded SignedData
-std::string JsonChallengeToProtobufChallenge(const std::string& challenge);
+// }
+std::string JsonChallengeToProtobufChallenge(const std::string& json_challenge);
 
 // Take a challenge_response proto and return the json version of it.
 // The format follows Vaapi v2 definition:
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_browsertest.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_browsertest.cc
index 859c791a..732dcb8 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_browsertest.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_browsertest.cc
@@ -63,6 +63,21 @@
     "u3W4CMboCswxIxNYRCGrIIVPElE3Yb4QS65mKrg=\""
     "}";
 
+constexpr char kChallengeV1[] =
+    "{\"challenge\": "
+    "{"
+    "\"data\": "
+    "\"ChZFbnRlcnByaXNlS2V5Q2hhbGxlbmdlEiABAZTXEb/mB+E3Ncja9cazVIg3frBMjxpc"
+    "UfyWoC+M6xjOmrvJ0y8=\","
+    "\"signature\": "
+    "\"cEA1rPdSEuBaM/4cWOv8R/OicR5c8IT+anVnVd7ain6ucZuyyy/8sjWYK4JpvVu2Diy6y"
+    "6a77/5mis+QRNsbjVQ1QkEf7TcQOaGitt618jwQyhc54cyGhKUiuCok8Q7jc2gwrN6POKmB"
+    "3Vdx+nrhmmVjzp/QAGgamPoLQmuW5XM+Cq5hSrW/U8bg12KmrZ5OHYdiZLyGGlmgE811kpxq"
+    "dKQSWWB1c2xiu5ALY0q8aa8o/Hrzqko8JJbMXcefwrr9YxcEAoVH524mjtj83Pru55WfPmDL"
+    "2ZgSJhErFEQDvWjyX0cDuFX8fO2i40aAwJsFoX+Z5fHbd3kanTcK+ty56w==\""
+    "}"
+    "}";
+
 constexpr char kFakeCustomerId[] = "fake-customer-id";
 constexpr char kFakeBrowserDMToken[] = "fake-browser-dm-token";
 constexpr char kFakeEnrollmentToken[] = "fake-enrollment-token";
@@ -80,8 +95,9 @@
 
 }  // namespace
 
-class DeviceTrustBrowserTest : public InProcessBrowserTest,
-                               public ::testing::WithParamInterface<bool> {
+class DeviceTrustBrowserTest
+    : public InProcessBrowserTest,
+      public ::testing::WithParamInterface<std::tuple<bool, bool>> {
  public:
   DeviceTrustBrowserTest() {
     browser_dm_token_storage_ =
@@ -115,8 +131,13 @@
     browser_policy_manager->core()->store()->set_policy_data_for_testing(
         std::move(browser_policy_data));
 
-    embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
-        &DeviceTrustBrowserTest::HandleRequest, base::Unretained(this)));
+    // Device trust only works with VerfiedAccess v2. However make sure that v1
+    // headers are just treated like "untrusted" and nothing further.
+    const std::string header = use_v2_header() ? kChallenge : kChallengeV1;
+
+    embedded_test_server()->RegisterRequestHandler(
+        base::BindRepeating(&DeviceTrustBrowserTest::HandleRequest,
+                            base::Unretained(this), header));
     host_resolver()->AddRule("*", "127.0.0.1");
     ASSERT_TRUE(test_server_handle_ =
                     embedded_test_server()->StartAndReturnHandle());
@@ -165,6 +186,7 @@
 
   // This function needs to reflect how IdP are expected to behave.
   std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
+      const std::string& header,
       const net::test_server::HttpRequest& request) {
     auto deviceTrustHeader = request.headers.find(kDeviceTrustHeader);
     if (deviceTrustHeader != request.headers.end()) {
@@ -175,7 +197,7 @@
       auto response = std::make_unique<net::test_server::BasicHttpResponse>();
       response->set_code(net::HTTP_FOUND);
       response->AddCustomHeader("Location", GetRedirectLocationUrl().spec());
-      response->AddCustomHeader(kVerifiedAccessChallengeHeader, kChallenge);
+      response->AddCustomHeader(kVerifiedAccessChallengeHeader, header);
       return response;
     }
 
@@ -197,7 +219,8 @@
     return browser()->tab_strip_model()->GetActiveWebContents();
   }
 
-  bool is_enabled() { return GetParam(); }
+  bool is_enabled() { return std::get<0>(GetParam()); }
+  bool use_v2_header() { return std::get<1>(GetParam()); }
 
   PrefService* prefs() { return browser()->profile()->GetPrefs(); }
 
@@ -236,7 +259,6 @@
 
   // Attestation flow should be fully done.
   EXPECT_TRUE(initial_attestation_request_);
-  EXPECT_TRUE(challenge_response_request_);
 
   // Validate that the two requests contain expected information. URLs' paths
   // have to be used for comparison due to how the HostResolver is replacing
@@ -247,14 +269,19 @@
       initial_attestation_request_->headers.find(kDeviceTrustHeader)->second,
       kDeviceTrustHeaderValue);
 
-  EXPECT_EQ(challenge_response_request_->GetURL().path(),
-            GetRedirectLocationUrl().path());
+  EXPECT_EQ(use_v2_header(), challenge_response_request_.has_value());
 
-  // TODO(crbug.com/1241857): Add challenge-response validation.
-  const std::string& challenge_response =
-      challenge_response_request_->headers.find(kVerifiedAccessResponseHeader)
-          ->second;
-  EXPECT_TRUE(!challenge_response.empty());
+  if (use_v2_header()) {
+    EXPECT_EQ(challenge_response_request_->GetURL().path(),
+              GetRedirectLocationUrl().path());
+
+    // TODO(crbug.com/1241857): Add challenge-response validation.
+    const std::string& challenge_response =
+        challenge_response_request_->headers
+            .find(kVerifiedAccessResponseHeader)
+            ->second;
+    EXPECT_TRUE(!challenge_response.empty());
+  }
 }
 
 // Tests that the attestation flow does not get triggered when navigating to a
@@ -306,6 +333,8 @@
   EXPECT_FALSE(challenge_response_request_);
 }
 
-INSTANTIATE_TEST_SUITE_P(All, DeviceTrustBrowserTest, testing::Bool());
+INSTANTIATE_TEST_SUITE_P(All,
+                         DeviceTrustBrowserTest,
+                         testing::Combine(testing::Bool(), testing::Bool()));
 
 }  // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service.cc
index 6470f95d..614df56 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service.cc
@@ -39,13 +39,25 @@
 
 DeviceTrustConnectorService::DeviceTrustConnectorService(
     PrefService* profile_prefs)
-    : profile_prefs_(profile_prefs),
-      matcher_(std::make_unique<url_matcher::URLMatcher>()) {
+    : profile_prefs_(profile_prefs) {
   DCHECK(profile_prefs_);
+}
+
+DeviceTrustConnectorService::~DeviceTrustConnectorService() = default;
+
+bool DeviceTrustConnectorService::IsConnectorEnabled() const {
+  return DeviceTrustConnectorService::IsConnectorEnabled(profile_prefs_);
+}
+
+void DeviceTrustConnectorService::Initialize() {
   if (!IsDeviceTrustConnectorFeatureEnabled()) {
     return;
   }
 
+  if (!pref_observer_.IsEmpty()) {
+    return;
+  }
+
   pref_observer_.Init(profile_prefs_);
   pref_observer_.Add(
       kContextAwareAccessSignalsAllowlistPref,
@@ -56,14 +68,8 @@
   OnPolicyUpdated();
 }
 
-DeviceTrustConnectorService::~DeviceTrustConnectorService() = default;
-
-bool DeviceTrustConnectorService::IsConnectorEnabled() const {
-  return DeviceTrustConnectorService::IsConnectorEnabled(profile_prefs_);
-}
-
 bool DeviceTrustConnectorService::Watches(const GURL& url) const {
-  return !matcher_->MatchURL(url).empty();
+  return matcher_ && !matcher_->MatchURL(url).empty();
 }
 
 void DeviceTrustConnectorService::OnConnectorEnabled() {
@@ -75,16 +81,14 @@
 
   const base::ListValue* url_patterns = GetPolicyUrlPatterns(profile_prefs_);
 
-  url_matcher::URLMatcherConditionSet::ID condition_set_id(0);
-  if (!matcher_->IsEmpty()) {
-    // Clear old conditions in case they exist.
-    matcher_->RemoveConditionSets({condition_set_id});
+  if (!matcher_ || !matcher_->IsEmpty()) {
+    // Reset the matcher.
+    matcher_ = std::make_unique<url_matcher::URLMatcher>();
   }
 
   if (url_patterns && !url_patterns->GetList().empty()) {
     // Add the new endpoints to the conditions.
-    policy::url_util::AddFilters(matcher_.get(), /*allow=*/true,
-                                 &condition_set_id, url_patterns);
+    policy::url_util::AddAllowFilters(matcher_.get(), url_patterns);
 
     // Call the hook which signals that the connector has been enabled.
     OnConnectorEnabled();
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service.h b/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service.h
index 8ee64c9..69ed695 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service.h
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service.h
@@ -35,6 +35,10 @@
   // given `profile_prefs` to check the policy value.
   static bool IsConnectorEnabled(PrefService* profile_prefs);
 
+  // Does one time initialization of the service.  This is called from the
+  // factory and client do not need to call it.
+  void Initialize();
+
   // Returns whether the Device Trust connector is enabled or not.
   bool IsConnectorEnabled() const;
 
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service_factory.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service_factory.cc
index f93b496..89eeb9f4 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service_factory.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service_factory.cc
@@ -56,16 +56,24 @@
     content::BrowserContext* context) const {
   auto* profile = Profile::FromBrowserContext(context);
 
+  DeviceTrustConnectorService* service = nullptr;
+
 #if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC)
   if (IsDeviceTrustConnectorFeatureEnabled()) {
     auto* key_manager = g_browser_process->browser_policy_connector()
                             ->chrome_browser_cloud_management_controller()
                             ->GetDeviceTrustKeyManager();
-    return new BrowserDeviceTrustConnectorService(key_manager,
-                                                  profile->GetPrefs());
+    service = new BrowserDeviceTrustConnectorService(key_manager,
+                                                     profile->GetPrefs());
   }
+#else
+  service = new DeviceTrustConnectorService(profile->GetPrefs());
 #endif  // defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC)
-  return new DeviceTrustConnectorService(profile->GetPrefs());
+
+  if (service)
+    service->Initialize();
+
+  return service;
 }
 
 }  // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service_unittest.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service_unittest.cc
new file mode 100644
index 0000000..239978f
--- /dev/null
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service_unittest.cc
@@ -0,0 +1,129 @@
+// 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/enterprise/connectors/device_trust/device_trust_connector_service.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "base/values.h"
+#include "chrome/browser/enterprise/connectors/connectors_prefs.h"
+#include "chrome/browser/enterprise/connectors/device_trust/device_trust_features.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace enterprise_connectors {
+
+namespace {
+
+constexpr char kExampleDomain1[] = "example1.com";
+constexpr char kExampleDomain2[] = "example2.com";
+constexpr char kExampleDomain3[] = "example3.com";
+
+constexpr char kExampleUrl1[] = "https://example1.com/somepath";
+constexpr char kExampleUrl2[] = "https://example2.com/some2path";
+constexpr char kExampleUrl3[] = "https://example3.com/some3path";
+
+const base::Value origins[]{base::Value(kExampleDomain1),
+                            base::Value(kExampleDomain2)};
+const base::Value more_origins[]{base::Value(kExampleDomain1),
+                                 base::Value(kExampleDomain2),
+                                 base::Value(kExampleDomain3)};
+
+}  // namespace
+
+class DeviceTrustConnectorServiceTest
+    : public testing::Test,
+      public ::testing::WithParamInterface<std::tuple<bool, bool>> {
+ protected:
+  void SetUp() override {
+    RegisterProfilePrefs(prefs_.registry());
+
+    feature_list_.InitWithFeatureState(kDeviceTrustConnectorEnabled,
+                                       is_flag_enabled());
+
+    if (is_policy_enabled()) {
+      EnableServicePolicy();
+    } else {
+      DisableServicePolicy();
+    }
+  }
+
+  void EnableServicePolicy() {
+    prefs_.SetUserPref(kContextAwareAccessSignalsAllowlistPref,
+                       std::make_unique<base::ListValue>(origins));
+  }
+
+  void UpdateServicePolicy() {
+    prefs_.SetUserPref(kContextAwareAccessSignalsAllowlistPref,
+                       std::make_unique<base::ListValue>(more_origins));
+  }
+
+  void DisableServicePolicy() {
+    prefs_.SetUserPref(kContextAwareAccessSignalsAllowlistPref,
+                       std::make_unique<base::ListValue>());
+  }
+
+  std::unique_ptr<DeviceTrustConnectorService> CreateService() {
+    return std::make_unique<DeviceTrustConnectorService>(&prefs_);
+  }
+
+  bool is_attestation_flow_enabled() {
+    return is_flag_enabled() && is_policy_enabled();
+  }
+
+  bool is_flag_enabled() { return std::get<0>(GetParam()); }
+  bool is_policy_enabled() { return std::get<1>(GetParam()); }
+
+  base::test::ScopedFeatureList feature_list_;
+  TestingPrefServiceSimple prefs_;
+};
+
+TEST_P(DeviceTrustConnectorServiceTest, Static_IsConnectorEnabled) {
+  EXPECT_EQ(is_attestation_flow_enabled(),
+            DeviceTrustConnectorService::IsConnectorEnabled(&prefs_));
+}
+
+TEST_P(DeviceTrustConnectorServiceTest, IsConnectorEnabled_Update) {
+  auto service = CreateService();
+  service->Initialize();
+  EXPECT_EQ(is_attestation_flow_enabled(), service->IsConnectorEnabled());
+
+  if (!is_flag_enabled()) {
+    return;
+  }
+
+  UpdateServicePolicy();
+
+  EXPECT_TRUE(service->IsConnectorEnabled());
+}
+
+TEST_P(DeviceTrustConnectorServiceTest, Matches_Update) {
+  if (!is_attestation_flow_enabled()) {
+    return;
+  }
+
+  auto service = CreateService();
+  service->Initialize();
+
+  GURL url1(kExampleUrl1);
+  GURL url2(kExampleUrl2);
+  GURL url3(kExampleUrl3);
+
+  EXPECT_TRUE(service->Watches(url1));
+  EXPECT_TRUE(service->Watches(url2));
+  EXPECT_FALSE(service->Watches(url3));
+
+  UpdateServicePolicy();
+
+  EXPECT_TRUE(service->Watches(url1));
+  EXPECT_TRUE(service->Watches(url2));
+  EXPECT_TRUE(service->Watches(url3));
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+                         DeviceTrustConnectorServiceTest,
+                         testing::Combine(testing::Bool(), testing::Bool()));
+
+}  // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/browser/key_rotation_launcher.h b/chrome/browser/enterprise/connectors/device_trust/key_management/browser/key_rotation_launcher.h
index 757b5b4b..4954d75 100644
--- a/chrome/browser/enterprise/connectors/device_trust/key_management/browser/key_rotation_launcher.h
+++ b/chrome/browser/enterprise/connectors/device_trust/key_management/browser/key_rotation_launcher.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/enterprise/connectors/device_trust/key_management/browser/commands/key_rotation_command.h"
 
 namespace policy {
diff --git a/chrome/browser/enterprise/connectors/device_trust/navigation_throttle_unittest.cc b/chrome/browser/enterprise/connectors/device_trust/navigation_throttle_unittest.cc
index d5b2e06..b281363 100644
--- a/chrome/browser/enterprise/connectors/device_trust/navigation_throttle_unittest.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/navigation_throttle_unittest.cc
@@ -70,6 +70,8 @@
 
     fake_connector_ = std::make_unique<FakeDeviceTrustConnectorService>(
         profile_.GetTestingPrefService());
+    fake_connector_->Initialize();
+
     fake_connector_->update_policy(
         std::make_unique<base::ListValue>(GetTrustedUrls()));
 
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 3d13e295..3c107943 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -1113,6 +1113,7 @@
     }
     deps += [
       "//ash",
+      "//ash/components/attestation",
       "//ash/components/enhanced_network_tts/mojom",
       "//ash/components/settings",
       "//ash/constants",
@@ -1127,7 +1128,6 @@
       "//chrome/browser/nearby_sharing/common",
       "//chrome/browser/ui/webui/settings/chromeos/constants:mojom",
       "//chromeos",
-      "//chromeos/attestation",
       "//chromeos/components/chromebox_for_meetings/buildflags",
       "//chromeos/components/proximity_auth",
       "//chromeos/components/quick_answers/public/cpp:prefs",
diff --git a/chrome/browser/extensions/activity_log/activity_log_enabled_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_enabled_unittest.cc
index 827ba57..e398244 100644
--- a/chrome/browser/extensions/activity_log/activity_log_enabled_unittest.cc
+++ b/chrome/browser/extensions/activity_log/activity_log_enabled_unittest.cc
@@ -169,10 +169,13 @@
   EXPECT_TRUE(activity_log1->IsDatabaseEnabled());
   EXPECT_FALSE(activity_log2->IsDatabaseEnabled());
 
+  // Wait for UninstallExtension to complete to avoid race condition with data
+  // cleanup at TearDown.
+  base::RunLoop loop;
   extension_service1->UninstallExtension(
-      kExtensionID,
-      extensions::UNINSTALL_REASON_FOR_TESTING,
-      NULL);
+      kExtensionID, extensions::UNINSTALL_REASON_FOR_TESTING, nullptr,
+      loop.QuitClosure());
+  loop.Run();
 
   EXPECT_EQ(0,
       profile1->GetPrefs()->GetInteger(prefs::kWatchdogExtensionActive));
@@ -246,10 +249,13 @@
       profile->GetPrefs()->GetInteger(prefs::kWatchdogExtensionActive));
   EXPECT_TRUE(activity_log->IsWatchdogAppActive());
 
+  // Wait for UninstallExtension to complete to avoid race condition with data
+  // cleanup at TearDown.
+  base::RunLoop loop;
   extension_service->UninstallExtension(
-      kExtensionID,
-      extensions::UNINSTALL_REASON_FOR_TESTING,
-      NULL);
+      kExtensionID, extensions::UNINSTALL_REASON_FOR_TESTING, nullptr,
+      loop.QuitClosure());
+  loop.Run();
 
   EXPECT_TRUE(activity_log->IsDatabaseEnabled());
   EXPECT_EQ(0,
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.h b/chrome/browser/extensions/api/chrome_extensions_api_client.h
index 735450e..2cca3e8e 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.h
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_CHROME_EXTENSIONS_API_CLIENT_H_
 #define CHROME_BROWSER_EXTENSIONS_API_CHROME_EXTENSIONS_API_CLIENT_H_
 
-#include "base/compiler_specific.h"
 #include "build/chromeos_buildflags.h"
 #include "extensions/browser/api/extensions_api_client.h"
 
diff --git a/chrome/browser/extensions/api/cookies/cookies_api.h b/chrome/browser/extensions/api/cookies/cookies_api.h
index 7d7e202..43b4f3e 100644
--- a/chrome/browser/extensions/api/cookies/cookies_api.h
+++ b/chrome/browser/extensions/api/cookies/cookies_api.h
@@ -11,7 +11,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/common/extensions/api/cookies.h"
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc b/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
index ad2bdac..95a016718 100644
--- a/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
+++ b/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
@@ -1018,7 +1018,7 @@
   // The test verification below is applicable only to scenarios where the
   // download shelf is supported - on ChromeOS, instead of the download shelf,
   // there is a download notification in the right-bottom corner of the screen.
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !defined(OS_CHROMEOS)
   EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
 #endif
 }
@@ -1053,7 +1053,7 @@
   // The test verification below is applicable only to scenarios where the
   // download shelf is supported - on ChromeOS, instead of the download shelf,
   // there is a download notification in the right-bottom corner of the screen.
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !defined(OS_CHROMEOS)
   EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
 #endif
 }
diff --git a/chrome/browser/extensions/api/history/history_api.h b/chrome/browser/extensions/api/history/history_api.h
index 812e647d..624bfdb 100644
--- a/chrome/browser/extensions/api/history/history_api.h
+++ b/chrome/browser/extensions/api/history/history_api.h
@@ -8,7 +8,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/scoped_observation.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/values.h"
diff --git a/chrome/browser/extensions/api/permissions/permissions_api.h b/chrome/browser/extensions/api/permissions/permissions_api.h
index a671b9a9..b449aa8 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api.h
+++ b/chrome/browser/extensions/api/permissions/permissions_api.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_PERMISSIONS_PERMISSIONS_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_PERMISSIONS_PERMISSIONS_API_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
 #include "extensions/browser/extension_function.h"
 #include "extensions/common/permissions/permission_set.h"
diff --git a/chrome/browser/extensions/api/storage/managed_value_store_cache.h b/chrome/browser/extensions/api/storage/managed_value_store_cache.h
index 360499309..0c56b55 100644
--- a/chrome/browser/extensions/api/storage/managed_value_store_cache.h
+++ b/chrome/browser/extensions/api/storage/managed_value_store_cache.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "components/policy/core/common/policy_namespace.h"
 #include "components/policy/core/common/policy_service.h"
diff --git a/chrome/browser/extensions/api/storage/policy_value_store.h b/chrome/browser/extensions/api/storage/policy_value_store.h
index bae27df..562f9c4 100644
--- a/chrome/browser/extensions/api/storage/policy_value_store.h
+++ b/chrome/browser/extensions/api/storage/policy_value_store.h
@@ -11,7 +11,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "components/value_store/value_store.h"
 #include "extensions/browser/api/storage/settings_observer.h"
diff --git a/chrome/browser/extensions/api/storage/sync_storage_backend.h b/chrome/browser/extensions/api/storage/sync_storage_backend.h
index 435d4199..9c8a4c5 100644
--- a/chrome/browser/extensions/api/storage/sync_storage_backend.h
+++ b/chrome/browser/extensions/api/storage/sync_storage_backend.h
@@ -10,7 +10,6 @@
 #include <set>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "components/sync/model/syncable_service.h"
 #include "components/value_store/value_store_factory.h"
diff --git a/chrome/browser/extensions/api/storage/sync_value_store_cache.h b/chrome/browser/extensions/api/storage/sync_value_store_cache.h
index ae3de69..3e603e3 100644
--- a/chrome/browser/extensions/api/storage/sync_value_store_cache.h
+++ b/chrome/browser/extensions/api/storage/sync_value_store_cache.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "components/sync/model/syncable_service.h"
diff --git a/chrome/browser/extensions/api/storage/syncable_settings_storage.h b/chrome/browser/extensions/api/storage/syncable_settings_storage.h
index 51980e7..4bf52b908 100644
--- a/chrome/browser/extensions/api/storage/syncable_settings_storage.h
+++ b/chrome/browser/extensions/api/storage/syncable_settings_storage.h
@@ -11,7 +11,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/api/storage/setting_sync_data.h"
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.h b/chrome/browser/extensions/api/tabs/tabs_api.h
index dc057c6..23057722 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.h
+++ b/chrome/browser/extensions/api/tabs/tabs_api.h
@@ -8,7 +8,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/scoped_refptr.h"
 #include "chrome/browser/extensions/chrome_extension_function_details.h"
 #include "chrome/common/extensions/api/tabs.h"
diff --git a/chrome/browser/extensions/api/tabs/tabs_constants.cc b/chrome/browser/extensions/api/tabs/tabs_constants.cc
index 925c8b1..185e8ec 100644
--- a/chrome/browser/extensions/api/tabs/tabs_constants.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_constants.cc
@@ -129,6 +129,8 @@
 const char kCannotNavigateToDevtools[] =
     "Cannot navigate to a devtools:// page without either the devtools or "
     "debugger permission.";
+const char kCannotNavigateToChromeUntrusted[] =
+    "Cannot navigate to a chrome-untrusted:// page.";
 const char kCannotHighlightTabs[] =
     "Cannot change tab highlight. This may be due to user dragging in "
     "progress.";
diff --git a/chrome/browser/extensions/api/tabs/tabs_constants.h b/chrome/browser/extensions/api/tabs/tabs_constants.h
index 6df59cef..ea67267 100644
--- a/chrome/browser/extensions/api/tabs/tabs_constants.h
+++ b/chrome/browser/extensions/api/tabs/tabs_constants.h
@@ -112,6 +112,7 @@
 extern const char kLockedFullscreenModeNewTabError[];
 extern const char kGroupParamsError[];
 extern const char kCannotNavigateToDevtools[];
+extern const char kCannotNavigateToChromeUntrusted[];
 extern const char kCannotHighlightTabs[];
 extern const char kNotAllowedForDevToolsError[];
 
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h
index d07d80a..87dedb1 100644
--- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h
+++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "ash/public/cpp/clipboard_history_controller.h"
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/browser_context.h"
 #include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_delegate.h"
diff --git a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h
index 9cbd6313..08fa0519 100644
--- a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h
+++ b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_WEB_NAVIGATION_FRAME_NAVIGATION_STATE_H_
 #define CHROME_BROWSER_EXTENSIONS_API_WEB_NAVIGATION_FRAME_NAVIGATION_STATE_H_
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/document_user_data.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api.h b/chrome/browser/extensions/api/web_navigation/web_navigation_api.h
index 83c2734..d1f01ce8 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_api.h
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api.h
@@ -12,7 +12,6 @@
 #include <set>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/extensions/api/web_navigation/frame_navigation_state.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_tab_strip_tracker.h"
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
index 238c94b..4815f403 100644
--- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
+++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "chrome/browser/chrome_content_browser_client_parts.h"
 #include "components/download/public/common/quarantine_connection.h"
diff --git a/chrome/browser/extensions/chrome_extension_web_contents_observer.h b/chrome/browser/extensions/chrome_extension_web_contents_observer.h
index c0eadbc..16bfff4e 100644
--- a/chrome/browser/extensions/chrome_extension_web_contents_observer.h
+++ b/chrome/browser/extensions/chrome_extension_web_contents_observer.h
@@ -9,7 +9,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "extensions/browser/extension_web_contents_observer.h"
 #include "extensions/common/stack_frame.h"
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.h b/chrome/browser/extensions/chrome_extensions_browser_client.h
index 9df873e..d0bee73 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.h
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.h
@@ -9,7 +9,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/lazy_instance.h"
 #include "base/memory/ref_counted.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/extensions/chrome_process_manager_delegate.h b/chrome/browser/extensions/chrome_process_manager_delegate.h
index 6547dde..9b6e9218 100644
--- a/chrome/browser/extensions/chrome_process_manager_delegate.h
+++ b/chrome/browser/extensions/chrome_process_manager_delegate.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_CHROME_PROCESS_MANAGER_DELEGATE_H_
 #define CHROME_BROWSER_EXTENSIONS_CHROME_PROCESS_MANAGER_DELEGATE_H_
 
-#include "base/compiler_specific.h"
 #include "base/scoped_multi_source_observation.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager_observer.h"
diff --git a/chrome/browser/extensions/content_verifier_browsertest.cc b/chrome/browser/extensions/content_verifier_browsertest.cc
index b6aba2b0..500f7563 100644
--- a/chrome/browser/extensions/content_verifier_browsertest.cc
+++ b/chrome/browser/extensions/content_verifier_browsertest.cc
@@ -879,7 +879,14 @@
 }
 
 // Now actually test what happens on the next startup after the PRE test above.
-IN_PROC_BROWSER_TEST_F(ContentVerifierPolicyTest, PolicyCorruptedOnStartup) {
+// TODO(crbug.com/1271946): Flaky on mac arm64.
+#if defined(OS_MAC) && defined(ARCH_CPU_ARM64)
+#define MAYBE_PolicyCorruptedOnStartup DISABLED_PolicyCorruptedOnStartup
+#else
+#define MAYBE_PolicyCorruptedOnStartup PolicyCorruptedOnStartup
+#endif
+IN_PROC_BROWSER_TEST_F(ContentVerifierPolicyTest,
+                       MAYBE_PolicyCorruptedOnStartup) {
   // Depdending on timing, the extension may have already been reinstalled
   // between SetUpInProcessBrowserTestFixture and now (usually not during local
   // testing on a developer machine, but sometimes on a heavily loaded system
diff --git a/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc b/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc
index a7a0367..0a28118b 100644
--- a/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc
+++ b/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc
@@ -209,7 +209,7 @@
           "permissions": [
               "tabs",
               "*://fetch-initiator.com/*",
-              "*://127.0.0.1/*",  // Initiator in AppCache tests.
+              "*://127.0.0.1/*",
               "*://cross-site.com/*",
               "*://*.subdomain.com/*",
               "*://other-with-permission.com/*"
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index 04f860f..253af0b 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -10,7 +10,6 @@
 #include <utility>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/extensions/extension_action_runner.h b/chrome/browser/extensions/extension_action_runner.h
index 9971976f..3c51f3b9 100644
--- a/chrome/browser/extensions/extension_action_runner.h
+++ b/chrome/browser/extensions/extension_action_runner.h
@@ -13,7 +13,6 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_bar_bubble_delegate.h"
diff --git a/chrome/browser/extensions/extension_commands_global_registry.h b/chrome/browser/extensions/extension_commands_global_registry.h
index f6a306a..095b9d4b7 100644
--- a/chrome/browser/extensions/extension_commands_global_registry.h
+++ b/chrome/browser/extensions/extension_commands_global_registry.h
@@ -8,7 +8,6 @@
 #include <map>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/extensions/extension_keybinding_registry.h"
 #include "chrome/browser/extensions/global_shortcut_listener.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
diff --git a/chrome/browser/extensions/extension_gcm_app_handler.h b/chrome/browser/extensions/extension_gcm_app_handler.h
index 48a86259..0c8afae7 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler.h
+++ b/chrome/browser/extensions/extension_gcm_app_handler.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
 #include "components/gcm_driver/common/gcm_message.h"
diff --git a/chrome/browser/extensions/extension_keybinding_registry.h b/chrome/browser/extensions/extension_keybinding_registry.h
index 1609e20..429bdb4 100644
--- a/chrome/browser/extensions/extension_keybinding_registry.h
+++ b/chrome/browser/extensions/extension_keybinding_registry.h
@@ -10,7 +10,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/scoped_observation.h"
 #include "chrome/browser/extensions/api/commands/command_service.h"
 #include "extensions/browser/extension_registry.h"
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 0547a06..b263e287 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -11,7 +11,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index f0dbd62..3d85575 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -840,6 +840,12 @@
     }
   }
 
+  // Don't let the extension navigate directly to chrome-untrusted scheme pages.
+  if (url.SchemeIs(content::kChromeUIUntrustedScheme)) {
+    *error = tabs_constants::kCannotNavigateToChromeUntrusted;
+    return false;
+  }
+
   return_url->Swap(&url);
   return true;
 }
diff --git a/chrome/browser/extensions/extension_tab_util_unittest.cc b/chrome/browser/extensions/extension_tab_util_unittest.cc
index 663a503..bca4bc019 100644
--- a/chrome/browser/extensions/extension_tab_util_unittest.cc
+++ b/chrome/browser/extensions/extension_tab_util_unittest.cc
@@ -203,4 +203,14 @@
   }
 }
 
+TEST(ExtensionTabUtilTest, PrepareURLForNavigationOnChromeUntrusted) {
+  const std::string kChromeUntrustedURL("chrome-untrusted://terminal/");
+  auto extension = ExtensionBuilder("none").Build();
+  std::string error;
+  GURL url;
+  EXPECT_FALSE(ExtensionTabUtil::PrepareURLForNavigation(
+      kChromeUntrustedURL, extension.get(), &url, &error));
+  EXPECT_EQ(tabs_constants::kCannotNavigateToChromeUntrusted, error);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/external_component_loader.h b/chrome/browser/extensions/external_component_loader.h
index 53b5f79..bd1bffe1 100644
--- a/chrome/browser/extensions/external_component_loader.h
+++ b/chrome/browser/extensions/external_component_loader.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/extensions/external_loader.h"
 #include "chrome/browser/profiles/profile.h"
 
diff --git a/chrome/browser/extensions/external_policy_loader.h b/chrome/browser/extensions/external_policy_loader.h
index e2733ac948..43292e06 100644
--- a/chrome/browser/extensions/external_policy_loader.h
+++ b/chrome/browser/extensions/external_policy_loader.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/extensions/extension_management.h"
 #include "chrome/browser/extensions/external_loader.h"
 
diff --git a/chrome/browser/extensions/external_pref_loader.h b/chrome/browser/extensions/external_pref_loader.h
index da93308..2f12dc4 100644
--- a/chrome/browser/extensions/external_pref_loader.h
+++ b/chrome/browser/extensions/external_pref_loader.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/values.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/external_loader.h"
diff --git a/chrome/browser/extensions/external_registry_loader_win.h b/chrome/browser/extensions/external_registry_loader_win.h
index e2cd41e..1767090 100644
--- a/chrome/browser/extensions/external_registry_loader_win.h
+++ b/chrome/browser/extensions/external_registry_loader_win.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_LOADER_WIN_H_
 #define CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_LOADER_WIN_H_
 
-#include "base/compiler_specific.h"
 #include "base/win/registry.h"
 #include "chrome/browser/extensions/external_loader.h"
 
diff --git a/chrome/browser/extensions/menu_manager.h b/chrome/browser/extensions/menu_manager.h
index 155f02e..062f262 100644
--- a/chrome/browser/extensions/menu_manager.h
+++ b/chrome/browser/extensions/menu_manager.h
@@ -14,7 +14,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.h b/chrome/browser/extensions/theme_installed_infobar_delegate.h
index 0294513..6d07f5a7 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.h
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_observer.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
diff --git a/chrome/browser/extensions/user_script_listener.h b/chrome/browser/extensions/user_script_listener.h
index c8ddbb1..618ef2a 100644
--- a/chrome/browser/extensions/user_script_listener.h
+++ b/chrome/browser/extensions/user_script_listener.h
@@ -8,7 +8,6 @@
 #include <list>
 #include <map>
 
-#include "base/compiler_specific.h"
 #include "base/containers/circular_deque.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_multi_source_observation.h"
diff --git a/chrome/browser/extensions/webstore_installer.h b/chrome/browser/extensions/webstore_installer.h
index f75b27fb..eb8570e 100644
--- a/chrome/browser/extensions/webstore_installer.h
+++ b/chrome/browser/extensions/webstore_installer.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/file_select_helper.h b/chrome/browser/file_select_helper.h
index a10132d..5b68c12 100644
--- a/chrome/browser/file_select_helper.h
+++ b/chrome/browser/file_select_helper.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/scoped_observation.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index d780321..053a6eb 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1512,8 +1512,8 @@
   },
   {
     "name": "enable-bluetooth-spp-in-serial-api",
-    "owners": [ "mattreynolds", "odejesush" ],
-    "expiry_milestone": 90
+    "owners": [ "mattreynolds", "cmumford" ],
+    "expiry_milestone": 110
   },
   {
     "name": "enable-browsing-data-lifetime-manager",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index cb4fd31..62c1b18 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3541,10 +3541,6 @@
     "#site-isolation-trial-opt-out for how to disable site isolation for "
     "testing.";
 
-const char kThemeRefactorAndroidName[] = "Theme refactor on Android";
-const char kThemeRefactorAndroidDescription[] =
-    "Enables the theme refactoring on Android.";
-
 const char kToolbarIphAndroidName[] = "Enable Toolbar IPH on Android";
 const char kToolbarIphAndroidDescription[] =
     "Enables in product help bubbles on the toolbar. In particular, the home "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index b90aaef2..0bfb4e8 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2030,9 +2030,6 @@
 extern const char kStrictSiteIsolationName[];
 extern const char kStrictSiteIsolationDescription[];
 
-extern const char kThemeRefactorAndroidName[];
-extern const char kThemeRefactorAndroidDescription[];
-
 extern const char kToolbarIphAndroidName[];
 extern const char kToolbarIphAndroidDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index ccbe93c..c8d8f110 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -283,7 +283,6 @@
     &kTabToGTSAnimation,
     &kTestDefaultDisabled,
     &kTestDefaultEnabled,
-    &kThemeRefactorAndroid,
     &kToolbarIphAndroid,
     &kToolbarMicIphAndroid,
     &kTrustedWebActivityLocationDelegation,
@@ -760,9 +759,6 @@
 const base::Feature kTestDefaultEnabled{"TestDefaultEnabled",
                                         base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kThemeRefactorAndroid{"ThemeRefactorAndroid",
-                                          base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kToolbarIphAndroid{"ToolbarIphAndroid",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 92496016..c5d8f70 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -143,7 +143,6 @@
 extern const base::Feature kTabToGTSAnimation;
 extern const base::Feature kTestDefaultDisabled;
 extern const base::Feature kTestDefaultEnabled;
-extern const base::Feature kThemeRefactorAndroid;
 extern const base::Feature kToolbarIphAndroid;
 extern const base::Feature kToolbarMicIphAndroid;
 extern const base::Feature kToolbarUseHardwareBitmapDraw;
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
index 566a807..026bddd 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
@@ -82,7 +82,6 @@
                     .put(ChromeFeatureList.TEST_DEFAULT_DISABLED, false)
                     .put(ChromeFeatureList.TEST_DEFAULT_ENABLED, true)
                     .put(ChromeFeatureList.INTEREST_FEED_V2, true)
-                    .put(ChromeFeatureList.THEME_REFACTOR_ANDROID, false)
                     .put(ChromeFeatureList.USE_CHIME_ANDROID_SDK, false)
                     .put(ChromeFeatureList.CCT_INCOGNITO_AVAILABLE_TO_THIRD_PARTY, false)
                     .put(ChromeFeatureList.READ_LATER, false)
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 0b85e8d..8e60be0 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -518,7 +518,6 @@
     public static final String TAB_TO_GTS_ANIMATION = "TabToGTSAnimation";
     public static final String TEST_DEFAULT_DISABLED = "TestDefaultDisabled";
     public static final String TEST_DEFAULT_ENABLED = "TestDefaultEnabled";
-    public static final String THEME_REFACTOR_ANDROID = "ThemeRefactorAndroid";
     public static final String TOOLBAR_IPH_ANDROID = "ToolbarIphAndroid";
     public static final String TOOLBAR_MIC_IPH_ANDROID = "ToolbarMicIphAndroid";
     public static final String TOOLBAR_USE_HARDWARE_BITMAP_DRAW = "ToolbarUseHardwareBitmapDraw";
diff --git a/chrome/browser/gcm/gcm_profile_service_factory.h b/chrome/browser/gcm/gcm_profile_service_factory.h
index 3c62000..13511e84 100644
--- a/chrome/browser/gcm/gcm_profile_service_factory.h
+++ b/chrome/browser/gcm/gcm_profile_service_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_GCM_GCM_PROFILE_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_GCM_GCM_PROFILE_SERVICE_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/no_destructor.h"
 #include "components/gcm_driver/system_encryptor.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
diff --git a/chrome/browser/history/history_browsertest.cc b/chrome/browser/history/history_browsertest.cc
index 11d0ad5..3b6df58 100644
--- a/chrome/browser/history/history_browsertest.cc
+++ b/chrome/browser/history/history_browsertest.cc
@@ -970,7 +970,8 @@
             history_tab_helper->last_load_completion_);
 
   // Create a fenced frame.
-  GURL fenced_frame_url = embedded_test_server()->GetURL("/title1.html");
+  GURL fenced_frame_url =
+      embedded_test_server()->GetURL("/fenced_frames/title1.html");
   content::RenderFrameHost* fenced_frame_host =
       fenced_frame_test_helper().CreateFencedFrame(
           web_contents()->GetMainFrame(), fenced_frame_url);
diff --git a/chrome/browser/importer/external_process_importer_client.h b/chrome/browser/importer/external_process_importer_client.h
index 0d273e8..f9834aef 100644
--- a/chrome/browser/importer/external_process_importer_client.h
+++ b/chrome/browser/importer/external_process_importer_client.h
@@ -11,7 +11,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/importer/external_process_importer_host.h b/chrome/browser/importer/external_process_importer_host.h
index fe029f86..53c2770a 100644
--- a/chrome/browser/importer/external_process_importer_host.h
+++ b/chrome/browser/importer/external_process_importer_host.h
@@ -9,7 +9,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/importer/importer_progress_observer.h"
diff --git a/chrome/browser/importer/in_process_importer_bridge.h b/chrome/browser/importer/in_process_importer_bridge.h
index 3c6695c..4fe7fcb 100644
--- a/chrome/browser/importer/in_process_importer_bridge.h
+++ b/chrome/browser/importer/in_process_importer_bridge.h
@@ -8,7 +8,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
 #include "chrome/browser/importer/profile_writer.h"
diff --git a/chrome/browser/install_verification/win/module_verification_test.h b/chrome/browser/install_verification/win/module_verification_test.h
index 9c19c8f..be753b9 100644
--- a/chrome/browser/install_verification/win/module_verification_test.h
+++ b/chrome/browser/install_verification/win/module_verification_test.h
@@ -8,7 +8,6 @@
 #include <stddef.h>
 
 #include <set>
-#include "base/compiler_specific.h"
 #include "chrome/browser/install_verification/win/module_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/lifetime/application_lifetime.h b/chrome/browser/lifetime/application_lifetime.h
index 13f4a7f..45fb99a5 100644
--- a/chrome/browser/lifetime/application_lifetime.h
+++ b/chrome/browser/lifetime/application_lifetime.h
@@ -7,7 +7,6 @@
 
 #include "base/callback.h"
 #include "base/callback_list.h"
-#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 
diff --git a/chrome/browser/media/router/discovery/dial/device_description_fetcher.cc b/chrome/browser/media/router/discovery/dial/device_description_fetcher.cc
index 35c7459..7e17df58 100644
--- a/chrome/browser/media/router/discovery/dial/device_description_fetcher.cc
+++ b/chrome/browser/media/router/discovery/dial/device_description_fetcher.cc
@@ -18,14 +18,12 @@
 namespace media_router {
 
 DeviceDescriptionFetcher::DeviceDescriptionFetcher(
-    const GURL& device_description_url,
+    const DialDeviceData& device_data,
     base::OnceCallback<void(const DialDeviceDescriptionData&)> success_cb,
     base::OnceCallback<void(const std::string&)> error_cb)
-    : device_description_url_(device_description_url),
+    : device_data_(device_data),
       success_cb_(std::move(success_cb)),
-      error_cb_(std::move(error_cb)) {
-  DCHECK(device_description_url_.is_valid());
-}
+      error_cb_(std::move(error_cb)) {}
 
 DeviceDescriptionFetcher::~DeviceDescriptionFetcher() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -41,7 +39,7 @@
       base::BindOnce(&DeviceDescriptionFetcher::ReportError,
                      base::Unretained(this)));
 
-  fetcher_->Get(device_description_url_, false /** set_origin_header **/);
+  fetcher_->Get(device_description_url(), false /** set_origin_header **/);
 }
 
 void DeviceDescriptionFetcher::ProcessResponse(const std::string& response) {
@@ -67,12 +65,7 @@
   // Section 5.4 of the DIAL spec implies that the Application URL should not
   // have path, query or fragment...unsure if that can be enforced.
   GURL app_url(app_url_header);
-
-  // TODO(crbug.com/679432): Get the device IP from the SSDP response.
-  net::IPAddress device_ip;
-  if (!device_ip.AssignFromIPLiteral(
-          device_description_url_.HostNoBracketsPiece()) ||
-      !DialDeviceData::IsValidDialAppUrl(app_url, device_ip)) {
+  if (!device_data_.IsValidUrl(app_url)) {
     ReportError(base::StringPrintf("Invalid Application-URL: %s",
                                    app_url_header.c_str()));
     return;
diff --git a/chrome/browser/media/router/discovery/dial/device_description_fetcher.h b/chrome/browser/media/router/discovery/dial/device_description_fetcher.h
index be5f5500..94dc9cc 100644
--- a/chrome/browser/media/router/discovery/dial/device_description_fetcher.h
+++ b/chrome/browser/media/router/discovery/dial/device_description_fetcher.h
@@ -10,6 +10,7 @@
 
 #include "base/callback.h"
 #include "base/sequence_checker.h"
+#include "chrome/browser/media/router/discovery/dial/dial_device_data.h"
 #include "chrome/browser/media/router/discovery/dial/dial_url_fetcher.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "url/gurl.h"
@@ -26,7 +27,7 @@
 class DeviceDescriptionFetcher {
  public:
   DeviceDescriptionFetcher(
-      const GURL& device_description_url,
+      const DialDeviceData& device_data,
       base::OnceCallback<void(const DialDeviceDescriptionData&)> success_cb,
       base::OnceCallback<void(const std::string&)> error_cb);
 
@@ -35,7 +36,9 @@
 
   virtual ~DeviceDescriptionFetcher();
 
-  const GURL& device_description_url() { return device_description_url_; }
+  const GURL& device_description_url() const {
+    return device_data_.device_description_url();
+  }
 
   // Marked virtual for tests.
   virtual void Start();
@@ -51,7 +54,7 @@
   void ReportError(const std::string& message,
                    absl::optional<int> response_code = absl::nullopt);
 
-  const GURL device_description_url_;
+  const DialDeviceData device_data_;
 
   base::OnceCallback<void(const DialDeviceDescriptionData&)> success_cb_;
   base::OnceCallback<void(const std::string&)> error_cb_;
diff --git a/chrome/browser/media/router/discovery/dial/device_description_fetcher_unittest.cc b/chrome/browser/media/router/discovery/dial/device_description_fetcher_unittest.cc
index 7852b54..39737537 100644
--- a/chrome/browser/media/router/discovery/dial/device_description_fetcher_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/device_description_fetcher_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/media/router/discovery/dial/device_description_fetcher.h"
 #include "chrome/browser/media/router/discovery/dial/dial_device_data.h"
 #include "chrome/browser/media/router/test/provider_test_helpers.h"
+#include "net/base/ip_address.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -28,11 +29,11 @@
 class TestDeviceDescriptionFetcher : public DeviceDescriptionFetcher {
  public:
   TestDeviceDescriptionFetcher(
-      const GURL& device_description_url,
+      const DialDeviceData& device_data,
       base::OnceCallback<void(const DialDeviceDescriptionData&)> success_cb,
       base::OnceCallback<void(const std::string&)> error_cb,
       network::TestURLLoaderFactory* factory)
-      : DeviceDescriptionFetcher(device_description_url,
+      : DeviceDescriptionFetcher(device_data,
                                  std::move(success_cb),
                                  std::move(error_cb)),
         factory_(factory) {}
@@ -45,7 +46,7 @@
         base::BindOnce(&DeviceDescriptionFetcher::ReportError,
                        base::Unretained(this)),
         factory_);
-    fetcher_->Get(device_description_url_);
+    fetcher_->Get(device_data_.device_description_url());
   }
 
  private:
@@ -60,8 +61,11 @@
       delete;
 
   void StartRequest() {
+    DialDeviceData device_data;
+    device_data.set_device_description_url(url_);
+    device_data.set_ip_address(net::IPAddress::IPv4Localhost());
     description_fetcher_ = std::make_unique<TestDeviceDescriptionFetcher>(
-        url_,
+        device_data,
         base::BindOnce(&DeviceDescriptionFetcherTest::OnSuccess,
                        base::Unretained(this)),
         base::BindOnce(&DeviceDescriptionFetcherTest::OnError,
diff --git a/chrome/browser/media/router/discovery/dial/device_description_service.cc b/chrome/browser/media/router/discovery/dial/device_description_service.cc
index 064272c4..613e0fc 100644
--- a/chrome/browser/media/router/discovery/dial/device_description_service.cc
+++ b/chrome/browser/media/router/discovery/dial/device_description_service.cc
@@ -39,7 +39,7 @@
 // Checks mandatory fields. Returns ParsingError::kNone if device description is
 // valid; Otherwise returns specific error type.
 ParsingError ValidateParsedDeviceDescription(
-    const GURL& device_description_url,
+    const DialDeviceData& device_data,
     const ParsedDialDeviceDescription& description_data) {
   if (description_data.unique_id.empty()) {
     return ParsingError::kMissingUniqueId;
@@ -50,14 +50,10 @@
   if (!description_data.app_url.is_valid()) {
     return ParsingError::kMissingAppUrl;
   }
-
-  // TODO(crbug.com/679432): Get the device IP from the SSDP response.
-  net::IPAddress device_ip;
-  if (!device_ip.AssignFromIPLiteral(
-          device_description_url.HostNoBracketsPiece()) ||
-      !DialDeviceData::IsValidDialAppUrl(description_data.app_url, device_ip)) {
+  if (!device_data.IsValidUrl(description_data.app_url)) {
     return ParsingError::kInvalidAppUrl;
   }
+
   return ParsingError::kNone;
 }
 
@@ -141,7 +137,7 @@
     return;
 
   auto device_description_fetcher = std::make_unique<DeviceDescriptionFetcher>(
-      device_data.device_description_url(),
+      device_data,
       base::BindOnce(
           &DeviceDescriptionService::OnDeviceDescriptionFetchComplete,
           base::Unretained(this), device_data),
@@ -194,8 +190,8 @@
     return;
   }
 
-  ParsingError error = ValidateParsedDeviceDescription(
-      device_data.device_description_url(), device_description);
+  ParsingError error =
+      ValidateParsedDeviceDescription(device_data, device_description);
   if (error != ParsingError::kNone) {
     RecordDialParsingError(error);
     error_cb_.Run(device_data, "Failed to process fetch result");
diff --git a/chrome/browser/media/router/discovery/dial/device_description_service_unittest.cc b/chrome/browser/media/router/discovery/dial/device_description_service_unittest.cc
index d550d23..96f8580 100644
--- a/chrome/browser/media/router/discovery/dial/device_description_service_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/device_description_service_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/media/router/discovery/dial/parsed_dial_device_description.h"
 #include "chrome/browser/media/router/discovery/dial/safe_dial_device_description_parser.h"
 #include "content/public/test/browser_task_environment.h"
+#include "net/base/ip_address.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -31,6 +32,9 @@
       GURL(base::StringPrintf("http://192.168.1.%d/dd.xml", num)),
       base::Time::Now());
   device_data.set_label(base::StringPrintf("Device label %d", num));
+  net::IPAddress address;
+  CHECK(address.AssignFromIPLiteral(base::StringPrintf("192.168.1.%d", num)));
+  device_data.set_ip_address(address);
   return device_data;
 }
 
diff --git a/chrome/browser/media/router/discovery/dial/dial_device_data.cc b/chrome/browser/media/router/discovery/dial/dial_device_data.cc
index bc52975..4bbcf9a 100644
--- a/chrome/browser/media/router/discovery/dial/dial_device_data.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_device_data.cc
@@ -3,7 +3,10 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/media/router/discovery/dial/dial_device_data.h"
-#include "net/base/ip_address.h"
+
+#include "base/check.h"
+#include "base/feature_list.h"
+#include "chrome/browser/media/router/media_router_feature.h"
 
 namespace media_router {
 
@@ -30,30 +33,26 @@
   device_description_url_ = url;
 }
 
-// static
-bool DialDeviceData::IsDeviceDescriptionUrl(const GURL& url) {
+void DialDeviceData::set_ip_address(const net::IPAddress& ip_address) {
+  ip_address_ = ip_address;
+}
+
+bool DialDeviceData::IsValidUrl(const GURL& url) const {
   if (!url.is_valid() || url.is_empty() || !url.SchemeIsHTTPOrHTTPS())
     return false;
 
-  net::IPAddress address;
-  if (!net::ParseURLHostnameToAddress(url.host(), &address))
+  net::IPAddress host_address;
+  if (!net::ParseURLHostnameToAddress(url.host(), &host_address))
     return false;
 
-  // TODO(crbug.com/679432): check that this IP address matches the address that
-  // we received the SSDP advertisement from.
-  return !address.IsPubliclyRoutable();
-}
-
-// static
-bool DialDeviceData::IsValidDialAppUrl(
-    const GURL& url,
-    const net::IPAddress& expected_ip_address) {
-  if (!url.is_valid() || !url.SchemeIsHTTPOrHTTPS())
+  if (host_address.IsPubliclyRoutable())
     return false;
 
-  net::IPAddress host_ip;
-  return host_ip.AssignFromIPLiteral(url.HostNoBracketsPiece()) &&
-         host_ip.IsValid() && host_ip == expected_ip_address;
+  if (base::FeatureList::IsEnabled(kDialEnforceUrlIPAddress)) {
+    return host_address == ip_address_;
+  } else {
+    return true;
+  }
 }
 
 bool DialDeviceData::UpdateFrom(const DialDeviceData& new_data) {
@@ -62,7 +61,9 @@
   std::string label_tmp(label_);
   bool updated_api_visible_field =
       (new_data.device_description_url() != device_description_url_) ||
-      (new_data.config_id() != config_id_);
+      (new_data.config_id() != config_id_) ||
+      (new_data.ip_address() != ip_address_) ||
+      (new_data.max_age() != max_age_);
   *this = new_data;
   label_ = label_tmp;
   return updated_api_visible_field;
diff --git a/chrome/browser/media/router/discovery/dial/dial_device_data.h b/chrome/browser/media/router/discovery/dial/dial_device_data.h
index 1506934..68ab938 100644
--- a/chrome/browser/media/router/discovery/dial/dial_device_data.h
+++ b/chrome/browser/media/router/discovery/dial/dial_device_data.h
@@ -6,15 +6,11 @@
 #define CHROME_BROWSER_MEDIA_ROUTER_DISCOVERY_DIAL_DIAL_DEVICE_DATA_H_
 
 #include <string>
-#include <vector>
 
 #include "base/time/time.h"
+#include "net/base/ip_address.h"
 #include "url/gurl.h"
 
-namespace net {
-class IPAddress;
-}
-
 namespace media_router {
 
 // Dial device information that is used within the DialService and Registry on
@@ -49,24 +45,28 @@
 
   int max_age() const { return max_age_; }
   void set_max_age(int max_age) { max_age_ = max_age; }
-  bool has_max_age() const { return max_age_ >= 0; }
+  bool has_max_age() const { return max_age_ > 0; }
 
   int config_id() const { return config_id_; }
   void set_config_id(int config_id) { config_id_ = config_id; }
   bool has_config_id() const { return config_id_ >= 0; }
 
+  const net::IPAddress& ip_address() const { return ip_address_; }
+  void set_ip_address(const net::IPAddress& ip_address);
+
   // Updates this DeviceData based on information from a new response in
   // |new_data|.  Returns |true| if a field was updated that is visible through
   // the DIAL API.
+  //
+  // TODO(crbug.com/1260555): Merge logic into operator== once we remove the
+  // extension-specific code that needs this.
   bool UpdateFrom(const DialDeviceData& new_data);
 
-  // Validates that the URL is valid for the device description.
-  static bool IsDeviceDescriptionUrl(const GURL& url);
-
-  // Returns true if |app_url| is a valid DIAL Application URL with a hostname
-  // matching |expected_ip_address|.
-  static bool IsValidDialAppUrl(const GURL& url,
-                                const net::IPAddress& expected_ip_address);
+  // Validates that |url| is a valid URL for this device - either a device
+  // description URL, or a DIAL application URL.  The URL host must match the IP
+  // address that the device is advertising SSDP on, and must not be publicly
+  // routable.
+  bool IsValidUrl(const GURL& url) const;
 
  private:
   // Hardware identifier from the DIAL response.  Not exposed to API clients.
@@ -82,6 +82,9 @@
   // The time that the most recent response was received.
   base::Time response_time_;
 
+  // The IP address that the device's SSDP advertisement was sent from.
+  net::IPAddress ip_address_;
+
   // Optional (-1 means unset).
   int max_age_;
 
diff --git a/chrome/browser/media/router/discovery/dial/dial_device_data_unittest.cc b/chrome/browser/media/router/discovery/dial/dial_device_data_unittest.cc
index 52bc682..fa81b4e 100644
--- a/chrome/browser/media/router/discovery/dial/dial_device_data_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_device_data_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/media/router/discovery/dial/dial_device_data.h"
 
-#include "net/base/ip_address.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace media_router {
@@ -19,6 +18,13 @@
   EXPECT_EQ(first.response_time(), second.response_time());
   EXPECT_EQ(first.max_age(), second.max_age());
   EXPECT_EQ(first.config_id(), second.config_id());
+  EXPECT_EQ(first.ip_address(), second.ip_address());
+}
+
+bool IsValidUrl(const GURL& url, const net::IPAddress& address) {
+  DialDeviceData device_data;
+  device_data.set_ip_address(address);
+  return device_data.IsValidUrl(url);
 }
 
 }  // namespace
@@ -30,6 +36,7 @@
   original.set_device_description_url(GURL("http://127.0.0.1/dd-a.xml"));
   original.set_response_time(base::Time::FromInternalValue(1000));
   original.set_max_age(100);
+  original.set_ip_address(net::IPAddress::IPv4Localhost());
   original.set_config_id(1);
 
   DialDeviceData new_data;
@@ -37,6 +44,7 @@
   new_data.set_device_description_url(GURL("http://127.0.0.1/dd-a.xml"));
   new_data.set_response_time(base::Time::FromInternalValue(1000));
   new_data.set_max_age(100);
+  new_data.set_ip_address(net::IPAddress::IPv4Localhost());
   new_data.set_config_id(1);
 
   DialDeviceData original_1(original);
@@ -46,7 +54,7 @@
   DialDeviceData original_2(original);
   new_data.set_max_age(200);
   new_data.set_response_time(base::Time::FromInternalValue(2000));
-  EXPECT_FALSE(original_2.UpdateFrom(new_data));
+  EXPECT_TRUE(original_2.UpdateFrom(new_data));
 
   EXPECT_EQ("device_a", original_2.device_id());
   EXPECT_EQ(GURL("http://127.0.0.1/dd-a.xml"),
@@ -54,6 +62,7 @@
   EXPECT_EQ("label_a", original_2.label());
   EXPECT_EQ(200, original_2.max_age());
   EXPECT_EQ(base::Time::FromInternalValue(2000), original_2.response_time());
+  EXPECT_EQ(net::IPAddress::IPv4Localhost(), original_2.ip_address());
   EXPECT_EQ(1, original_2.config_id());
 
   DialDeviceData original_3(original);
@@ -67,55 +76,57 @@
   EXPECT_EQ("label_a", original_3.label());
   EXPECT_EQ(200, original_3.max_age());
   EXPECT_EQ(base::Time::FromInternalValue(2000), original_3.response_time());
+  EXPECT_EQ(net::IPAddress::IPv4Localhost(), original_3.ip_address());
   EXPECT_EQ(2, original_3.config_id());
+
+  DialDeviceData original_4(original);
+  net::IPAddress new_address;
+  CHECK(new_address.AssignFromIPLiteral("127.0.0.2"));
+  new_data.set_ip_address(new_address);
+  EXPECT_TRUE(original_4.UpdateFrom(new_data));
+  EXPECT_EQ(new_address, original_4.ip_address());
 }
 
-TEST(DialDeviceDataTest, TestIsDeviceDescriptionUrl) {
-  EXPECT_FALSE(DialDeviceData::IsDeviceDescriptionUrl(
-      GURL("http://some.device.com/dd.xml")));
-  EXPECT_FALSE(DialDeviceData::IsDeviceDescriptionUrl(
-      GURL("https://some.device.com/dd.xml")));
-  EXPECT_TRUE(DialDeviceData::IsDeviceDescriptionUrl(
-      GURL("http://192.168.1.1:1234/dd.xml")));
-  EXPECT_TRUE(DialDeviceData::IsDeviceDescriptionUrl(
-      GURL("https://192.168.1.1:1234/dd.xml")));
-
-  EXPECT_FALSE(DialDeviceData::IsDeviceDescriptionUrl(GURL()));
-  EXPECT_FALSE(DialDeviceData::IsDeviceDescriptionUrl(GURL(std::string())));
-  EXPECT_FALSE(
-      DialDeviceData::IsDeviceDescriptionUrl(GURL("file://path/to/file")));
-}
-
-TEST(DialDeviceDataTest, TestIsValidDialAppUrl) {
+TEST(DialDeviceDataTest, TestIsValidUrl) {
   net::IPAddress ipv4_address_1;
   ASSERT_TRUE(ipv4_address_1.AssignFromIPLiteral("192.168.1.1"));
   net::IPAddress ipv4_address_2;
   ASSERT_TRUE(ipv4_address_2.AssignFromIPLiteral("192.168.1.2"));
+  net::IPAddress ipv4_address_public;
+  ASSERT_TRUE(ipv4_address_public.AssignFromIPLiteral("8.8.8.8"));
   net::IPAddress ipv4_address_bad_octets;
   ASSERT_FALSE(ipv4_address_bad_octets.AssignFromIPLiteral("400.500.12.999"));
-  net::IPAddress ipv4_address_hex;
-  ASSERT_TRUE(ipv4_address_hex.AssignFromIPLiteral("222.173.190.239"));
   net::IPAddress ipv6_address;
   ASSERT_TRUE(ipv6_address.AssignFromIPLiteral(
-      "2401:fa00:480:8600:c4ee:4adc:6dd2:8e78"));
+      "4401:fa00:480:8600:c4ee:4adc:6dd2:8e78"));
 
-  EXPECT_TRUE(DialDeviceData::IsValidDialAppUrl(
-      GURL("http://192.168.1.1:1234/apps"), ipv4_address_1));
-  EXPECT_TRUE(DialDeviceData::IsValidDialAppUrl(
-      GURL("https://192.168.1.2:4321/apps"), ipv4_address_2));
-  EXPECT_TRUE(DialDeviceData::IsValidDialAppUrl(
-      GURL("http://0xDEADBEEF:1234/apps"), ipv4_address_hex));
-  EXPECT_TRUE(DialDeviceData::IsValidDialAppUrl(
-      GURL("http://[2401:fa00:480:8600:c4ee:4adc:6dd2:8e78]:1234/apps"),
+  EXPECT_TRUE(IsValidUrl(GURL("http://192.168.1.1:1234/apps"), ipv4_address_1));
+  EXPECT_TRUE(
+      IsValidUrl(GURL("https://192.168.1.2:4321/apps"), ipv4_address_2));
+  EXPECT_TRUE(IsValidUrl(GURL("http://0xC0A80102:1234/apps"), ipv4_address_2));
+  EXPECT_TRUE(IsValidUrl(
+      GURL("http://[4401:fa00:480:8600:c4ee:4adc:6dd2:8e78]:1234/apps"),
       ipv6_address));
 
-  // AppUrl host does not match.
-  EXPECT_FALSE(DialDeviceData::IsValidDialAppUrl(
-      GURL("http://192.168.0.1:1234/apps"), ipv4_address_1));
-  EXPECT_FALSE(DialDeviceData::IsValidDialAppUrl(
-      GURL("http://400.500.12.999:1234/apps"), ipv4_address_bad_octets));
-  EXPECT_FALSE(DialDeviceData::IsValidDialAppUrl(
-      GURL("http://192.168.0.2.com:1234/apps"), ipv4_address_1));
+  // URL host does not match address.
+  EXPECT_FALSE(
+      IsValidUrl(GURL("http://192.168.0.1:1234/apps"), ipv4_address_1));
+  EXPECT_FALSE(IsValidUrl(GURL("http://400.500.12.999:1234/apps"),
+                          ipv4_address_bad_octets));
+  EXPECT_FALSE(
+      IsValidUrl(GURL("http://192.168.0.2.com:1234/apps"), ipv4_address_1));
+
+  // URL is publicly routable.
+  EXPECT_FALSE(
+      IsValidUrl(GURL("http://8.8.8.8:1234/apps"), ipv4_address_public));
+
+  // URL is has a bad scheme.
+  EXPECT_FALSE(
+      IsValidUrl(GURL("file://192.168.1.1:1234/apps"), ipv4_address_1));
+
+  // URL host is not an IP literal.
+  EXPECT_FALSE(
+      IsValidUrl(GURL("http://example.com:1234/apps"), ipv4_address_1));
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
index 7c62079..d10377a6 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
@@ -223,10 +223,7 @@
   DialSinkExtraData extra_data;
   extra_data.app_url = description_data.app_url;
   extra_data.model_name = description_data.model_name;
-  std::string ip_address = device_data.device_description_url().host();
-  if (!extra_data.ip_address.AssignFromIPLiteral(ip_address)) {
-    return;
-  }
+  extra_data.ip_address = device_data.ip_address();
 
   MediaSinkInternal dial_sink(sink, extra_data);
   latest_sinks_.insert_or_assign(sink_id, dial_sink);
diff --git a/chrome/browser/media/router/discovery/dial/dial_service.cc b/chrome/browser/media/router/discovery/dial/dial_service.cc
index a47a573..7a7f594 100644
--- a/chrome/browser/media/router/discovery/dial/dial_service.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_service.cc
@@ -9,12 +9,15 @@
 #include <algorithm>
 #include <set>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/check_op.h"
 #include "base/location.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -95,6 +98,9 @@
 const char kSsdpCacheControlHeader[] = "CACHE-CONTROL";
 const char kSsdpConfigIdHeader[] = "CONFIGID.UPNP.ORG";
 const char kSsdpUsnHeader[] = "USN";
+constexpr char kSsdpMaxAgeDirective[] = "max-age";
+constexpr int kSsdpMaxMaxAge = 3600;
+constexpr int kSsdpMaxConfigId = (2 << 24) - 1;
 
 // The receive buffer size, in bytes.
 const int kDialRecvBufferSize = 1500;
@@ -271,13 +277,11 @@
 
 bool DialServiceImpl::DialSocket::ReadSocket() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (!socket_) {
+  if (!socket_)
     return false;
-  }
 
-  if (is_reading_) {
+  if (is_reading_)
     return false;
-  }
 
   int result = net::OK;
   bool result_ok = true;
@@ -326,10 +330,12 @@
     dial_service_->NotifyOnDeviceDiscovered(parsed_device);
 }
 
-// static
 bool DialServiceImpl::DialSocket::ParseResponse(const std::string& response,
                                                 const base::Time& response_time,
                                                 DialDeviceData* device) {
+  device->set_ip_address(recv_address_.address());
+  device->set_response_time(response_time);
+
   size_t headers_end =
       HttpUtil::LocateEndOfHeaders(response.c_str(), response.size());
   if (headers_end == 0 || headers_end == std::string::npos) {
@@ -346,7 +352,9 @@
   }
 
   GURL device_url(device_url_str);
-  if (!DialDeviceData::IsDeviceDescriptionUrl(device_url)) {
+  if (device->IsValidUrl(device_url)) {
+    device->set_device_description_url(device_url);
+  } else {
     return false;
   }
 
@@ -355,20 +363,30 @@
       device_id.empty()) {
     return false;
   }
-
   device->set_device_id(device_id);
-  device->set_device_description_url(device_url);
-  device->set_response_time(response_time);
 
-  // TODO(mfoltz): Parse the max-age value from the cache control header.
-  // http://crbug.com/165289
   std::string cache_control;
-  GetHeader(headers.get(), kSsdpCacheControlHeader, &cache_control);
+  if (GetHeader(headers.get(), kSsdpCacheControlHeader, &cache_control) &&
+      !cache_control.empty()) {
+    std::vector<std::string> cache_control_directives = base::SplitString(
+        cache_control, "=", base::WhitespaceHandling::TRIM_WHITESPACE,
+        base::SplitResult::SPLIT_WANT_NONEMPTY);
+    if (cache_control_directives.size() == 2 &&
+        base::EqualsCaseInsensitiveASCII(cache_control_directives[0],
+                                         kSsdpMaxAgeDirective)) {
+      int max_age = 0;
+      if (base::StringToInt(cache_control_directives[1], &max_age) &&
+          max_age > 0) {
+        device->set_max_age(std::min(max_age, kSsdpMaxMaxAge));
+      }
+    }
+  }
 
   std::string config_id;
   int config_id_int;
   if (GetHeader(headers.get(), kSsdpConfigIdHeader, &config_id) &&
-      base::StringToInt(config_id, &config_id_int)) {
+      !config_id.empty() && base::StringToInt(config_id, &config_id_int) &&
+      config_id_int > 0 && config_id_int <= kSsdpMaxConfigId) {
     device->set_config_id(config_id_int);
   }
   return true;
diff --git a/chrome/browser/media/router/discovery/dial/dial_service.h b/chrome/browser/media/router/discovery/dial/dial_service.h
index 9f054d0..2e00e81 100644
--- a/chrome/browser/media/router/discovery/dial/dial_service.h
+++ b/chrome/browser/media/router/discovery/dial/dial_service.h
@@ -25,9 +25,14 @@
 
 class DialDeviceData;
 
-// DialService accepts requests to discover devices, sends multiple M-SEARCH
-// requests via UDP multicast, and notifies observers when a DIAL-compliant
-// device responds.
+// DialService accepts requests to discover devices, sends multiple SSDP
+// M-SEARCH requests via UDP multicast, and notifies observers when a
+// DIAL-compliant device responds.
+//
+// The syntax of the M-SEARCH request and response is defined by Section 1.3
+// of the uPnP device architecture specification and related documents:
+//
+// http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf
 //
 // Each time Discover() is called, kDialNumRequests M-SEARCH requests are sent
 // (with a delay of kDialRequestIntervalMillis in between):
@@ -167,9 +172,9 @@
     // Parses a response into a DialDeviceData object. If the DIAL response is
     // invalid or does not contain enough information, then the return
     // value will be false and |device| is not changed.
-    static bool ParseResponse(const std::string& response,
-                              const base::Time& response_time,
-                              DialDeviceData* device);
+    bool ParseResponse(const std::string& response,
+                       const base::Time& response_time,
+                       DialDeviceData* device);
 
     // The UDP socket.
     std::unique_ptr<net::UDPSocket> socket_;
diff --git a/chrome/browser/media/router/discovery/dial/dial_service_unittest.cc b/chrome/browser/media/router/discovery/dial/dial_service_unittest.cc
index 33af47ba..fb82446 100644
--- a/chrome/browser/media/router/discovery/dial/dial_service_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_service_unittest.cc
@@ -78,6 +78,8 @@
   EXPECT_CALL(mock_observer_, OnDiscoveryFinished(A<DialService*>())).Times(1);
   dial_service_.BindAndAddSocket(mock_ip_);
   EXPECT_EQ(1u, dial_service_.dial_sockets_.size());
+  EXPECT_TRUE(dial_service_.dial_sockets_[0]);
+  EXPECT_FALSE(dial_service_.dial_sockets_[0]->IsClosed());
   dial_service_.SendOneRequest();
   base::RunLoop().RunUntilIdle();
   dial_service_.FinishDiscovery();
@@ -139,7 +141,8 @@
   dial_socket_->recv_buffer_ =
       base::MakeRefCounted<net::IOBufferWithSize>(response_size);
   strncpy(dial_socket_->recv_buffer_->data(), kValidResponse, response_size);
-  dial_socket_->recv_address_ = net::IPEndPoint(mock_ip_, 12345);
+  dial_socket_->recv_address_ =
+      net::IPEndPoint(net::IPAddress::IPv4Localhost(), 12345);
 
   DialDeviceData expected_device;
   expected_device.set_device_id("some_id");
@@ -161,55 +164,121 @@
 TEST_F(DialServiceTest, TestResponseParsing) {
   Time now = Time::Now();
 
-  // Successful case
+  // Force the socket address to match what is expected in the response.
+  dial_socket_->recv_address_ =
+      net::IPEndPoint(net::IPAddress::IPv4Localhost(), 12345);
+
+  // Successful case, all values parsed successfully.
   DialDeviceData parsed;
-  EXPECT_TRUE(
-      DialServiceImpl::DialSocket::ParseResponse(kValidResponse, now, &parsed));
+  EXPECT_TRUE(dial_socket_->ParseResponse(kValidResponse, now, &parsed));
   EXPECT_EQ("some_id", parsed.device_id());
   EXPECT_EQ("http://127.0.0.1/dd.xml", parsed.device_description_url().spec());
   EXPECT_EQ(1, parsed.config_id());
   EXPECT_EQ(now, parsed.response_time());
+  EXPECT_EQ(1800, parsed.max_age());
+
+  // Cases where we do not fail entirely, but we are unable to extract the
+  // CACHE-CONTROL or CONFIG header values.
+
+  // Max-age is too low
+  DialDeviceData parsed_max_age_low;
+  EXPECT_TRUE(
+      dial_socket_->ParseResponse("HTTP/1.1 OK\r\n"
+                                  "LOCATION: http://127.0.0.1/dd.xml\r\n"
+                                  "USN: some_id\r\n"
+                                  "CACHE-CONTROL: max-age=-100\r\n"
+                                  "CONFIGID.UPNP.ORG: 1\r\n\r\n",
+                                  now, &parsed_max_age_low));
+  EXPECT_EQ(-1, parsed_max_age_low.max_age());
+
+  // max-age is too high
+  DialDeviceData parsed_max_age_high;
+  EXPECT_TRUE(
+      dial_socket_->ParseResponse("HTTP/1.1 OK\r\n"
+                                  "LOCATION: http://127.0.0.1/dd.xml\r\n"
+                                  "USN: some_id\r\n"
+                                  "CACHE-CONTROL: max-age=5000\r\n"
+                                  "CONFIGID.UPNP.ORG: 1\r\n\r\n",
+                                  now, &parsed_max_age_high));
+  EXPECT_EQ(3600, parsed_max_age_high.max_age());
+
+  // Invalid CACHE-CONTROL directive
+  DialDeviceData parsed_invalid_cache;
+  EXPECT_TRUE(
+      dial_socket_->ParseResponse("HTTP/1.1 OK\r\n"
+                                  "LOCATION: http://127.0.0.1/dd.xml\r\n"
+                                  "USN: some_id\r\n"
+                                  "CACHE-CONTROL: xyzzy=100,\r\n"
+                                  "CONFIGID.UPNP.ORG: 1\r\n\r\n",
+                                  now, &parsed_invalid_cache));
+  EXPECT_EQ(-1, parsed_invalid_cache.max_age());
+
+  // Extra CACHE-CONTROL directives
+  DialDeviceData parsed_extra_cache;
+  EXPECT_TRUE(
+      dial_socket_->ParseResponse("HTTP/1.1 OK\r\n"
+                                  "LOCATION: http://127.0.0.1/dd.xml\r\n"
+                                  "USN: some_id\r\n"
+                                  "CACHE-CONTROL: bar=a,max-age=1800,foo=b\r\n"
+                                  "CONFIGID.UPNP.ORG: 1\r\n\r\n",
+                                  now, &parsed_extra_cache));
+  EXPECT_EQ(-1, parsed_extra_cache.max_age());
+
+  // Invalid CONFIGID.UPNP.ORG value
+  DialDeviceData parsed_invalid_config;
+  EXPECT_TRUE(
+      dial_socket_->ParseResponse("HTTP/1.1 OK\r\n"
+                                  "LOCATION: http://127.0.0.1/dd.xml\r\n"
+                                  "USN: some_id\r\n"
+                                  "CACHE-CONTROL: max-age=1000\r\n"
+                                  "CONFIGID.UPNP.ORG: -100\r\n\r\n",
+                                  now, &parsed_invalid_config));
+  EXPECT_EQ(-1, parsed_invalid_config.config_id());
 
   // Failure cases
   DialDeviceData not_parsed;
 
   // Empty, garbage
-  EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse(std::string(), now,
-                                                          &not_parsed));
-  EXPECT_FALSE(
-      DialServiceImpl::DialSocket::ParseResponse("\r\n\r\n", now, &not_parsed));
-  EXPECT_FALSE(
-      DialServiceImpl::DialSocket::ParseResponse("xyzzy", now, &not_parsed));
+  EXPECT_FALSE(dial_socket_->ParseResponse(std::string(), now, &not_parsed));
+  EXPECT_FALSE(dial_socket_->ParseResponse("\r\n\r\n", now, &not_parsed));
+  EXPECT_FALSE(dial_socket_->ParseResponse("xyzzy", now, &not_parsed));
 
   // No headers
-  EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse("HTTP/1.1 OK\r\n\r\n",
-                                                          now, &not_parsed));
+  EXPECT_FALSE(
+      dial_socket_->ParseResponse("HTTP/1.1 OK\r\n\r\n", now, &not_parsed));
+
+  // Missing USN
+  EXPECT_FALSE(
+      dial_socket_->ParseResponse("HTTP/1.1 OK\r\n"
+                                  "LOCATION: http://127.0.0.1/dd.xml\r\n\r\n",
+                                  now, &not_parsed));
+
+  // Empty USN
+  EXPECT_FALSE(
+      dial_socket_->ParseResponse("HTTP/1.1 OK\r\n"
+                                  "LOCATION: http://127.0.0.1/dd.xml\r\n"
+                                  "USN:\r\n\r\n",
+                                  now, &not_parsed));
 
   // Missing LOCATION
   EXPECT_FALSE(
-      DialServiceImpl::DialSocket::ParseResponse("HTTP/1.1 OK\r\n"
-                                                 "USN: some_id\r\n\r\n",
-                                                 now, &not_parsed));
+      dial_socket_->ParseResponse("HTTP/1.1 OK\r\n"
+                                  "USN: some_id\r\n\r\n",
+                                  now, &not_parsed));
 
   // Empty LOCATION
   EXPECT_FALSE(
-      DialServiceImpl::DialSocket::ParseResponse("HTTP/1.1 OK\r\n"
-                                                 "LOCATION:\r\n"
-                                                 "USN: some_id\r\n\r\n",
-                                                 now, &not_parsed));
+      dial_socket_->ParseResponse("HTTP/1.1 OK\r\n"
+                                  "LOCATION:\r\n"
+                                  "USN: some_id\r\n\r\n",
+                                  now, &not_parsed));
 
-  // Missing USN
-  EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse(
-      "HTTP/1.1 OK\r\n"
-      "LOCATION: http://127.0.0.1/dd.xml\r\n\r\n",
-      now, &not_parsed));
-
-  // Empty USN
-  EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse(
-      "HTTP/1.1 OK\r\n"
-      "LOCATION: http://127.0.0.1/dd.xml\r\n"
-      "USN:\r\n\r\n",
-      now, &not_parsed));
+  // Invalid LOCATION
+  EXPECT_FALSE(
+      dial_socket_->ParseResponse("HTTP/1.1 OK\r\n"
+                                  "LOCATION: http://127.8.8.8/dd.xml\r\n"
+                                  "USN:\r\n\r\n",
+                                  now, &not_parsed));
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
index 0d4b385..d34ca3b 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
@@ -581,6 +581,7 @@
 
   CastAnalytics::RecordCastChannelConnectResult(
       MediaRouterChannelConnectResults::SUCCESS);
+  CastAnalytics::RecordDeviceNameLength(cast_sink.sink().name().size());
   CastSinkExtraData& extra_data = cast_sink.cast_data();
   // Manually set device capabilities for sinks discovered via DIAL as DIAL
   // discovery does not provide capability info.
diff --git a/chrome/browser/media/router/discovery/media_sink_discovery_metrics.cc b/chrome/browser/media/router/discovery/media_sink_discovery_metrics.cc
index bc030c8..d51f233 100644
--- a/chrome/browser/media/router/discovery/media_sink_discovery_metrics.cc
+++ b/chrome/browser/media/router/discovery/media_sink_discovery_metrics.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/media/router/discovery/media_sink_discovery_metrics.h"
 
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/default_clock.h"
 
@@ -82,6 +83,8 @@
     "MediaRouter.Cast.Channel.ConnectResult";
 const char CastAnalytics::kHistogramCastChannelError[] =
     "MediaRouter.Cast.Channel.Error";
+const char CastAnalytics::kHistogramCastDeviceNameLength[] =
+    "MediaRouter.Cast.DeviceNameLength";
 const char CastAnalytics::kHistogramCastMdnsChannelOpenSuccess[] =
     "MediaRouter.Cast.Mdns.Channel.Open_Success";
 const char CastAnalytics::kHistogramCastMdnsChannelOpenFailure[] =
@@ -114,6 +117,11 @@
   }
 }
 
+// static
+void CastAnalytics::RecordDeviceNameLength(size_t length) {
+  base::UmaHistogramCounts100(kHistogramCastDeviceNameLength, length);
+}
+
 void WiredDisplayDeviceCountMetrics::RecordDeviceCounts(
     size_t available_device_count,
     size_t known_device_count) {
diff --git a/chrome/browser/media/router/discovery/media_sink_discovery_metrics.h b/chrome/browser/media/router/discovery/media_sink_discovery_metrics.h
index 8ff0305..48e9c0e 100644
--- a/chrome/browser/media/router/discovery/media_sink_discovery_metrics.h
+++ b/chrome/browser/media/router/discovery/media_sink_discovery_metrics.h
@@ -102,6 +102,7 @@
  public:
   static const char kHistogramCastChannelConnectResult[];
   static const char kHistogramCastChannelError[];
+  static const char kHistogramCastDeviceNameLength[];
   static const char kHistogramCastMdnsChannelOpenSuccess[];
   static const char kHistogramCastMdnsChannelOpenFailure[];
 
@@ -110,6 +111,7 @@
   static void RecordDeviceChannelError(MediaRouterChannelError channel_error);
   static void RecordDeviceChannelOpenDuration(bool success,
                                               const base::TimeDelta& duration);
+  static void RecordDeviceNameLength(size_t length);
 };
 
 // Metrics for wired display (local screen) sink counts.
diff --git a/chrome/browser/media/router/media_router_feature.cc b/chrome/browser/media/router/media_router_feature.cc
index cc1fbf2..9c84d37a 100644
--- a/chrome/browser/media/router/media_router_feature.cc
+++ b/chrome/browser/media/router/media_router_feature.cc
@@ -37,6 +37,8 @@
     "AllowAllSitesToInitiateMirroring", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kDialMediaRouteProvider{"DialMediaRouteProvider",
                                             base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kDialEnforceUrlIPAddress{"DialEnforceUrlIPAddress",
+                                             base::FEATURE_ENABLED_BY_DEFAULT};
 #endif  // !defined(OS_ANDROID)
 
 namespace {
diff --git a/chrome/browser/media/router/media_router_feature.h b/chrome/browser/media/router/media_router_feature.h
index 6f69a38..cac7edb 100644
--- a/chrome/browser/media/router/media_router_feature.h
+++ b/chrome/browser/media/router/media_router_feature.h
@@ -46,6 +46,11 @@
 // Presentation API. If disabled, only the allowlisted sites can do so.
 extern const base::Feature kAllowAllSitesToInitiateMirroring;
 
+// If enabled, HTTP requests for DIAL can only be made to URLs that contain the
+// target device IP address.
+// TODO(crbug.com/1270509): Remove this base::Feature once fully launched.
+extern const base::Feature kDialEnforceUrlIPAddress;
+
 namespace prefs {
 // Pref name for the enterprise policy for allowing Cast devices on all IPs.
 constexpr char kMediaRouterCastAllowAllIPs[] =
diff --git a/chrome/browser/media/webrtc/display_media_access_handler.cc b/chrome/browser/media/webrtc/display_media_access_handler.cc
index 92e9792..2d43714 100644
--- a/chrome/browser/media/webrtc/display_media_access_handler.cc
+++ b/chrome/browser/media/webrtc/display_media_access_handler.cc
@@ -16,7 +16,6 @@
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/bad_message.h"
-#include "chrome/browser/media/webrtc/capture_policy_utils.h"
 #include "chrome/browser/media/webrtc/desktop_capture_devices_util.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker_factory_impl.h"
 #include "chrome/browser/media/webrtc/native_desktop_media_list.h"
@@ -153,6 +152,17 @@
   }
 #endif  // defined(OS_MAC)
 
+  if (request.request_type == blink::MEDIA_DEVICE_UPDATE) {
+    DCHECK(!request.requested_video_device_id.empty());
+    // The share-this-tab-instead button is not shown when the screen capture is
+    // initiated with preferCurrentTab: true, so it should not be possible to
+    // reach HandleRequest in that case.
+    DCHECK(request.video_type !=
+           blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_THIS_TAB);
+    ProcessChangeSourceRequest(web_contents, request, std::move(callback));
+    return;
+  }
+
   if (request.video_type ==
           blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_THIS_TAB ||
       request.video_type ==
@@ -209,6 +219,24 @@
     ProcessQueuedAccessRequest(queue, web_contents);
 }
 
+void DisplayMediaAccessHandler::ProcessChangeSourceRequest(
+    content::WebContents* web_contents,
+    const content::MediaStreamRequest& request,
+    content::MediaResponseCallback callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  // Ensure we are observing the deletion of |web_contents|.
+  web_contents_collection_.StartObserving(web_contents);
+
+  RequestsQueue& queue = pending_requests_[web_contents];
+  queue.push_back(std::make_unique<PendingAccessRequest>(
+      /*picker=*/nullptr, request, std::move(callback)));
+  // If this is the only request then pop it. Otherwise, there is already a task
+  // scheduled to pop the next request.
+  if (queue.size() == 1)
+    ProcessQueuedAccessRequest(queue, web_contents);
+}
+
 void DisplayMediaAccessHandler::UpdateMediaRequestState(
     int render_process_id,
     int render_frame_id,
@@ -241,24 +269,64 @@
 
   const PendingAccessRequest& pending_request = *queue.front();
   UpdateTrusted(pending_request.request, false /* is_trusted */);
+
   const GURL& request_origin = pending_request.request.security_origin;
   AllowedScreenCaptureLevel capture_level =
       capture_policy::GetAllowedCaptureLevel(request_origin, web_contents);
 
   // If Capture is not allowed, then reject.
   if (capture_level == AllowedScreenCaptureLevel::kDisallowed) {
-    auto it = pending_requests_.find(web_contents);
-    DCHECK(it != pending_requests_.end());
-    RequestsQueue& mutable_queue = it->second;
-    PendingAccessRequest& mutable_request = *mutable_queue.front();
-    std::move(mutable_request.callback)
-        .Run(blink::MediaStreamDevices(),
-             blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
-             nullptr);
-    mutable_queue.pop_front();
+    RejectRequest(web_contents,
+                  blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED);
     return;
   }
 
+  if (pending_request.request.request_type == blink::MEDIA_DEVICE_UPDATE) {
+    ProcessQueuedChangeSourceRequest(pending_request.request, web_contents);
+  } else {
+    ProcessQueuedPickerRequest(pending_request, web_contents, capture_level,
+                               request_origin);
+  }
+}
+
+void DisplayMediaAccessHandler::ProcessQueuedChangeSourceRequest(
+    const content::MediaStreamRequest& request,
+    content::WebContents* web_contents) {
+  DCHECK(!request.requested_video_device_id.empty());
+  content::WebContentsMediaCaptureId web_contents_id;
+  if (!content::WebContentsMediaCaptureId::Parse(
+          request.requested_video_device_id, &web_contents_id)) {
+    RejectRequest(web_contents,
+                  blink::mojom::MediaStreamRequestResult::INVALID_STATE);
+    return;
+  }
+  content::DesktopMediaID media_id(content::DesktopMediaID::TYPE_WEB_CONTENTS,
+                                   content::DesktopMediaID::kNullId,
+                                   web_contents_id);
+  media_id.audio_share =
+      request.audio_type != blink::mojom::MediaStreamType::NO_SERVICE;
+  OnDisplaySurfaceSelected(web_contents, media_id);
+}
+
+void DisplayMediaAccessHandler::RejectRequest(
+    content::WebContents* web_contents,
+    blink::mojom::MediaStreamRequestResult result) {
+  auto it = pending_requests_.find(web_contents);
+  DCHECK(it != pending_requests_.end());
+  RequestsQueue& mutable_queue = it->second;
+  PendingAccessRequest& mutable_request = *mutable_queue.front();
+  std::move(mutable_request.callback)
+      .Run(blink::MediaStreamDevices(), result, nullptr);
+  mutable_queue.pop_front();
+  if (!mutable_queue.empty())
+    ProcessQueuedAccessRequest(mutable_queue, web_contents);
+}
+
+void DisplayMediaAccessHandler::ProcessQueuedPickerRequest(
+    const DisplayMediaAccessHandler::PendingAccessRequest& pending_request,
+    content::WebContents* web_contents,
+    AllowedScreenCaptureLevel capture_level,
+    const GURL& request_origin) {
   std::vector<DesktopMediaList::Type> media_types;
   if (pending_request.request.video_type ==
       blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_THIS_TAB) {
@@ -290,7 +358,7 @@
       media_types, web_contents, includable_web_contents_filter);
 
   DesktopMediaPicker::DoneCallback done_callback =
-      base::BindOnce(&DisplayMediaAccessHandler::OnPickerDialogResults,
+      base::BindOnce(&DisplayMediaAccessHandler::OnDisplaySurfaceSelected,
                      base::Unretained(this), web_contents);
   DesktopMediaPicker::Params picker_params;
   picker_params.web_contents = web_contents;
@@ -351,7 +419,7 @@
     ProcessQueuedAccessRequest(queue, web_contents);
 }
 
-void DisplayMediaAccessHandler::OnPickerDialogResults(
+void DisplayMediaAccessHandler::OnDisplaySurfaceSelected(
     content::WebContents* web_contents,
     content::DesktopMediaID media_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/media/webrtc/display_media_access_handler.h b/chrome/browser/media/webrtc/display_media_access_handler.h
index 9c93c6d7..32341c4 100644
--- a/chrome/browser/media/webrtc/display_media_access_handler.h
+++ b/chrome/browser/media/webrtc/display_media_access_handler.h
@@ -10,6 +10,7 @@
 #include "base/containers/flat_map.h"
 #include "chrome/browser/media/capture_access_handler_base.h"
 #include "chrome/browser/media/media_access_handler.h"
+#include "chrome/browser/media/webrtc/capture_policy_utils.h"
 #include "chrome/browser/media/webrtc/desktop_media_list.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker_factory.h"
@@ -64,11 +65,28 @@
       base::circular_deque<std::unique_ptr<PendingAccessRequest>>;
   using RequestsQueues = base::flat_map<content::WebContents*, RequestsQueue>;
 
+  void ProcessChangeSourceRequest(content::WebContents* web_contents,
+                                  const content::MediaStreamRequest& request,
+                                  content::MediaResponseCallback callback);
+
   // Processes one pending request. Requests are queued so that we display one
   // picker UI at a time for each content::WebContents.
   void ProcessQueuedAccessRequest(const RequestsQueue& queue,
                                   content::WebContents* web_contents);
 
+  void ProcessQueuedPickerRequest(
+      const DisplayMediaAccessHandler::PendingAccessRequest& pending_request,
+      content::WebContents* web_contents,
+      AllowedScreenCaptureLevel capture_level,
+      const GURL& request_origin);
+
+  void ProcessQueuedChangeSourceRequest(
+      const content::MediaStreamRequest& request,
+      content::WebContents* web_contents);
+
+  void RejectRequest(content::WebContents* web_contents,
+                     blink::mojom::MediaStreamRequestResult result);
+
   // Processes the first queued access request for |web_contents|
   // according to |request_result|. Calls ProcessQueuedAccessRequest if there
   // are more requests left in the queue.
@@ -79,8 +97,8 @@
   // Called back after the user chooses one of the possible desktop media
   // sources for the request that's currently being processed. If no |media_id|
   // is given, the request was rejected, either by the browser or by the user.
-  void OnPickerDialogResults(content::WebContents* web_contents,
-                             content::DesktopMediaID media_id);
+  void OnDisplaySurfaceSelected(content::WebContents* web_contents,
+                                content::DesktopMediaID media_id);
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Called back after checking Data Leak Prevention (DLP) restrictions.
diff --git a/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc b/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc
index 1533060..94e89a7 100644
--- a/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc
+++ b/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc
@@ -14,7 +14,9 @@
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/media/webrtc/fake_desktop_media_picker_factory.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/desktop_media_id.h"
 #include "content/public/browser/web_contents.h"
@@ -44,17 +46,26 @@
         std::move(picker_factory), false /* display_notification */);
   }
 
-  void ProcessRequest(
-      const content::DesktopMediaID& fake_desktop_media_id_response,
-      blink::mojom::MediaStreamRequestResult* request_result,
-      blink::MediaStreamDevices* devices_result,
+  content::WebContentsMediaCaptureId GetWebContentsMediaCaptureId() {
+    return content::WebContentsMediaCaptureId(
+        web_contents()->GetMainFrame()->GetProcess()->GetID(), 1);
+  }
+
+  FakeDesktopMediaPickerFactory::TestFlags MakePickerTestFlags(
       bool request_audio) {
-    FakeDesktopMediaPickerFactory::TestFlags test_flags[] = {
-        {true /* expect_screens */, true /* expect_windows*/,
-         true /* expect_tabs */, /* expect_current_tab, */ false, request_audio,
-         fake_desktop_media_id_response /* selected_source */}};
-    picker_factory_->SetTestFlags(test_flags, base::size(test_flags));
-    content::MediaStreamRequest request(
+    return FakeDesktopMediaPickerFactory::TestFlags(
+        {.expect_screens = true,
+         .expect_windows = true,
+         .expect_tabs = true,
+         .expect_current_tab = false,
+         .expect_audio = request_audio,
+         .selected_source =
+             content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
+                                     content::DesktopMediaID::kFakeId)});
+  }
+
+  content::MediaStreamRequest MakeRequest(bool request_audio) {
+    return content::MediaStreamRequest(
         web_contents()->GetMainFrame()->GetProcess()->GetID(),
         web_contents()->GetMainFrame()->GetRoutingID(), 0,
         GURL("http://origin/"), false, blink::MEDIA_GENERATE_STREAM,
@@ -64,9 +75,22 @@
         blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE,
         /*disable_local_echo=*/false,
         /*request_pan_tilt_zoom_permission=*/false);
+  }
 
-    base::RunLoop wait_loop;
-    content::MediaResponseCallback callback = base::BindOnce(
+  content::MediaStreamRequest MakeMediaDeviceUpdateRequest(bool request_audio) {
+    content::MediaStreamRequest request =
+        MakeRequest(request_audio /* request_audio */);
+    request.request_type = blink::MEDIA_DEVICE_UPDATE;
+    request.requested_video_device_id =
+        GetWebContentsMediaCaptureId().ToString();
+    return request;
+  }
+
+  content::MediaResponseCallback MakeCallback(
+      base::RunLoop* wait_loop,
+      blink::mojom::MediaStreamRequestResult* request_result,
+      blink::MediaStreamDevices* devices_result) {
+    return base::BindOnce(
         [](base::RunLoop* wait_loop,
            blink::mojom::MediaStreamRequestResult* request_result,
            blink::MediaStreamDevices* devices_result,
@@ -77,14 +101,47 @@
           *devices_result = devices;
           wait_loop->Quit();
         },
-        &wait_loop, request_result, devices_result);
+        wait_loop, request_result, devices_result);
+  }
+
+  void HandleRequest(const content::MediaStreamRequest& request,
+                     base::RunLoop* wait_loop,
+                     blink::mojom::MediaStreamRequestResult* request_result,
+                     blink::MediaStreamDevices* devices_result) {
+    access_handler_->HandleRequest(
+        web_contents(), request,
+        MakeCallback(wait_loop, request_result, devices_result),
+        nullptr /* extension */);
+  }
+
+  void SetTestFlags(
+      std::vector<FakeDesktopMediaPickerFactory::TestFlags> test_flags_vector) {
+    test_flags_ = std::move(test_flags_vector);
+    picker_factory_->SetTestFlags(&test_flags_[0], test_flags_.size());
+  }
+
+  void ProcessRequest(
+      const content::DesktopMediaID& fake_desktop_media_id_response,
+      blink::mojom::MediaStreamRequestResult* request_result,
+      blink::MediaStreamDevices* devices_result,
+      bool request_audio) {
+    SetTestFlags({{true /* expect_screens */, true /* expect_windows*/,
+                   true /* expect_tabs */, /* expect_current_tab, */ false,
+                   request_audio,
+                   fake_desktop_media_id_response /* selected_source */}});
+
+    content::MediaStreamRequest request = MakeRequest(request_audio);
+
+    base::RunLoop wait_loop;
+    content::MediaResponseCallback callback =
+        MakeCallback(&wait_loop, request_result, devices_result);
     access_handler_->HandleRequest(web_contents(), request, std::move(callback),
                                    nullptr /* extension */);
     wait_loop.Run();
-    EXPECT_TRUE(test_flags[0].picker_created);
+    EXPECT_TRUE(test_flags_[0].picker_created);
 
     access_handler_.reset();
-    EXPECT_TRUE(test_flags[0].picker_deleted);
+    EXPECT_TRUE(test_flags_[0].picker_deleted);
   }
 
   void NotifyWebContentsDestroyed() {
@@ -99,6 +156,35 @@
     return access_handler_->pending_requests_;
   }
 
+  void ChangeSourceRequestTest(
+      bool with_audio,
+      blink::mojom::MediaStreamRequestResult expected_result,
+      size_t expected_number_of_devices) {
+    blink::mojom::MediaStreamRequestResult result;
+    blink::MediaStreamDevices devices;
+    SetTestFlags({MakePickerTestFlags(with_audio /*request_audio*/)});
+
+    base::RunLoop wait_loop;
+    HandleRequest(MakeMediaDeviceUpdateRequest(with_audio /* request_audio */),
+                  &wait_loop, &result, &devices);
+    wait_loop.Run();
+    EXPECT_FALSE(test_flags_[0].picker_created);
+    access_handler_.reset();
+    EXPECT_EQ(expected_result, result);
+
+    ASSERT_EQ(expected_number_of_devices, devices.size());
+    if (expected_number_of_devices >= 1) {
+      EXPECT_EQ(blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE,
+                devices[0].type);
+    }
+    if (expected_number_of_devices >= 2) {
+      EXPECT_EQ(blink::mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE,
+                devices[1].type);
+    }
+  }
+
+  std::vector<FakeDesktopMediaPickerFactory::TestFlags> test_flags_;
+
  protected:
   FakeDesktopMediaPickerFactory* picker_factory_;
   std::unique_ptr<DisplayMediaAccessHandler> access_handler_;
@@ -110,6 +196,7 @@
   ProcessRequest(content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
                                          content::DesktopMediaID::kFakeId),
                  &result, &devices, false /* request_audio */);
+// TODO(https://crbug.com/1266425): Fix screen-capture tests on MacOS
 #if defined(OS_MAC)
   // Starting from macOS 10.15, screen capture requires system permissions
   // that are disabled by default.
@@ -134,6 +221,7 @@
                                         content::DesktopMediaID::kFakeId,
                                         true /* audio_share */);
   ProcessRequest(fake_media_id, &result, &devices, true /* request_audio */);
+// TODO(https://crbug.com/1266425): Fix screen-capture tests on MacOS
 #if defined(OS_MAC)
   // Starting from macOS 10.15, screen capture requires system permissions
   // that are disabled by default.
@@ -169,7 +257,7 @@
 
   // Setup Data Leak Prevention restriction.
   policy::MockDlpContentManager mock_dlp_content_manager;
-  policy::ScopedDlpContentManagerForTesting scoped_dlp_content_manager_(
+  policy::ScopedDlpContentManagerForTesting scoped_dlp_content_manager(
       &mock_dlp_content_manager);
   EXPECT_CALL(mock_dlp_content_manager, CheckScreenShareRestriction)
       .WillOnce([](const content::DesktopMediaID& media_id,
@@ -197,12 +285,10 @@
       blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE;
   const blink::mojom::MediaStreamType audio_stream_type =
       blink::mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE;
-  FakeDesktopMediaPickerFactory::TestFlags test_flags[] = {
-      {true /* expect_screens */, true /* expect_windows*/,
-       true /* expect_tabs */, false /* expect_current_tab */,
-       true /* expect_audio */, content::DesktopMediaID(),
-       true /* cancelled */}};
-  picker_factory_->SetTestFlags(test_flags, base::size(test_flags));
+  SetTestFlags({{true /* expect_screens */, true /* expect_windows*/,
+                 true /* expect_tabs */, false /* expect_current_tab */,
+                 true /* expect_audio */, content::DesktopMediaID(),
+                 true /* cancelled */}});
   content::MediaStreamRequest request(
       render_process_id, render_frame_id, page_request_id,
       GURL("http://origin/"), false, blink::MEDIA_GENERATE_STREAM,
@@ -211,7 +297,7 @@
   content::MediaResponseCallback callback;
   access_handler_->HandleRequest(web_contents(), request, std::move(callback),
                                  nullptr /* extension */);
-  EXPECT_TRUE(test_flags[0].picker_created);
+  EXPECT_TRUE(test_flags_[0].picker_created);
   EXPECT_EQ(1u, GetRequestQueues().size());
   auto queue_it = GetRequestQueues().find(web_contents());
   EXPECT_TRUE(queue_it != GetRequestQueues().end());
@@ -224,7 +310,7 @@
   queue_it = GetRequestQueues().find(web_contents());
   EXPECT_TRUE(queue_it != GetRequestQueues().end());
   EXPECT_EQ(0u, queue_it->second.size());
-  EXPECT_TRUE(test_flags[0].picker_deleted);
+  EXPECT_TRUE(test_flags_[0].picker_deleted);
   access_handler_.reset();
 }
 
@@ -237,12 +323,10 @@
       blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE;
   const blink::mojom::MediaStreamType audio_stream_type =
       blink::mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE;
-  FakeDesktopMediaPickerFactory::TestFlags test_flags[] = {
-      {true /* expect_screens */, true /* expect_windows*/,
-       true /* expect_tabs */, false /* expect_current_tab */,
-       true /* expect_audio */, content::DesktopMediaID(),
-       true /* cancelled */}};
-  picker_factory_->SetTestFlags(test_flags, base::size(test_flags));
+  SetTestFlags({{true /* expect_screens */, true /* expect_windows*/,
+                 true /* expect_tabs */, false /* expect_current_tab */,
+                 true /* expect_audio */, content::DesktopMediaID(),
+                 true /* cancelled */}});
   content::MediaStreamRequest request(
       render_process_id, render_frame_id, page_request_id,
       GURL("http://origin/"), false, blink::MEDIA_GENERATE_STREAM,
@@ -273,12 +357,10 @@
       blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE;
   const blink::mojom::MediaStreamType audio_stream_type =
       blink::mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE;
-  FakeDesktopMediaPickerFactory::TestFlags test_flags[] = {
-      {true /* expect_screens */, true /* expect_windows*/,
-       true /* expect_tabs */, false /* expect_current_tab */,
-       true /* expect_audio */, content::DesktopMediaID(),
-       true /* cancelled */}};
-  picker_factory_->SetTestFlags(test_flags, base::size(test_flags));
+  SetTestFlags({{true /* expect_screens */, true /* expect_windows*/,
+                 true /* expect_tabs */, false /* expect_current_tab */,
+                 true /* expect_audio */, content::DesktopMediaID(),
+                 true /* cancelled */}});
   content::MediaStreamRequest request(
       render_process_id, render_frame_id, page_request_id,
       GURL("http://origin/"), false, blink::MEDIA_GENERATE_STREAM,
@@ -300,12 +382,10 @@
 }
 
 TEST_F(DisplayMediaAccessHandlerTest, WebContentsDestroyed) {
-  FakeDesktopMediaPickerFactory::TestFlags test_flags[] = {
-      {true /* expect_screens */, true /* expect_windows*/,
-       true /* expect_tabs */, false /* expect_current_tab */,
-       false /* expect_audio */, content::DesktopMediaID(),
-       true /* cancelled */}};
-  picker_factory_->SetTestFlags(test_flags, base::size(test_flags));
+  SetTestFlags({{true /* expect_screens */, true /* expect_windows*/,
+                 true /* expect_tabs */, false /* expect_current_tab */,
+                 false /* expect_audio */, content::DesktopMediaID(),
+                 true /* cancelled */}});
   content::MediaStreamRequest request(
       web_contents()->GetMainFrame()->GetProcess()->GetID(),
       web_contents()->GetMainFrame()->GetRoutingID(), 0, GURL("http://origin/"),
@@ -316,7 +396,7 @@
   content::MediaResponseCallback callback;
   access_handler_->HandleRequest(web_contents(), request, std::move(callback),
                                  nullptr /* extension */);
-  EXPECT_TRUE(test_flags[0].picker_created);
+  EXPECT_TRUE(test_flags_[0].picker_created);
   EXPECT_EQ(1u, GetRequestQueues().size());
   auto queue_it = GetRequestQueues().find(web_contents());
   EXPECT_TRUE(queue_it != GetRequestQueues().end());
@@ -328,21 +408,19 @@
 }
 
 TEST_F(DisplayMediaAccessHandlerTest, MultipleRequests) {
-  FakeDesktopMediaPickerFactory::TestFlags test_flags[] = {
-      {true /* expect_screens */, true /* expect_windows*/,
-       true /* expect_tabs */, false /* expect_current_tab */,
-       false /* expect_audio */,
-       content::DesktopMediaID(
-           content::DesktopMediaID::TYPE_SCREEN,
-           content::DesktopMediaID::kFakeId) /* selected_source */},
-      {true /* expect_screens */, true /* expect_windows*/,
-       true /* expect_tabs */, false /* expect_current_tab */,
-       false /* expect_audio */,
-       content::DesktopMediaID(
-           content::DesktopMediaID::TYPE_WINDOW,
-           content::DesktopMediaID::kNullId) /* selected_source */}};
+  SetTestFlags({{true /* expect_screens */, true /* expect_windows*/,
+                 true /* expect_tabs */, false /* expect_current_tab */,
+                 false /* expect_audio */,
+                 content::DesktopMediaID(
+                     content::DesktopMediaID::TYPE_SCREEN,
+                     content::DesktopMediaID::kFakeId) /* selected_source */},
+                {true /* expect_screens */, true /* expect_windows*/,
+                 true /* expect_tabs */, false /* expect_current_tab */,
+                 false /* expect_audio */,
+                 content::DesktopMediaID(
+                     content::DesktopMediaID::TYPE_WINDOW,
+                     content::DesktopMediaID::kNullId) /* selected_source */}});
   const size_t kTestFlagCount = 2;
-  picker_factory_->SetTestFlags(test_flags, kTestFlagCount);
 
   blink::mojom::MediaStreamRequestResult result;
   blink::MediaStreamDevices devices;
@@ -372,8 +450,9 @@
                                    nullptr /* extension */);
   }
   wait_loop[0].Run();
-  EXPECT_TRUE(test_flags[0].picker_created);
-  EXPECT_TRUE(test_flags[0].picker_deleted);
+  EXPECT_TRUE(test_flags_[0].picker_created);
+  EXPECT_TRUE(test_flags_[0].picker_deleted);
+// TODO(https://crbug.com/1266425): Fix screen-capture tests on MacOS
 #if defined(OS_MAC)
   // Starting from macOS 10.15, screen capture requires system permissions
   // that are disabled by default.
@@ -390,10 +469,10 @@
             devices[0].type);
 
   blink::MediaStreamDevice first_device = devices[0];
-  EXPECT_TRUE(test_flags[1].picker_created);
-  EXPECT_FALSE(test_flags[1].picker_deleted);
+  EXPECT_TRUE(test_flags_[1].picker_created);
+  EXPECT_FALSE(test_flags_[1].picker_deleted);
   wait_loop[1].Run();
-  EXPECT_TRUE(test_flags[1].picker_deleted);
+  EXPECT_TRUE(test_flags_[1].picker_deleted);
   EXPECT_EQ(blink::mojom::MediaStreamRequestResult::OK, result);
   EXPECT_EQ(1u, devices.size());
   EXPECT_EQ(blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE,
@@ -402,3 +481,158 @@
 
   access_handler_.reset();
 }
+
+TEST_F(DisplayMediaAccessHandlerTest,
+       ChangeSourceWithoutAudioRequestPermissionGiven) {
+  ChangeSourceRequestTest(
+      /*with_audio=*/false,
+      /*expected_result=*/blink::mojom::MediaStreamRequestResult::OK,
+      /*expected_number_of_devices=*/1u);
+}
+
+TEST_F(DisplayMediaAccessHandlerTest,
+       ChangeSourceWithAudioRequestPermissionGiven) {
+  blink::MediaStreamDevices devices;
+  ChangeSourceRequestTest(
+      /*with_audio=*/true,
+      /*expected_result=*/blink::mojom::MediaStreamRequestResult::OK,
+      /*expected_number_of_devices=*/2u);
+}
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(DisplayMediaAccessHandlerTest, ChangeSourceDlpRestricted) {
+  const content::DesktopMediaID media_id(
+      content::DesktopMediaID::TYPE_WEB_CONTENTS,
+      content::DesktopMediaID::kNullId, GetWebContentsMediaCaptureId());
+
+  // Setup Data Leak Prevention restriction.
+  policy::MockDlpContentManager mock_dlp_content_manager;
+  policy::ScopedDlpContentManagerForTesting scoped_dlp_content_manager_(
+      &mock_dlp_content_manager);
+  EXPECT_CALL(mock_dlp_content_manager, CheckScreenShareRestriction)
+      .WillOnce([](const content::DesktopMediaID& media_id,
+                   const std::u16string& application_title,
+                   base::OnceCallback<void(bool)> callback) {
+        // Disallow
+        std::move(callback).Run(false);
+      });
+
+  ChangeSourceRequestTest(
+      /*with_audio=*/false,
+      /*expected_result=*/
+      blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+      /*expected_number_of_devices=*/0u);
+}
+#endif
+
+TEST_F(DisplayMediaAccessHandlerTest, ChangeSourceWithPendingPickerRequest) {
+  SetTestFlags({MakePickerTestFlags(false /*request_audio*/),
+                MakePickerTestFlags(false /*request_audio*/)});
+
+  blink::mojom::MediaStreamRequestResult results[2];
+  blink::MediaStreamDevices devices[2];
+  base::RunLoop wait_loop[2];
+
+  HandleRequest(MakeRequest(false /* request_audio */), &wait_loop[0],
+                &results[0], &devices[0]);
+  HandleRequest(MakeMediaDeviceUpdateRequest(false /* request_audio */),
+                &wait_loop[1], &results[1], &devices[1]);
+
+  wait_loop[0].Run();
+  EXPECT_TRUE(test_flags_[0].picker_created);
+  EXPECT_TRUE(test_flags_[0].picker_deleted);
+// TODO(https://crbug.com/1266425): Fix screen-capture tests on MacOS
+#if defined(OS_MAC)
+  // Starting from macOS 10.15, screen capture requires system permissions
+  // that are disabled by default.
+  if (base::mac::IsAtLeastOS10_15()) {
+    EXPECT_EQ(blink::mojom::MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED,
+              results[0]);
+    access_handler_.reset();
+    return;
+  }
+#endif
+  EXPECT_EQ(blink::mojom::MediaStreamRequestResult::OK, results[0]);
+  EXPECT_FALSE(test_flags_[1].picker_created);
+  EXPECT_FALSE(test_flags_[1].picker_deleted);
+  EXPECT_EQ(blink::mojom::MediaStreamRequestResult::OK, results[1]);
+  access_handler_.reset();
+}
+
+TEST_F(DisplayMediaAccessHandlerTest,
+       ChangeSourcePolicyViolationWithPendingPickerRequest) {
+  SetTestFlags({MakePickerTestFlags(false /*request_audio*/),
+                MakePickerTestFlags(false /*request_audio*/)});
+
+  blink::mojom::MediaStreamRequestResult results[2];
+  blink::MediaStreamDevices devices[2];
+  base::RunLoop wait_loop[2];
+
+  HandleRequest(MakeRequest(false /* request_audio */), &wait_loop[0],
+                &results[0], &devices[0]);
+  HandleRequest(MakeMediaDeviceUpdateRequest(false /* request_audio */),
+                &wait_loop[1], &results[1], &devices[1]);
+
+  // Policy is changed after the requests are received, but before they are
+  // processed in the call to wait_loop.Run() below.
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
+  profile->GetPrefs()->SetBoolean(prefs::kScreenCaptureAllowed, false);
+
+  wait_loop[0].Run();
+// TODO(https://crbug.com/1266425): Fix screen-capture tests on MacOS
+#if defined(OS_MAC)
+  // Starting from macOS 10.15, screen capture requires system permissions
+  // that are disabled by default.
+  if (base::mac::IsAtLeastOS10_15()) {
+    EXPECT_EQ(blink::mojom::MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED,
+              results[0]);
+    access_handler_.reset();
+    return;
+  }
+#endif
+  EXPECT_FALSE(test_flags_[1].picker_created);
+  EXPECT_FALSE(test_flags_[1].picker_deleted);
+  EXPECT_EQ(blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+            results[1]);
+  access_handler_.reset();
+}
+
+TEST_F(DisplayMediaAccessHandlerTest,
+       MalformedChangeSourceBetweenPickerRequests) {
+  SetTestFlags({{MakePickerTestFlags(false /*request_audio*/)}});
+
+  blink::mojom::MediaStreamRequestResult results[3];
+  blink::MediaStreamDevices devices[3];
+  base::RunLoop wait_loop[3];
+
+  HandleRequest(MakeRequest(false /* request_audio */), &wait_loop[0],
+                &results[0], &devices[0]);
+  {
+    content::MediaStreamRequest request =
+        MakeMediaDeviceUpdateRequest(false /* request_audio */);
+    request.requested_video_device_id = "MALFORMED";
+    HandleRequest(request, &wait_loop[1], &results[1], &devices[1]);
+  }
+  HandleRequest(MakeMediaDeviceUpdateRequest(false /* request_audio */),
+                &wait_loop[2], &results[2], &devices[2]);
+
+  wait_loop[0].Run();
+  EXPECT_TRUE(test_flags_[0].picker_created);
+  EXPECT_TRUE(test_flags_[0].picker_deleted);
+// TODO(https://crbug.com/1266425): Fix screen-capture tests on MacOS
+#if defined(OS_MAC)
+  // Starting from macOS 10.15, screen capture requires system permissions
+  // that are disabled by default.
+  if (base::mac::IsAtLeastOS10_15()) {
+    EXPECT_EQ(blink::mojom::MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED,
+              results[0]);
+    access_handler_.reset();
+    return;
+  }
+#endif
+  EXPECT_EQ(blink::mojom::MediaStreamRequestResult::OK, results[0]);
+  EXPECT_EQ(blink::mojom::MediaStreamRequestResult::INVALID_STATE, results[1]);
+  EXPECT_EQ(blink::mojom::MediaStreamRequestResult::OK, results[2]);
+  access_handler_.reset();
+}
diff --git a/chrome/browser/media/webrtc/native_desktop_media_list.cc b/chrome/browser/media/webrtc/native_desktop_media_list.cc
index f777d8e..aa05a5dd 100644
--- a/chrome/browser/media/webrtc/native_desktop_media_list.cc
+++ b/chrome/browser/media/webrtc/native_desktop_media_list.cc
@@ -365,7 +365,14 @@
     if (source.id.type != DesktopMediaID::TYPE_WINDOW)
       continue;
 
-#if defined(USE_AURA)
+// TODO(https://crbug.com/1270801): The capturer id to aura::Window mapping on
+// lacros is currently broken because they both separately use monotonically
+// increasing ints as ids. This causes collisions where we mistakenly try to
+// capture non-aura windows as aura windows. While the preview matches what is
+// ultimately captured, it does not match the title of the window in the preview
+// and is both unexpected for the user and means that the collided non-aura
+// window cannot be captured.
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_LACROS)
     aura::WindowTreeHost* const host =
         aura::WindowTreeHost::GetForAcceleratedWidget(
             *reinterpret_cast<gfx::AcceleratedWidget*>(&source.id.id));
diff --git a/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc b/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
index 5149a81..0f5a418 100644
--- a/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
@@ -16,8 +16,13 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/infobars/content/content_infobar_manager.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "components/infobars/core/infobar.h"
 #include "components/prefs/pref_service.h"
+#include "components/url_formatter/elide_url.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
@@ -25,6 +30,7 @@
 #include "media/base/media_switches.h"
 #include "net/base/filename_util.h"
 #include "third_party/blink/public/common/features.h"
+#include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_MAC)
 #include "base/mac/mac_util.h"
@@ -41,6 +47,15 @@
 static const char kMainHtmlPage[] = "/webrtc/webrtc_getdisplaymedia_test.html";
 static const char kMainHtmlFileName[] = "webrtc_getdisplaymedia_test.html";
 static const char kSameOriginRenamedTitle[] = "Renamed Same Origin Tab";
+// TODO(https://crbug.com/1215089): Enable on Lacros.
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
+// The captured tab is identified by its title.
+static const char kCapturedTabTitle[] = "totally-unique-captured-page-title";
+static const char kCapturedPageMain[] = "/webrtc/captured_page_main.html";
+static const std::u16string kShareThisTabInsteadMessage =
+    u"Share this tab instead";
+static const std::u16string kViewTabMessagePrefix = u"View tab:";
+#endif
 
 enum class DisplaySurfaceType { kTab, kWindow, kScreen };
 
@@ -83,7 +98,7 @@
                         const std::string& constraints,
                         bool is_fake_ui,
                         bool expect_success,
-                        bool is_capturing_screen) {
+                        bool is_tab_capture) {
   std::string result;
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
       tab->GetMainFrame(),
@@ -92,7 +107,7 @@
       &result));
 
 #if defined(OS_MAC)
-  if (!is_fake_ui && is_capturing_screen &&
+  if (!is_fake_ui && !is_tab_capture &&
       system_media_permissions::CheckSystemScreenCapturePermission() !=
           system_media_permissions::SystemPermission::kAllowed) {
     expect_success = false;
@@ -119,6 +134,30 @@
   return net::FilePathToFileURL(path);
 }
 
+// TODO(https://crbug.com/1215089): Enable on Lacros.
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
+infobars::ContentInfoBarManager* GetInfoBarManager(
+    content::WebContents* web_contents) {
+  return infobars::ContentInfoBarManager::FromWebContents(web_contents);
+}
+
+ConfirmInfoBarDelegate* GetDelegate(content::WebContents* web_contents) {
+  return static_cast<ConfirmInfoBarDelegate*>(
+      GetInfoBarManager(web_contents)->infobar_at(0)->delegate());
+}
+
+bool HasSecondaryButton(content::WebContents* web_contents) {
+  return GetDelegate(web_contents)->GetButtons() &
+         ConfirmInfoBarDelegate::InfoBarButton::BUTTON_CANCEL;
+}
+
+std::u16string GetSecondaryButtonLabel(content::WebContents* web_contents) {
+  DCHECK(HasSecondaryButton(web_contents));  // Test error otherwise.
+  return GetDelegate(web_contents)
+      ->GetButtonLabel(ConfirmInfoBarDelegate::InfoBarButton::BUTTON_CANCEL);
+}
+#endif
+
 }  // namespace
 
 // Base class for top level tests for getDisplayMedia().
@@ -185,7 +224,7 @@
   content::WebContents* tab = OpenTestPageInNewTab(kMainHtmlPage);
   RunGetDisplayMedia(tab, GetConstraints(/*video=*/true, /*audio=*/false),
                      /*is_fake_ui=*/false, test_config_.accept_this_tab_capture,
-                     /*is_capturing_screen=*/!PreferCurrentTab());
+                     /*is_tab_capture=*/PreferCurrentTab());
 }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -197,7 +236,7 @@
   content::WebContents* tab = OpenTestPageInNewTab(kMainHtmlPage);
   RunGetDisplayMedia(tab, GetConstraints(/*video=*/true, /*audio=*/false),
                      /*is_fake_ui=*/false, test_config_.accept_this_tab_capture,
-                     /*is_capturing_screen=*/!PreferCurrentTab());
+                     /*is_tab_capture=*/PreferCurrentTab());
 
   if (!test_config_.accept_this_tab_capture) {
     // This test is not relevant for this parameterized test case because it
@@ -250,7 +289,7 @@
   content::WebContents* tab = OpenTestPageInNewTab(kMainHtmlPage);
   RunGetDisplayMedia(tab, GetConstraints(/*video=*/true, /*audio=*/true),
                      /*is_fake_ui=*/false, test_config_.accept_this_tab_capture,
-                     /*is_capturing_screen=*/!PreferCurrentTab());
+                     /*is_tab_capture=*/PreferCurrentTab());
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -297,7 +336,7 @@
   content::WebContents* tab = OpenTestPageInNewTab(kMainHtmlPage);
   RunGetDisplayMedia(tab, GetConstraints(/*video=*/true, /*audio=*/false),
                      /*is_fake_ui=*/true, /*expect_success=*/true,
-                     /*is_capturing_screen=*/!PreferCurrentTab());
+                     /*is_tab_capture=*/PreferCurrentTab());
 
   std::string result;
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
@@ -320,7 +359,7 @@
   content::WebContents* tab = OpenTestPageInNewTab(kMainHtmlPage);
   RunGetDisplayMedia(tab, GetConstraints(/*video=*/true, /*audio=*/true),
                      /*is_fake_ui=*/true, /*expect_success=*/true,
-                     /*is_capturing_screen=*/!PreferCurrentTab());
+                     /*is_tab_capture=*/PreferCurrentTab());
 
   std::string result;
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
@@ -343,7 +382,7 @@
       test_config_.should_prefer_current_tab_ ? "true" : "false");
   RunGetDisplayMedia(tab, constraints,
                      /*is_fake_ui=*/true, /*expect_success=*/true,
-                     /*is_capturing_screen=*/!PreferCurrentTab());
+                     /*is_tab_capture=*/PreferCurrentTab());
 
   std::string result;
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
@@ -500,7 +539,7 @@
 
   RunGetDisplayMedia(capturing_tab, "{video: true}", /*is_fake_ui=*/false,
                      /*expect_success=*/true,
-                     /*is_capturing_screen=*/false);
+                     /*is_tab_capture=*/true);
   CloseAppWindow(app_window);
 }
 
@@ -554,7 +593,7 @@
   RunGetDisplayMedia(capturing_tab,
                      GetConstraints(/*video=*/true, /*audio=*/true),
                      /*is_fake_ui=*/false, /*expect_success=*/true,
-                     /*is_capturing_screen=*/false);
+                     /*is_tab_capture=*/true);
 
   // Though the target tab should've been focused as a result of starting the
   // capture, we don't want to take a dependency on that behavior. Ensure that
@@ -593,7 +632,7 @@
   RunGetDisplayMedia(capturing_tab,
                      GetConstraints(/*video=*/true, /*audio=*/true),
                      /*is_fake_ui=*/false, /*expect_success=*/true,
-                     /*is_capturing_screen=*/false);
+                     /*is_tab_capture=*/true);
 
   // Though the target tab should've been focused as a result of starting the
   // capture, we don't want to take a dependency on that behavior. Ensure that
@@ -783,3 +822,77 @@
     EXPECT_EQ(GetAudioTrackType(), "MediaStreamTrack");
   }
 }
+
+// TODO(https://crbug.com/1215089): Enable this test suite on Lacros.
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
+class GetDisplayMediaChangeSourceBrowserTest : public WebRtcTestBase {
+ public:
+  void SetUpInProcessBrowserTestFixture() override {
+    WebRtcTestBase::SetUpInProcessBrowserTestFixture();
+
+    DetectErrorsInJavaScript();
+
+    base::FilePath test_dir;
+    ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitch(
+        switches::kEnableExperimentalWebPlatformFeatures);
+    command_line->AppendSwitchASCII(
+        switches::kAutoSelectTabCaptureSourceByTitle, kCapturedTabTitle);
+  }
+};
+
+// TODO(crbug.com/1272023): Flaky on Linux Wayland, Win7.
+IN_PROC_BROWSER_TEST_F(GetDisplayMediaChangeSourceBrowserTest,
+                       DISABLED_ChangeSource) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  content::WebContents* captured_tab = OpenTestPageInNewTab(kCapturedPageMain);
+  content::WebContents* other_tab = OpenTestPageInNewTab(kMainHtmlPage);
+  content::WebContents* capturing_tab = OpenTestPageInNewTab(kMainHtmlPage);
+
+  RunGetDisplayMedia(capturing_tab, "{video: true}", /*is_fake_ui=*/false,
+                     /*expect_success=*/true,
+                     /*is_capturing_screen=*/false);
+
+  EXPECT_TRUE(captured_tab->IsBeingCaptured());
+  EXPECT_FALSE(other_tab->IsBeingCaptured());
+  EXPECT_FALSE(capturing_tab->IsBeingCaptured());
+  EXPECT_EQ(GetSecondaryButtonLabel(captured_tab),
+            l10n_util::GetStringFUTF16(
+                IDS_TAB_SHARING_INFOBAR_SWITCH_TO_BUTTON,
+                url_formatter::FormatOriginForSecurityDisplay(
+                    captured_tab->GetMainFrame()->GetLastCommittedOrigin(),
+                    url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS)));
+  EXPECT_EQ(GetSecondaryButtonLabel(other_tab), kShareThisTabInsteadMessage);
+  EXPECT_EQ(GetSecondaryButtonLabel(capturing_tab),
+            l10n_util::GetStringFUTF16(
+                IDS_TAB_SHARING_INFOBAR_SWITCH_TO_BUTTON,
+                url_formatter::FormatOriginForSecurityDisplay(
+                    capturing_tab->GetMainFrame()->GetLastCommittedOrigin(),
+                    url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS)));
+
+  // Click the secondary button, i.e., the "Share this tab instead" button
+  GetDelegate(other_tab)->Cancel();
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(captured_tab->IsBeingCaptured());
+  EXPECT_TRUE(other_tab->IsBeingCaptured());
+  EXPECT_FALSE(capturing_tab->IsBeingCaptured());
+  EXPECT_EQ(GetSecondaryButtonLabel(captured_tab), kShareThisTabInsteadMessage);
+  EXPECT_EQ(GetSecondaryButtonLabel(other_tab),
+            l10n_util::GetStringFUTF16(
+                IDS_TAB_SHARING_INFOBAR_SWITCH_TO_BUTTON,
+                url_formatter::FormatOriginForSecurityDisplay(
+                    other_tab->GetMainFrame()->GetLastCommittedOrigin(),
+                    url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS)));
+  EXPECT_EQ(GetSecondaryButtonLabel(capturing_tab),
+            l10n_util::GetStringFUTF16(
+                IDS_TAB_SHARING_INFOBAR_SWITCH_TO_BUTTON,
+                url_formatter::FormatOriginForSecurityDisplay(
+                    capturing_tab->GetMainFrame()->GetLastCommittedOrigin(),
+                    url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS)));
+}
+#endif
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest.cc b/chrome/browser/media/webrtc/webrtc_interactive_uitest.cc
similarity index 90%
rename from chrome/browser/media/webrtc/webrtc_browsertest.cc
rename to chrome/browser/media/webrtc/webrtc_interactive_uitest.cc
index 09db7a2..595aee4 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_interactive_uitest.cc
@@ -33,8 +33,7 @@
 #include "base/mac/mac_util.h"
 #endif
 
-static const char kMainWebrtcTestHtmlPage[] =
-    "/webrtc/webrtc_jsep01_test.html";
+static const char kMainWebrtcTestHtmlPage[] = "/webrtc/webrtc_jsep01_test.html";
 
 static const char kKeygenAlgorithmRsa[] =
     "{ name: \"RSASSA-PKCS1-v1_5\", modulusLength: 2048, publicExponent: "
@@ -96,8 +95,8 @@
     CloseDatabase(left_tab_);
     DeleteDatabase(left_tab_);
 
-    SetupPeerconnectionWithCertificateAndLocalStream(
-        left_tab_, "gCertificateClone");
+    SetupPeerconnectionWithCertificateAndLocalStream(left_tab_,
+                                                     "gCertificateClone");
     SetupPeerconnectionWithLocalStream(right_tab_, cert_keygen_alg);
 
     NegotiateCall(left_tab_, right_tab_);
@@ -161,21 +160,12 @@
   content::WebContents* right_tab_;
 };
 
-// TODO(898546): many of these tests are failing on ASan builds.
-// They are also flaky crashers on Linux.
-#if defined(ADDRESS_SANITIZER) || defined(OS_LINUX) || defined(OS_CHROMEOS)
-#define MAYBE_WebRtcBrowserTest DISABLED_WebRtcBrowserTest
-class DISABLED_WebRtcBrowserTest : public WebRtcBrowserTest {};
-#else
-#define MAYBE_WebRtcBrowserTest WebRtcBrowserTest
-#endif
-
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
                        RunsAudioVideoWebRTCCallInTwoTabsVP8) {
   RunsAudioVideoWebRTCCallInTwoTabs("VP8");
 }
 
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
                        RunsAudioVideoWebRTCCallInTwoTabsVP9) {
   RunsAudioVideoWebRTCCallInTwoTabs("VP9");
 }
@@ -187,9 +177,10 @@
   // Only run test if run-time feature corresponding to |rtc_use_h264| is on.
   if (!base::FeatureList::IsEnabled(
           blink::features::kWebRtcH264WithOpenH264FFmpeg)) {
-    LOG(WARNING) << "Run-time feature WebRTC-H264WithOpenH264FFmpeg disabled. "
-        "Skipping WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsH264 "
-        "(test \"OK\")";
+    LOG(WARNING)
+        << "Run-time feature WebRTC-H264WithOpenH264FFmpeg disabled. "
+           "Skipping WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsH264 "
+           "(test \"OK\")";
     return;
   }
 
@@ -219,14 +210,14 @@
   ASSERT_FALSE(tab->IsCrashed());
 }
 
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
                        RunsAudioVideoWebRTCCallInTwoTabsOfferRsaAnswerRsa) {
   RunsAudioVideoWebRTCCallInTwoTabs(WebRtcTestBase::kUseDefaultVideoCodec,
                                     false /* prefer_hw_video_codec */,
                                     kKeygenAlgorithmRsa, kKeygenAlgorithmRsa);
 }
 
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
                        RunsAudioVideoWebRTCCallInTwoTabsOfferEcdsaAnswerEcdsa) {
   RunsAudioVideoWebRTCCallInTwoTabs(
       WebRtcTestBase::kUseDefaultVideoCodec, false /* prefer_hw_video_codec */,
@@ -234,32 +225,32 @@
 }
 
 IN_PROC_BROWSER_TEST_F(
-    MAYBE_WebRtcBrowserTest,
+    WebRtcBrowserTest,
     RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificateRsa) {
   RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificate(kKeygenAlgorithmRsa);
 }
 
 IN_PROC_BROWSER_TEST_F(
-    MAYBE_WebRtcBrowserTest,
+    WebRtcBrowserTest,
     RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificateEcdsa) {
   RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificate(kKeygenAlgorithmEcdsa);
 }
 
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
                        RunsAudioVideoWebRTCCallInTwoTabsOfferRsaAnswerEcdsa) {
   RunsAudioVideoWebRTCCallInTwoTabs(WebRtcTestBase::kUseDefaultVideoCodec,
                                     false /* prefer_hw_video_codec */,
                                     kKeygenAlgorithmRsa, kKeygenAlgorithmEcdsa);
 }
 
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
                        RunsAudioVideoWebRTCCallInTwoTabsOfferEcdsaAnswerRsa) {
   RunsAudioVideoWebRTCCallInTwoTabs(WebRtcTestBase::kUseDefaultVideoCodec,
                                     false /* prefer_hw_video_codec */,
                                     kKeygenAlgorithmEcdsa, kKeygenAlgorithmRsa);
 }
 
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
                        RunsAudioVideoWebRTCCallInTwoTabsGetStatsCallback) {
   StartServerAndOpenTabs();
   SetupPeerconnectionWithLocalStream(left_tab_);
@@ -271,7 +262,7 @@
   DetectVideoAndHangUp();
 }
 
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
                        GetPeerToPeerConnectionsCountChangeFromNetworkService) {
   EXPECT_EQ(0u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
 
@@ -288,7 +279,7 @@
   EXPECT_EQ(0u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
 }
 
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
                        RunsAudioVideoWebRTCCallInTwoTabsGetStatsPromise) {
   StartServerAndOpenTabs();
   SetupPeerconnectionWithLocalStream(left_tab_);
@@ -312,7 +303,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(
-    MAYBE_WebRtcBrowserTest,
+    WebRtcBrowserTest,
     RunsAudioVideoWebRTCCallInTwoTabsEmitsGatheringStateChange) {
   StartServerAndOpenTabs();
   SetupPeerconnectionWithLocalStream(left_tab_);
@@ -335,7 +326,7 @@
   RunsAudioVideoWebRTCCallInTwoTabsEmitsGatheringStateChange_ConnectionCount
 #endif
 IN_PROC_BROWSER_TEST_F(
-    MAYBE_WebRtcBrowserTest,
+    WebRtcBrowserTest,
     MAYBE_RunsAudioVideoWebRTCCallInTwoTabsEmitsGatheringStateChange_ConnectionCount) {
   EXPECT_EQ(0u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
   StartServerAndOpenTabs();
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h
index e8ebb55..ff32d29ac 100644
--- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h
+++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h
@@ -9,7 +9,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_browser_main_extra_parts.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chrome/browser/nacl_host/nacl_browser_delegate_impl.h b/chrome/browser/nacl_host/nacl_browser_delegate_impl.h
index a65807d..c2be902 100644
--- a/chrome/browser/nacl_host/nacl_browser_delegate_impl.h
+++ b/chrome/browser/nacl_host/nacl_browser_delegate_impl.h
@@ -8,7 +8,6 @@
 #include <set>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "components/nacl/browser/nacl_browser_delegate.h"
 #include "extensions/buildflags/buildflags.h"
 
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
index d4a332a..d8e1e46cb 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
@@ -748,13 +748,10 @@
   EXPECT_EQ(2u, anchor_entries.size());
 
   // Create a fenced frame.
-  content::RenderFrameHost* fenced_frame_host =
-      fenced_frame_test_helper().CreateFencedFrame(
-          web_contents()->GetMainFrame(), url);
-
-  // Navigate the fenced frame.
-  fenced_frame_test_helper().NavigateFrameInFencedFrameTree(fenced_frame_host,
-                                                            url);
+  const GURL& fenced_frame_url =
+      test_server()->GetURL("/fenced_frames/simple_page_with_anchors.html");
+  ignore_result(fenced_frame_test_helper().CreateFencedFrame(
+      web_contents()->GetMainFrame(), fenced_frame_url));
 
   // Make sure the fenced frame doesn't log any anchors.
   anchor_entries = test_ukm_recorder->GetEntriesByName(AnchorEntry::kEntryName);
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_preconnect_client_browsertest.cc b/chrome/browser/navigation_predictor/navigation_predictor_preconnect_client_browsertest.cc
index 0eaf9cf8..2d5104b 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor_preconnect_client_browsertest.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor_preconnect_client_browsertest.cc
@@ -547,16 +547,17 @@
                                     1);
 
   // Create a fenced frame.
+  const GURL& fenced_frame_url =
+      GetTestURL("/fenced_frames/anchors_different_area.html");
   content::RenderFrameHost* fenced_frame_host =
       fenced_frame_test_helper().CreateFencedFrame(
-          web_contents()->GetMainFrame(), url);
+          web_contents()->GetMainFrame(), fenced_frame_url);
   // The count should not increase in DidFinishLoad method.
   histogram_tester.ExpectTotalCount("NavigationPredictor.IsPubliclyRoutable",
                                     1);
 
-  // Navigate the fenced frame.
   fenced_frame_test_helper().NavigateFrameInFencedFrameTree(fenced_frame_host,
-                                                            url);
+                                                            fenced_frame_url);
   // Histogram count should not increase after navigating the fenced frame.
   histogram_tester.ExpectTotalCount("NavigationPredictor.IsPubliclyRoutable",
                                     1);
diff --git a/chrome/browser/nearby_sharing/sharesheet/nearby_share_action.cc b/chrome/browser/nearby_sharing/sharesheet/nearby_share_action.cc
index 4af3a626..c5ace09 100644
--- a/chrome/browser/nearby_sharing/sharesheet/nearby_share_action.cc
+++ b/chrome/browser/nearby_sharing/sharesheet/nearby_share_action.cc
@@ -201,11 +201,10 @@
 
 bool NearbyShareAction::ShouldShowAction(const apps::mojom::IntentPtr& intent,
                                          bool contains_hosted_document) {
-  bool valid_file_share =
-      (intent->action == apps_util::kIntentActionSend ||
-       intent->action == apps_util::kIntentActionSendMultiple) &&
-      intent->files && !intent->files->empty() && !intent->share_text &&
-      !intent->url && !intent->drive_share_url && !contains_hosted_document;
+  bool valid_file_share = apps_util::IsShareIntent(intent) && intent->files &&
+                          !intent->files->empty() && !intent->share_text &&
+                          !intent->url && !intent->drive_share_url &&
+                          !contains_hosted_document;
 
   bool valid_text_share = intent->action == apps_util::kIntentActionSend &&
                           intent->share_text && !intent->files;
diff --git a/chrome/browser/net/disk_cache_dir_policy_handler.h b/chrome/browser/net/disk_cache_dir_policy_handler.h
index d3ad50d9..ee3a71a 100644
--- a/chrome/browser/net/disk_cache_dir_policy_handler.h
+++ b/chrome/browser/net/disk_cache_dir_policy_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_NET_DISK_CACHE_DIR_POLICY_HANDLER_H_
 #define CHROME_BROWSER_NET_DISK_CACHE_DIR_POLICY_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "components/policy/core/browser/configuration_policy_handler.h"
 
 namespace policy {
diff --git a/chrome/browser/net/net_error_tab_helper.h b/chrome/browser/net/net_error_tab_helper.h
index e99b6ab..f8f6359 100644
--- a/chrome/browser/net/net_error_tab_helper.h
+++ b/chrome/browser/net/net_error_tab_helper.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/bind.h"
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/net/dns_probe_service.h"
 #include "chrome/common/net/net_error_page_support.mojom.h"
diff --git a/chrome/browser/net/net_error_tab_helper_browsertest.cc b/chrome/browser/net/net_error_tab_helper_browsertest.cc
index c06c721a..42febe2 100644
--- a/chrome/browser/net/net_error_tab_helper_browsertest.cc
+++ b/chrome/browser/net/net_error_tab_helper_browsertest.cc
@@ -239,8 +239,11 @@
             result.ExtractString());
 }
 
+// TODO(crbug.com/1269931): Make this test work properly and not result in an
+// error page being navigated to in the fenced frame, and then re-enable the
+// test.
 IN_PROC_BROWSER_TEST_F(NetErrorTabHelperWithFencedFrameTest,
-                       CanRunDiagnosticsDialogOnFencedFrame) {
+                       DISABLED_CanRunDiagnosticsDialogOnFencedFrame) {
   GURL initial_url =
       net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
   RenderFrameHost* inner_fenced_frame_rfh =
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index ed132cb..625f60f2 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -881,12 +881,6 @@
   }
 #endif
 
-  // Should be initialized with existing per-profile CORS access lists.
-  network_context_params->cors_origin_access_list =
-      profile_->GetSharedCorsOriginAccessList()
-          ->GetOriginAccessList()
-          .CreateCorsOriginAccessPatternsList();
-
   network_context_params->reset_http_cache_backend =
       GetHttpCacheBackendResetParam(g_browser_process->local_state());
 
diff --git a/chrome/browser/net/system_network_context_manager_browsertest.cc b/chrome/browser/net/system_network_context_manager_browsertest.cc
index 6ec73e2..8fcb12c 100644
--- a/chrome/browser/net/system_network_context_manager_browsertest.cc
+++ b/chrome/browser/net/system_network_context_manager_browsertest.cc
@@ -269,9 +269,16 @@
   base::ScopedTempDir component_dir_;
 };
 
+// Flaky on Windows + Linux, crbug.com/1272198
+#if defined(OS_WIN) || defined(OS_LINUX)
+#define MAYBE_ReloadsFirstPartySetsAfterCrash \
+  DISABLED_ReloadsFirstPartySetsAfterCrash
+#else
+#define MAYBE_ReloadsFirstPartySetsAfterCrash ReloadsFirstPartySetsAfterCrash
+#endif
 IN_PROC_BROWSER_TEST_P(
     SystemNetworkContextManagerWithFirstPartySetComponentBrowserTest,
-    ReloadsFirstPartySetsAfterCrash) {
+    MAYBE_ReloadsFirstPartySetsAfterCrash) {
   // Network service is not running out of process, so cannot be crashed.
   if (!content::IsOutOfProcessNetworkService())
     return;
diff --git a/chrome/browser/password_manager/android/BUILD.gn b/chrome/browser/password_manager/android/BUILD.gn
index 08da528..e158245 100644
--- a/chrome/browser/password_manager/android/BUILD.gn
+++ b/chrome/browser/password_manager/android/BUILD.gn
@@ -51,10 +51,15 @@
     "//base:base_java",
     "//chrome/browser/device_reauth/android:java",
     "//chrome/browser/flags:java",
+    "//chrome/browser/profiles/android:java",
     "//chrome/browser/settings:java",
+    "//chrome/browser/signin/services/android:java",
+    "//chrome/browser/sync/android:java",
     "//components/browser_ui/settings/android:java",
     "//components/device_reauth:device_reauth_java_enums",
     "//components/password_manager/core/browser:password_manager_java_enums",
+    "//components/signin/public/android:java",
+    "//components/sync/android:sync_java",
     "//components/sync/protocol:protocol_java",
     "//content/public/android:content_java",
     "//third_party/android_deps:protobuf_lite_runtime_java",
@@ -102,6 +107,7 @@
   testonly = true
 
   sources = [
+    "junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelperTest.java",
     "junit/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendBridgeTest.java",
     "junit/src/org/chromium/chrome/browser/password_manager/settings/PasswordReauthenticationFragmentTest.java",
     "junit/src/org/chromium/chrome/browser/password_manager/settings/ReauthenticationManagerTest.java",
@@ -110,11 +116,19 @@
   deps = [
     ":android_backend_java_enums",
     ":java",
+    ":settings_interface_java",
     "$google_play_services_package:google_play_services_basement_java",
     "//base:base_java",
     "//base:base_java_test_support",
     "//base:base_junit_test_support",
+    "//chrome/browser/profiles/android:java",
+    "//chrome/browser/signin/services/android:java",
+    "//chrome/browser/sync/android:java",
     "//chrome/test/android:chrome_java_test_support",
+    "//components/browser_ui/settings/android:java",
+    "//components/password_manager/core/browser:password_manager_java_enums",
+    "//components/signin/public/android:java",
+    "//components/sync/android:sync_java",
     "//components/sync/protocol:protocol_java",
     "//third_party/android_deps:protobuf_lite_runtime_java",
     "//third_party/androidx:androidx_fragment_fragment_java",
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/CredentialManagerLauncher.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/CredentialManagerLauncher.java
index d692708..cf5b006 100644
--- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/CredentialManagerLauncher.java
+++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/CredentialManagerLauncher.java
@@ -12,40 +12,26 @@
  */
 public interface CredentialManagerLauncher {
     /**
-     * Launches the UI surface allowing users to manage their saved passwords.
-     *
-     * TODO(crbug.com/1255038): Remove once it becomes unused.
-     *
-     * @param referrer the place that requested the launch
-     */
-    @Deprecated
-    default void launchCredentialManager(@ManagePasswordsReferrer int referrer) {}
-
-    /**
      * Retrieves a pending intent that can be used to launch the credential manager. The intent
      * is to either be used immediately or discarded.
      *
-     * TODO(crbug.com/1255038): Change to abstract once downstream implements it.
-     *
      * @param referrer the place that will launch the credential manager
      * @param accountName the account name that is syncing passwords.
      * @param successCallback callback called with the intent if the retrieving was successful
      * @param failureCallback callback called if the retrieving failed with the raised exception
      */
-    default void getCredentialManagerLaunchIntentForAccount(@ManagePasswordsReferrer int referrer,
+    void getCredentialManagerLaunchIntentForAccount(@ManagePasswordsReferrer int referrer,
             String accountName, Callback<PendingIntent> successCallback,
-            Callback<Exception> failureCallback) {}
+            Callback<Exception> failureCallback);
 
     /**
      * Retrieves a pending intent that can be used to launch the credential manager. The intent
      * is to either be used immediately or discarded.
      *
-     * TODO(crbug.com/1255038): Change to abstract once downstream implements it.
-     *
      * @param referrer the place that will launch the credential manager
      * @param successCallback callback called with the intent if the retrieving was successful
      * @param failureCallback callback called if the retrieving failed with the raised exception
      */
-    default void getCredentialManagerLaunchIntentForLocal(@ManagePasswordsReferrer int referrer,
-            Callback<PendingIntent> successCallback, Callback<Exception> failureCallback) {}
+    void getCredentialManagerLaunchIntentForLocal(@ManagePasswordsReferrer int referrer,
+            Callback<PendingIntent> successCallback, Callback<Exception> failureCallback);
 }
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java
index 540cb53..70cdf39 100644
--- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java
+++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java
@@ -4,12 +4,18 @@
 
 package org.chromium.chrome.browser.password_manager;
 
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
 import android.content.Context;
 import android.os.Bundle;
 
 import org.chromium.base.metrics.RecordHistogram;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.sync.SyncService;
 import org.chromium.components.browser_ui.settings.SettingsLauncher;
+import org.chromium.components.signin.base.CoreAccountInfo;
+import org.chromium.components.signin.identitymanager.ConsentLevel;
+import org.chromium.components.signin.identitymanager.IdentityManager;
+import org.chromium.components.sync.ModelType;
 
 /** A helper class for showing PasswordSettings. */
 public class PasswordManagerHelper {
@@ -30,20 +36,22 @@
      * @param context used to show the UI to manage passwords.
      */
     public static void showPasswordSettings(Context context, @ManagePasswordsReferrer int referrer,
-            SettingsLauncher settingsLauncher) {
+            SettingsLauncher settingsLauncher, CredentialManagerLauncher credentialManagerLauncher,
+            IdentityManager identityManager, SyncService syncService) {
         RecordHistogram.recordEnumeratedHistogram("PasswordManager.ManagePasswordsReferrer",
                 referrer, ManagePasswordsReferrer.MAX_VALUE + 1);
-
-        // TODO(crbug.com/1255038): Add a Google Play Services version check before the feature
-        // check.
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_ANDROID)) {
-            CredentialManagerLauncher credentialManagerLauncher =
-                    CredentialManagerLauncherFactory.getInstance().createLauncher();
-
-            if (credentialManagerLauncher != null) {
-                credentialManagerLauncher.launchCredentialManager(referrer);
-                return;
+        if (credentialManagerLauncher != null) {
+            if (isSyncingPasswords(identityManager, syncService)) {
+                credentialManagerLauncher.getCredentialManagerLaunchIntentForAccount(referrer,
+                        CoreAccountInfo.getEmailFrom(syncService.getAccountInfo()),
+                        PasswordManagerHelper::launchCredentialManager,
+                        PasswordManagerHelper::recordFailureMetrics);
+            } else {
+                credentialManagerLauncher.getCredentialManagerLaunchIntentForLocal(referrer,
+                        PasswordManagerHelper::launchCredentialManager,
+                        PasswordManagerHelper::recordFailureMetrics);
             }
+            return;
         }
 
         Bundle fragmentArgs = new Bundle();
@@ -51,4 +59,33 @@
         context.startActivity(settingsLauncher.createSettingsActivityIntent(
                 context, PASSWORD_SETTINGS_CLASS, fragmentArgs));
     }
+
+    public static boolean isSyncingPasswords(
+            IdentityManager identityManager, SyncService syncService) {
+        if (!identityManager.hasPrimaryAccount(ConsentLevel.SYNC)) return false;
+        if (syncService == null
+                || !syncService.getActiveDataTypes().contains(ModelType.PASSWORDS)) {
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean isSyncingPasswordsWithoutCustomPassphrase(
+            IdentityManager identityManager, SyncService syncService) {
+        if (!PasswordManagerHelper.isSyncingPasswords(identityManager, syncService)) return false;
+        if (syncService == null || syncService.isUsingExplicitPassphrase()) return false;
+        return true;
+    }
+
+    private static void recordFailureMetrics(Exception exception) {
+        // TODO(crbug.com/1255038): Record metrics.
+    }
+
+    private static void launchCredentialManager(PendingIntent intent) {
+        try {
+            intent.send();
+        } catch (CanceledException e) {
+            // TODO(crbug.com/1255038): Record metrics.
+        }
+    }
 }
diff --git a/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelperTest.java b/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelperTest.java
new file mode 100644
index 0000000..f1e09851
--- /dev/null
+++ b/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelperTest.java
@@ -0,0 +1,133 @@
+// 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.chrome.browser.password_manager;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+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.robolectric.annotation.Config;
+
+import org.chromium.base.Callback;
+import org.chromium.base.CollectionUtil;
+import org.chromium.base.ContextUtils;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.Batch;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
+import org.chromium.chrome.browser.sync.SyncService;
+import org.chromium.components.browser_ui.settings.SettingsLauncher;
+import org.chromium.components.signin.base.CoreAccountInfo;
+import org.chromium.components.signin.identitymanager.ConsentLevel;
+import org.chromium.components.signin.identitymanager.IdentityManager;
+import org.chromium.components.sync.ModelType;
+
+import java.util.Collections;
+
+/** Tests for password manager helper methods. */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+@Batch(Batch.PER_CLASS)
+public class PasswordManagerHelperTest {
+    private static final String TEST_EMAIL_ADDRESS = "test@email.com";
+
+    @Mock
+    private CredentialManagerLauncher mCredentialManagerLauncherMock;
+
+    @Mock
+    private Profile mProfileMock;
+
+    @Mock
+    private IdentityServicesProvider mIdentityServicesProviderMock;
+
+    @Mock
+    private IdentityManager mIdentityManagerMock;
+
+    @Mock
+    private SyncService mSyncServiceMock;
+
+    @Mock
+    private SettingsLauncher mSettingsLauncherMock;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testSyncCheckNoSyncConsent() {
+        when(mIdentityManagerMock.hasPrimaryAccount(ConsentLevel.SYNC)).thenReturn(false);
+        Assert.assertFalse(
+                PasswordManagerHelper.isSyncingPasswords(mIdentityManagerMock, mSyncServiceMock));
+    }
+
+    @Test
+    public void testSyncPasswordsDisabled() {
+        when(mIdentityManagerMock.hasPrimaryAccount(ConsentLevel.SYNC)).thenReturn(true);
+        when(mSyncServiceMock.getActiveDataTypes()).thenReturn(Collections.EMPTY_SET);
+        Assert.assertFalse(
+                PasswordManagerHelper.isSyncingPasswords(mIdentityManagerMock, mSyncServiceMock));
+    }
+
+    @Test
+    public void testSyncPasswordsEnabled() {
+        when(mIdentityManagerMock.hasPrimaryAccount(ConsentLevel.SYNC)).thenReturn(true);
+        when(mSyncServiceMock.getActiveDataTypes())
+                .thenReturn(CollectionUtil.newHashSet(ModelType.PASSWORDS));
+        Assert.assertTrue(
+                PasswordManagerHelper.isSyncingPasswords(mIdentityManagerMock, mSyncServiceMock));
+    }
+
+    @Test
+    public void testSyncEnabledWithCustomPassphrase() {
+        when(mIdentityManagerMock.hasPrimaryAccount(ConsentLevel.SYNC)).thenReturn(true);
+        when(mSyncServiceMock.getActiveDataTypes())
+                .thenReturn(CollectionUtil.newHashSet(ModelType.PASSWORDS));
+        when(mSyncServiceMock.isUsingExplicitPassphrase()).thenReturn(true);
+        Assert.assertTrue(
+                PasswordManagerHelper.isSyncingPasswords(mIdentityManagerMock, mSyncServiceMock));
+        Assert.assertFalse(PasswordManagerHelper.isSyncingPasswordsWithoutCustomPassphrase(
+                mIdentityManagerMock, mSyncServiceMock));
+    }
+
+    @Test
+    public void testLaunchesCredentialManagerSync() {
+        when(mIdentityManagerMock.hasPrimaryAccount(ConsentLevel.SYNC)).thenReturn(true);
+        when(mSyncServiceMock.getActiveDataTypes())
+                .thenReturn(CollectionUtil.newHashSet(ModelType.PASSWORDS));
+        when(mSyncServiceMock.getAccountInfo())
+                .thenReturn(CoreAccountInfo.createFromEmailAndGaiaId(TEST_EMAIL_ADDRESS, "0"));
+
+        PasswordManagerHelper.showPasswordSettings(ContextUtils.getApplicationContext(),
+                ManagePasswordsReferrer.CHROME_SETTINGS, mSettingsLauncherMock,
+                mCredentialManagerLauncherMock, mIdentityManagerMock, mSyncServiceMock);
+
+        verify(mCredentialManagerLauncherMock)
+                .getCredentialManagerLaunchIntentForAccount(
+                        eq(ManagePasswordsReferrer.CHROME_SETTINGS), eq(TEST_EMAIL_ADDRESS),
+                        any(Callback.class), any(Callback.class));
+    }
+
+    @Test
+    public void testLaunchesCredentialManagerForLocal() {
+        when(mIdentityManagerMock.hasPrimaryAccount(ConsentLevel.SYNC)).thenReturn(false);
+
+        PasswordManagerHelper.showPasswordSettings(ContextUtils.getApplicationContext(),
+                ManagePasswordsReferrer.CHROME_SETTINGS, mSettingsLauncherMock,
+                mCredentialManagerLauncherMock, mIdentityManagerMock, mSyncServiceMock);
+
+        verify(mCredentialManagerLauncherMock)
+                .getCredentialManagerLaunchIntentForLocal(
+                        eq(ManagePasswordsReferrer.CHROME_SETTINGS), any(Callback.class),
+                        any(Callback.class));
+    }
+}
\ No newline at end of file
diff --git a/chrome/browser/password_manager/android/password_store_android_backend.cc b/chrome/browser/password_manager/android/password_store_android_backend.cc
index fe16d493..642a1f8 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend.cc
+++ b/chrome/browser/password_manager/android/password_store_android_backend.cc
@@ -269,11 +269,6 @@
           base::Unretained(this)));
 }
 
-void PasswordStoreAndroidBackend::GetSyncStatus(
-    base::OnceCallback<void(bool)> callback) {
-  NOTREACHED();
-}
-
 void PasswordStoreAndroidBackend::OnCompleteWithLogins(
     JobId job_id,
     std::vector<PasswordForm> passwords) {
diff --git a/chrome/browser/password_manager/android/password_store_android_backend.h b/chrome/browser/password_manager/android/password_store_android_backend.h
index 95cca26..501c641 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend.h
+++ b/chrome/browser/password_manager/android/password_store_android_backend.h
@@ -159,7 +159,6 @@
   FieldInfoStore* GetFieldInfoStore() override;
   std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() override;
-  void GetSyncStatus(base::OnceCallback<void(bool)> callback) override;
 
   // Implements PasswordStoreAndroidBackendBridge::Consumer interface.
   void OnCompleteWithLogins(PasswordStoreAndroidBackendBridge::JobId job_id,
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index 8db480e..3f7419e 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -10,7 +10,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/scoped_refptr.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
diff --git a/chrome/browser/performance_manager/browser_child_process_watcher.h b/chrome/browser/performance_manager/browser_child_process_watcher.h
index e108d55..0cd0c89 100644
--- a/chrome/browser/performance_manager/browser_child_process_watcher.h
+++ b/chrome/browser/performance_manager/browser_child_process_watcher.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/containers/flat_map.h"
 #include "base/process/process.h"
 #include "content/public/browser/browser_child_process_observer.h"
diff --git a/chrome/browser/performance_manager/chrome_browser_main_extra_parts_performance_manager.h b/chrome/browser/performance_manager/chrome_browser_main_extra_parts_performance_manager.h
index ec909ec..2098a25e 100644
--- a/chrome/browser/performance_manager/chrome_browser_main_extra_parts_performance_manager.h
+++ b/chrome/browser/performance_manager/chrome_browser_main_extra_parts_performance_manager.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/scoped_multi_source_observation.h"
 #include "chrome/browser/chrome_browser_main_extra_parts.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.h b/chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.h
index abca330..350ca62 100644
--- a/chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.h
+++ b/chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_CHROME_CONTENT_BROWSER_CLIENT_PERFORMANCE_MANAGER_PART_H_
 #define CHROME_BROWSER_PERFORMANCE_MANAGER_CHROME_CONTENT_BROWSER_CLIENT_PERFORMANCE_MANAGER_PART_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/chrome_content_browser_client_parts.h"
 
 // Allows tracking RenderProcessHost lifetime and proffering the Performance
diff --git a/chrome/browser/performance_manager/observers/page_load_metrics_observer_browsertest.cc b/chrome/browser/performance_manager/observers/page_load_metrics_observer_browsertest.cc
index e9999a66..cc60600 100644
--- a/chrome/browser/performance_manager/observers/page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/performance_manager/observers/page_load_metrics_observer_browsertest.cc
@@ -144,7 +144,8 @@
       performance_manager::LoadType::kVisibleTabBase, 1);
 
   // Load a fenced frame.
-  GURL fenced_frame_url = embedded_test_server()->GetURL("/title1.html");
+  GURL fenced_frame_url =
+      embedded_test_server()->GetURL("/fenced_frames/title1.html");
   content::RenderFrameHost* fenced_frame_host =
       fenced_frame_test_helper().CreateFencedFrame(
           GetWebContents()->GetMainFrame(), fenced_frame_url);
@@ -159,7 +160,8 @@
 
   // Navigate the fenced frame again.
   fenced_frame_test_helper().NavigateFrameInFencedFrameTree(
-      fenced_frame_host, embedded_test_server()->GetURL("/title2.html"));
+      fenced_frame_host,
+      embedded_test_server()->GetURL("/fenced_frames/title2.html"));
   entries = test_ukm_recorder()->GetEntriesByName(
       ukm::builders::LoadCountsPerTopLevelDocument::kEntryName);
   EXPECT_EQ(1u, entries.size());
diff --git a/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc b/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc
index a801f2d7..de3a85a 100644
--- a/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc
+++ b/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
-#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -14,11 +13,9 @@
 #include "chrome/test/permissions/permission_request_manager_test_api.h"
 #include "components/content_settings/browser/page_specific_content_settings.h"
 #include "components/embedder_support/switches.h"
-#include "components/permissions/features.h"
 #include "components/permissions/test/mock_permission_prompt_factory.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/common/content_features.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test_utils.h"
@@ -158,20 +155,9 @@
 // Tests of permissions behavior for an inheritance and embedding of an origin.
 // Test fixtures are run with and without the `PermissionsRevisedOriginHandling`
 // flag.
-class PermissionsSecurityModelInteractiveUITest
-    : public InProcessBrowserTest,
-      public ::testing::WithParamInterface<bool> {
+class PermissionsSecurityModelInteractiveUITest : public InProcessBrowserTest {
  public:
   PermissionsSecurityModelInteractiveUITest() {
-    std::vector<base::Feature> enabled_features, disabled_features;
-    enabled_features.push_back(features::kUserMediaCaptureOnFocus);
-    if (GetParam()) {
-      enabled_features.push_back(permissions::features::kRevisedOriginHandling);
-    } else {
-      disabled_features.push_back(
-          permissions::features::kRevisedOriginHandling);
-    }
-    feature_list_.InitWithFeatures(enabled_features, disabled_features);
     geolocation_overrider_ =
         std::make_unique<device::ScopedGeolocationOverrider>(0, 0);
   }
@@ -200,8 +186,6 @@
     return popup_contents;
   }
 
-  bool IsRevisedOriginHandlingEnabled() { return GetParam(); }
-
   void VerifyPermission(content::WebContents* opener_or_embedder_contents,
                         content::RenderFrameHost* test_rfh,
                         const std::string& request_permission_script,
@@ -214,10 +198,6 @@
     ASSERT_FALSE(
         content::EvalJs(test_rfh, check_permission_script).value.GetBool());
 
-    const bool contents_is_embedder =
-        content::WebContents::FromRenderFrameHost(test_rfh) ==
-        opener_or_embedder_contents;
-
     permissions::PermissionRequestManager* manager =
         permissions::PermissionRequestManager::FromWebContents(
             opener_or_embedder_contents);
@@ -247,24 +227,16 @@
     EXPECT_TRUE(
         content::EvalJs(opener_rfh, check_permission_script).value.GetBool());
 
-    // If `test_rfh` is not a descendant of `opener_or_embedder_contents`,
-    // in other words if `test_rfh` was created via `Window.open()`,
-    // permissions are propagated from an opener WebContents only if
-    // `RevisedOriginHandlingEnabled` is enabled.
-    const bool expect_granted =
-        IsRevisedOriginHandlingEnabled() || contents_is_embedder;
-
     // Verify permissions on the test RFH.
     {
-      EXPECT_EQ(
-          expect_granted,
+      EXPECT_TRUE(
           content::EvalJs(test_rfh, check_permission_script).value.GetBool());
     }
 
     // Request permission on the test RFH.
     test_rfh->GetView()->Focus();
     ASSERT_TRUE(test_rfh->GetView()->HasFocus());
-    EXPECT_EQ(expect_granted ? "granted" : "denied",
+    EXPECT_EQ("granted",
               content::EvalJs(test_rfh, request_permission_script,
                               is_notification
                                   ? content::EXECUTE_SCRIPT_DEFAULT_OPTIONS
@@ -275,6 +247,42 @@
     EXPECT_EQ(1, bubble_factory->TotalRequestCount());
   }
 
+  // getUserMedia requires focus. It should be verified only on a popup window.
+  void VerifyPopupWindowGetUserMedia(content::WebContents* opener_contents,
+                                     content::WebContents* popup_contents) {
+    content::RenderFrameHost* opener_rfh = opener_contents->GetMainFrame();
+    content::RenderFrameHost* popup_rfh = popup_contents->GetMainFrame();
+
+    ASSERT_FALSE(content::EvalJs(opener_rfh, kCheckCamera).value.GetBool());
+    ASSERT_FALSE(content::EvalJs(popup_rfh, kCheckCamera).value.GetBool());
+
+    permissions::PermissionRequestManager* manager =
+        permissions::PermissionRequestManager::FromWebContents(popup_contents);
+    std::unique_ptr<permissions::MockPermissionPromptFactory> bubble_factory =
+        std::make_unique<permissions::MockPermissionPromptFactory>(manager);
+
+    // Enable auto-accept of a permission request.
+    bubble_factory->set_response_type(
+        permissions::PermissionRequestManager::AutoResponseType::ACCEPT_ALL);
+
+    // Move the web contents to the foreground.
+    popup_rfh->GetView()->Focus();
+    ASSERT_TRUE(popup_rfh->GetView()->HasFocus());
+    // Request permission on the popup RenderFrameHost.
+    EXPECT_EQ("granted",
+              content::EvalJs(popup_rfh, kRequestCamera,
+                              content::EXECUTE_SCRIPT_USE_MANUAL_REPLY)
+                  .ExtractString());
+    EXPECT_EQ(1, bubble_factory->TotalRequestCount());
+
+    // Disable auto-accept of a permission request.
+    bubble_factory->set_response_type(
+        permissions::PermissionRequestManager::AutoResponseType::NONE);
+
+    EXPECT_TRUE(content::EvalJs(popup_rfh, kCheckCamera).value.GetBool());
+    EXPECT_TRUE(content::EvalJs(opener_rfh, kCheckCamera).value.GetBool());
+  }
+
   void VerifyPermissionsExceptGetUserMedia(
       content::WebContents* opener_or_embedder_contents,
       content::RenderFrameHost* test_rfh) {
@@ -317,15 +325,10 @@
   }
 
  private:
-  base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<device::ScopedGeolocationOverrider> geolocation_overrider_;
 };
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         PermissionsSecurityModelInteractiveUITest,
-                         ::testing::Bool());
-
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        EmbedIframeAboutBlank) {
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/iframe_about_blank.html"));
@@ -348,7 +351,7 @@
                    kCheckCamera);
 }
 
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        WindowOpenAboutBlank) {
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/empty.html"));
@@ -361,14 +364,13 @@
       OpenPopup(browser(), GURL("about:blank"));
   ASSERT_TRUE(popup_contents);
 
-  // TODO(crbug.com/1242047): Add back the camera access tests when they are
-  // no longer flaky on Linux.
   VerifyPermissionsExceptGetUserMedia(opener_contents,
                                       popup_contents->GetMainFrame());
+  VerifyPopupWindowGetUserMedia(opener_contents, popup_contents);
 }
 
 // `about:srcdoc` supports only embedder WebContents, hence no test for opener.
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        EmbedIframeSrcDoc) {
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/iframe_srcdoc.html"));
@@ -390,7 +392,7 @@
                    kCheckCamera);
 }
 
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        EmbedIframeBlob) {
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/iframe_blob.html"));
@@ -413,17 +415,8 @@
                    kCheckCamera);
 }
 
-// TODO(crbug.com/1242047): Add back the camera access tests when they are
-// no longer flaky on Linux.
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        WindowOpenBlob) {
-  if (GetParam()) {
-    // Blob iframe on an opener contents does not work if
-    // `kRevisedOriginHandling` feature enabled.
-    // TODO(crbug.com/698985): Remove when the bug is fixed.
-    return;
-  }
-
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/empty.html"));
   content::RenderFrameHost* main_rfh =
@@ -441,9 +434,10 @@
 
   VerifyPermissionsExceptGetUserMedia(opener_contents,
                                       blob_popup_contents->GetMainFrame());
+  VerifyPopupWindowGetUserMedia(opener_contents, blob_popup_contents);
 }
 
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        EmbedIframeFileSystem) {
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/empty.html"));
@@ -465,7 +459,7 @@
 }
 
 // Renderer navigation for "filesystem:" is not allowed.
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        WindowOpenFileSystemRendererNavigationNotAllowed) {
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/empty.html"));
@@ -485,15 +479,8 @@
   EXPECT_EQ("", popup_iframe->GetLastCommittedURL().scheme());
 }
 
-// TODO(crbug.com/1242046): Add back the camera access tests when they are
-// no longer flaky on Linux and Mac.
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        WindowOpenFileSystemBrowserNavigation) {
-  if (!GetParam()) {
-    // Filesystem iframe on an opener contents does not work if
-    // `kRevisedOriginHandling` feature disabled.
-    return;
-  }
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/empty.html"));
   content::RenderFrameHost* main_rfh =
@@ -520,9 +507,11 @@
   EXPECT_TRUE(popup_rfh->GetLastCommittedURL().SchemeIsFileSystem());
 
   VerifyPermissionsExceptGetUserMedia(opener_contents, popup_rfh);
+  VerifyPopupWindowGetUserMedia(
+      opener_contents, content::WebContents::FromRenderFrameHost(popup_rfh));
 }
 
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        TopIframeFile) {
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/empty.html"));
@@ -558,7 +547,7 @@
 }
 
 // Permissions granted for a file should not leak to another file.
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        PermissionDoesNotLeakToAnotherFile) {
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url(embedded_test_server()->GetURL("/empty.html"));
@@ -605,7 +594,7 @@
   VerifyPermissionsForFile(main_rfh, /*expect_granted*/ false);
 }
 
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        UniversalAccessFromFileUrls) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -676,7 +665,7 @@
 
 // Verifies that permissions are not supported for file:/// with changed URL to
 // `about:blank`.
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        UniversalAccessFromFileUrlsAboutBlank) {
   content::WebContents* embedder_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -714,7 +703,7 @@
   VerifyPermissionsForFile(main_rfh, /*expect_granted*/ false);
 }
 
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        PermissionRequestOnNtpUseDseOrigin) {
   content::WebContents* embedder_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -773,7 +762,7 @@
                   .value.GetBool());
 }
 
-IN_PROC_BROWSER_TEST_P(PermissionsSecurityModelInteractiveUITest,
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
                        MicActivityIndicatorOnNtpUseDseOrigin) {
   content::WebContents* embedder_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index e6dc33d..c53a4c4 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -1610,8 +1610,10 @@
   content::test::FencedFrameTestHelper fenced_frame_helper_;
 };
 
+// TODO(crbug.com/1269935): Make this test work properly with
+// FencedFrameTestHelper and re-enable the test.
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerFencedFrameBrowserTest,
-                       FencedFrameShouldNotCloseWindow) {
+                       DISABLED_FencedFrameShouldNotCloseWindow) {
   GURL test_page_url = embedded_test_server()->GetURL(
       "example.com", "/media/picture-in-picture/window-size.html");
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_page_url));
diff --git a/chrome/browser/plugins/plugin_info_host_impl.h b/chrome/browser/plugins/plugin_info_host_impl.h
index a2f3d90..5e55a0c 100644
--- a/chrome/browser/plugins/plugin_info_host_impl.h
+++ b/chrome/browser/plugins/plugin_info_host_impl.h
@@ -9,7 +9,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_piece.h"
 #include "base/task/sequenced_task_runner_helpers.h"
diff --git a/chrome/browser/plugins/plugin_prefs_factory.h b/chrome/browser/plugins/plugin_prefs_factory.h
index 0b8332b7..a010451 100644
--- a/chrome/browser/plugins/plugin_prefs_factory.h
+++ b/chrome/browser/plugins/plugin_prefs_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_PLUGINS_PLUGIN_PREFS_FACTORY_H_
 #define CHROME_BROWSER_PLUGINS_PLUGIN_PREFS_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/refcounted_browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/policy/browser_signin_policy_handler.h b/chrome/browser/policy/browser_signin_policy_handler.h
index 46c2de5..f061238 100644
--- a/chrome/browser/policy/browser_signin_policy_handler.h
+++ b/chrome/browser/policy/browser_signin_policy_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_POLICY_BROWSER_SIGNIN_POLICY_HANDLER_H_
 #define CHROME_BROWSER_POLICY_BROWSER_SIGNIN_POLICY_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "components/policy/core/browser/configuration_policy_handler.h"
 
 namespace policy {
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator.h b/chrome/browser/policy/cloud/cloud_policy_invalidator.h
index d7ca9b1..1c9b554 100644
--- a/chrome/browser/policy/cloud/cloud_policy_invalidator.h
+++ b/chrome/browser/policy/cloud/cloud_policy_invalidator.h
@@ -11,7 +11,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.h b/chrome/browser/policy/cloud/user_policy_signin_service.h
index 6bbb7c2..08f96d1 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service.h
+++ b/chrome/browser/policy/cloud/user_policy_signin_service.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/scoped_observation.h"
 #include "chrome/browser/policy/cloud/user_policy_signin_service_base.h"
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_base.h b/chrome/browser/policy/cloud/user_policy_signin_service_base.h
index 8ef9730..fee18be9 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_base.h
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_base.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "components/keyed_service/core/keyed_service.h"
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_mobile.h b/chrome/browser/policy/cloud/user_policy_signin_service_mobile.h
index 7d713ac1..19d548b 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_mobile.h
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_mobile.h
@@ -9,7 +9,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/policy/device_account_initializer.h b/chrome/browser/policy/device_account_initializer.h
index 7451e2d6..23834b4 100644
--- a/chrome/browser/policy/device_account_initializer.h
+++ b/chrome/browser/policy/device_account_initializer.h
@@ -10,7 +10,6 @@
 
 #include "chrome/browser/policy/enrollment_status.h"
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "components/policy/core/common/cloud/cloud_policy_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
diff --git a/chrome/browser/policy/device_management_service_configuration.h b/chrome/browser/policy/device_management_service_configuration.h
index 3207d78..1b0db03 100644
--- a/chrome/browser/policy/device_management_service_configuration.h
+++ b/chrome/browser/policy/device_management_service_configuration.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "components/policy/core/common/cloud/device_management_service.h"
 
 namespace content {
diff --git a/chrome/browser/policy/file_selection_dialogs_policy_handler.h b/chrome/browser/policy/file_selection_dialogs_policy_handler.h
index 8c709cc9..8c6ace38 100644
--- a/chrome/browser/policy/file_selection_dialogs_policy_handler.h
+++ b/chrome/browser/policy/file_selection_dialogs_policy_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_POLICY_FILE_SELECTION_DIALOGS_POLICY_HANDLER_H_
 #define CHROME_BROWSER_POLICY_FILE_SELECTION_DIALOGS_POLICY_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "components/policy/core/browser/configuration_policy_handler.h"
 
 namespace policy {
diff --git a/chrome/browser/policy/local_sync_policy_handler.h b/chrome/browser/policy/local_sync_policy_handler.h
index dd8adef..5f86fb5 100644
--- a/chrome/browser/policy/local_sync_policy_handler.h
+++ b/chrome/browser/policy/local_sync_policy_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_POLICY_LOCAL_SYNC_POLICY_HANDLER_H_
 #define CHROME_BROWSER_POLICY_LOCAL_SYNC_POLICY_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "components/policy/core/browser/configuration_policy_handler.h"
 
 namespace policy {
diff --git a/chrome/browser/prefetch/no_state_prefetch/no_state_prefetch_link_manager_factory.h b/chrome/browser/prefetch/no_state_prefetch/no_state_prefetch_link_manager_factory.h
index 99dbeea..756aac22 100644
--- a/chrome/browser/prefetch/no_state_prefetch/no_state_prefetch_link_manager_factory.h
+++ b/chrome/browser/prefetch/no_state_prefetch/no_state_prefetch_link_manager_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_PREFETCH_NO_STATE_PREFETCH_NO_STATE_PREFETCH_LINK_MANAGER_FACTORY_H_
 #define CHROME_BROWSER_PREFETCH_NO_STATE_PREFETCH_NO_STATE_PREFETCH_LINK_MANAGER_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/prefetch/no_state_prefetch/no_state_prefetch_manager_factory.h b/chrome/browser/prefetch/no_state_prefetch/no_state_prefetch_manager_factory.h
index 709797b8..bfe8cf0b 100644
--- a/chrome/browser/prefetch/no_state_prefetch/no_state_prefetch_manager_factory.h
+++ b/chrome/browser/prefetch/no_state_prefetch/no_state_prefetch_manager_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_PREFETCH_NO_STATE_PREFETCH_NO_STATE_PREFETCH_MANAGER_FACTORY_H_
 #define CHROME_BROWSER_PREFETCH_NO_STATE_PREFETCH_NO_STATE_PREFETCH_MANAGER_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/printing/background_printing_manager.h b/chrome/browser/printing/background_printing_manager.h
index 4073467..17a920e 100644
--- a/chrome/browser/printing/background_printing_manager.h
+++ b/chrome/browser/printing/background_printing_manager.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <set>
 
-#include "base/compiler_specific.h"
 #include "base/sequence_checker.h"
 
 namespace content {
diff --git a/chrome/browser/printing/print_preview_context_menu_observer.h b/chrome/browser/printing/print_preview_context_menu_observer.h
index ab7c92ec..e939a2a 100644
--- a/chrome/browser/printing/print_preview_context_menu_observer.h
+++ b/chrome/browser/printing/print_preview_context_menu_observer.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_PRINTING_PRINT_PREVIEW_CONTEXT_MENU_OBSERVER_H_
 #define CHROME_BROWSER_PRINTING_PRINT_PREVIEW_CONTEXT_MENU_OBSERVER_H_
 
-#include "base/compiler_specific.h"
 #include "components/renderer_context_menu/render_view_context_menu_observer.h"
 
 namespace content {
diff --git a/chrome/browser/profiles/avatar_menu.h b/chrome/browser/profiles/avatar_menu.h
index 2ba89b3d..638d2a8 100644
--- a/chrome/browser/profiles/avatar_menu.h
+++ b/chrome/browser/profiles/avatar_menu.h
@@ -10,7 +10,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/scoped_observation.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
diff --git a/chrome/browser/profiles/bookmark_model_loaded_observer.h b/chrome/browser/profiles/bookmark_model_loaded_observer.h
index d67e149..0863f66 100644
--- a/chrome/browser/profiles/bookmark_model_loaded_observer.h
+++ b/chrome/browser/profiles/bookmark_model_loaded_observer.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_PROFILES_BOOKMARK_MODEL_LOADED_OBSERVER_H_
 #define CHROME_BROWSER_PROFILES_BOOKMARK_MODEL_LOADED_OBSERVER_H_
 
-#include "base/compiler_specific.h"
 #include "components/bookmarks/browser/base_bookmark_model_observer.h"
 
 class Profile;
diff --git a/chrome/browser/profiles/gaia_info_update_service.h b/chrome/browser/profiles/gaia_info_update_service.h
index eb63626..6b76c12 100644
--- a/chrome/browser/profiles/gaia_info_update_service.h
+++ b/chrome/browser/profiles/gaia_info_update_service.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_downloader.h"
diff --git a/chrome/browser/profiles/profile_android.h b/chrome/browser/profiles/profile_android.h
index 74d85918..1d09d91 100644
--- a/chrome/browser/profiles/profile_android.h
+++ b/chrome/browser/profiles/profile_android.h
@@ -8,7 +8,6 @@
 #include <jni.h>
 
 #include "base/android/scoped_java_ref.h"
-#include "base/compiler_specific.h"
 #include "base/supports_user_data.h"
 #include "chrome/browser/profiles/profile.h"
 
diff --git a/chrome/browser/profiles/profile_key_android.h b/chrome/browser/profiles/profile_key_android.h
index 2665290..c740216 100644
--- a/chrome/browser/profiles/profile_key_android.h
+++ b/chrome/browser/profiles/profile_key_android.h
@@ -8,7 +8,6 @@
 #include <jni.h>
 
 #include "base/android/scoped_java_ref.h"
-#include "base/compiler_specific.h"
 
 class ProfileKey;
 
diff --git a/chrome/browser/profiling_host/chrome_browser_main_extra_parts_profiling.h b/chrome/browser/profiling_host/chrome_browser_main_extra_parts_profiling.h
index 99a8022a..37dac0a 100644
--- a/chrome/browser/profiling_host/chrome_browser_main_extra_parts_profiling.h
+++ b/chrome/browser/profiling_host/chrome_browser_main_extra_parts_profiling.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_PROFILING_HOST_CHROME_BROWSER_MAIN_EXTRA_PARTS_PROFILING_H_
 #define CHROME_BROWSER_PROFILING_HOST_CHROME_BROWSER_MAIN_EXTRA_PARTS_PROFILING_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/chrome_browser_main_extra_parts.h"
 
 class ChromeBrowserMainExtraPartsProfiling
diff --git a/chrome/browser/push_messaging/push_messaging_service_factory.h b/chrome/browser/push_messaging/push_messaging_service_factory.h
index 6d548068..5512ed8 100644
--- a/chrome/browser/push_messaging/push_messaging_service_factory.h
+++ b/chrome/browser/push_messaging/push_messaging_service_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_SERVICE_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.h b/chrome/browser/push_messaging/push_messaging_service_impl.h
index 7cf4b020..31a4670 100644
--- a/chrome/browser/push_messaging/push_messaging_service_impl.h
+++ b/chrome/browser/push_messaging/push_messaging_service_impl.h
@@ -13,7 +13,6 @@
 
 #include "base/callback.h"
 #include "base/callback_helpers.h"
-#include "base/compiler_specific.h"
 #include "base/containers/flat_map.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/renderer_context_menu/accessibility_labels_menu_observer.h b/chrome/browser/renderer_context_menu/accessibility_labels_menu_observer.h
index 0069c223..5b6496a 100644
--- a/chrome/browser/renderer_context_menu/accessibility_labels_menu_observer.h
+++ b/chrome/browser/renderer_context_menu/accessibility_labels_menu_observer.h
@@ -8,7 +8,6 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/compiler_specific.h"
 #include "components/prefs/pref_member.h"
 #include "components/renderer_context_menu/render_view_context_menu_observer.h"
 
diff --git a/chrome/browser/renderer_context_menu/quick_answers_menu_observer.cc b/chrome/browser/renderer_context_menu/quick_answers_menu_observer.cc
index 889b046..509cfef 100644
--- a/chrome/browser/renderer_context_menu/quick_answers_menu_observer.cc
+++ b/chrome/browser/renderer_context_menu/quick_answers_menu_observer.cc
@@ -7,8 +7,6 @@
 #include <utility>
 
 #include "ash/public/cpp/assistant/controller/assistant_interaction_controller.h"
-#include "ash/public/cpp/quick_answers/controller/quick_answers_controller.h"
-#include "ash/public/cpp/quick_answers/quick_answers_state.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -18,6 +16,8 @@
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chromeos/components/quick_answers/public/cpp/controller/quick_answers_controller.h"
+#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h"
 #include "chromeos/components/quick_answers/quick_answers_model.h"
 #include "chromeos/services/assistant/public/cpp/assistant_service.h"
 #include "components/language/core/browser/pref_names.h"
diff --git a/chrome/browser/renderer_context_menu/quick_answers_menu_observer_browsertest.cc b/chrome/browser/renderer_context_menu/quick_answers_menu_observer_browsertest.cc
index fe2d65b..295dd82 100644
--- a/chrome/browser/renderer_context_menu/quick_answers_menu_observer_browsertest.cc
+++ b/chrome/browser/renderer_context_menu/quick_answers_menu_observer_browsertest.cc
@@ -5,13 +5,13 @@
 #include "chrome/browser/renderer_context_menu/quick_answers_menu_observer.h"
 
 #include "ash/constants/ash_features.h"
-#include "ash/public/cpp/quick_answers/controller/quick_answers_controller.h"
-#include "ash/public/cpp/quick_answers/quick_answers_state.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/renderer_context_menu/mock_render_view_context_menu.h"
 #include "chrome/test/base/chrome_test_utils.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chromeos/components/quick_answers/public/cpp/controller/quick_answers_controller.h"
+#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h"
 #include "content/public/browser/context_menu_params.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
diff --git a/chrome/browser/renderer_context_menu/spelling_bubble_model.h b/chrome/browser/renderer_context_menu/spelling_bubble_model.h
index 22c5ecf9..c3bdf785c 100644
--- a/chrome/browser/renderer_context_menu/spelling_bubble_model.h
+++ b/chrome/browser/renderer_context_menu/spelling_bubble_model.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_RENDERER_CONTEXT_MENU_SPELLING_BUBBLE_MODEL_H_
 #define CHROME_BROWSER_RENDERER_CONTEXT_MENU_SPELLING_BUBBLE_MODEL_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/confirm_bubble_model.h"
 
diff --git a/chrome/browser/renderer_context_menu/spelling_menu_observer.h b/chrome/browser/renderer_context_menu/spelling_menu_observer.h
index efc5d2e79..8398a4d 100644
--- a/chrome/browser/renderer_context_menu/spelling_menu_observer.h
+++ b/chrome/browser/renderer_context_menu/spelling_menu_observer.h
@@ -12,7 +12,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/repost_form_warning_controller.h b/chrome/browser/repost_form_warning_controller.h
index 0013114..9dcceff 100644
--- a/chrome/browser/repost_form_warning_controller.h
+++ b/chrome/browser/repost_form_warning_controller.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_REPOST_FORM_WARNING_CONTROLLER_H_
 #define CHROME_BROWSER_REPOST_FORM_WARNING_CONTROLLER_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
 
 // This class is used to continue or cancel a pending reload when the
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index 6e9d811..446f539 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -11,7 +11,6 @@
 #include <vector>
 
 #include "base/callback_helpers.h"
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/memory_pressure_listener.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/resource_coordinator/tab_manager_stats_collector.cc b/chrome/browser/resource_coordinator/tab_manager_stats_collector.cc
index e89ddc6..8b9a95b 100644
--- a/chrome/browser/resource_coordinator/tab_manager_stats_collector.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_stats_collector.cc
@@ -28,7 +28,6 @@
 #include "chrome/browser/resource_coordinator/time.h"
 #include "chrome/browser/sessions/session_restore.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/swap_metrics_driver.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
@@ -218,66 +217,6 @@
 }
 
 // static
-void TabManagerStatsCollector::RecordDecisionDetails(
-    LifecycleUnit* lifecycle_unit,
-    const DecisionDetails& decision_details,
-    LifecycleUnitState target_state) {
-  ukm::SourceId ukm_source_id = lifecycle_unit->GetUkmSourceId();
-  if (ukm_source_id == ukm::kInvalidSourceId)
-    return;
-
-  // Don't log anything for invalid decision details (trivial reasons: crashed
-  // tabs, navigations not yet committed, etc).
-  if (decision_details.reasons().empty())
-    return;
-
-  ukm::builders::TabManager_LifecycleStateChange builder(ukm_source_id);
-
-  builder.SetOldLifecycleState(
-      static_cast<int64_t>(lifecycle_unit->GetState()));
-  builder.SetNewLifecycleState(static_cast<int64_t>(target_state));
-  // No LifecycleStateChangeReason is set right now, indicating that this is a
-  // theoretical state change rather than an actual one. This differentiates
-  // sampled lifecycle transitions from actual ones.
-
-  // We only currently report transitions for tabs, so this lookup should never
-  // fail. It will start failing once we add ARC processes as LifecycleUnits.
-  // TODO(chrisha): This should be time since the navigation was committed (the
-  // load started), but that information is currently only persisted inside the
-  // CU-graph. Using time since navigation finished is a cheap approximation for
-  // the time being.
-  auto* tab = lifecycle_unit->AsTabLifecycleUnitExternal();
-  auto* contents = tab->GetWebContents();
-  auto* nav_entry = contents->GetController().GetLastCommittedEntry();
-  if (nav_entry) {
-    auto timestamp = nav_entry->GetTimestamp();
-    if (!timestamp.is_null()) {
-      auto elapsed = base::Time::Now() - timestamp;
-      builder.SetTimeSinceNavigationMs(elapsed.InMilliseconds());
-    }
-  }
-
-  // Set visibility related data.
-  // |time_since_visible| is:
-  // - Zero if the LifecycleUnit is currently visible.
-  // - Time since creation if the LifecycleUnit was never visible.
-  // - Time since visible if the LifecycleUnit was visible in the past.
-  auto visibility = lifecycle_unit->GetVisibility();
-  base::TimeDelta time_since_visible;  // Zero.
-  if (visibility != content::Visibility::VISIBLE)
-    time_since_visible = NowTicks() - lifecycle_unit->GetWallTimeWhenHidden();
-  builder.SetTimeSinceVisibilityStateChangeMs(
-      time_since_visible.InMilliseconds());
-  builder.SetVisibilityState(static_cast<int64_t>(visibility));
-
-  // This populates all of the relevant Success/Failure fields, as well as
-  // Outcome.
-  decision_details.Populate(&builder);
-
-  builder.Record(ukm::UkmRecorder::Get());
-}
-
-// static
 const char TabManagerStatsCollector::kHistogramSessionRestoreSwitchToTab[] =
     "TabManager.SessionRestore.SwitchToTab";
 
diff --git a/chrome/browser/resource_coordinator/tab_manager_stats_collector.h b/chrome/browser/resource_coordinator/tab_manager_stats_collector.h
index a28a227..faf919f 100644
--- a/chrome/browser/resource_coordinator/tab_manager_stats_collector.h
+++ b/chrome/browser/resource_coordinator/tab_manager_stats_collector.h
@@ -99,12 +99,6 @@
   // Update session and sequence information for UKM recording.
   void UpdateSessionAndSequence();
 
-  // Helper function for RecordSampledTabData. Records a single UKM entry for
-  // the provided DecisionDetails and destination lifecycle state.
-  static void RecordDecisionDetails(LifecycleUnit* lifecycle_unit,
-                                    const DecisionDetails& decision_details,
-                                    LifecycleUnitState new_state);
-
   static const char kHistogramSessionRestoreSwitchToTab[];
   static const char kHistogramSessionRestoreTabSwitchLoadTime[];
   static const char kHistogramSessionOverlapSessionRestore[];
diff --git a/chrome/browser/resources/browser_switch/internals/browser_switch_internals.html b/chrome/browser/resources/browser_switch/internals/browser_switch_internals.html
index 3d4444d..8aa4d02 100644
--- a/chrome/browser/resources/browser_switch/internals/browser_switch_internals.html
+++ b/chrome/browser/resources/browser_switch/internals/browser_switch_internals.html
@@ -46,6 +46,8 @@
       width: 400px;
     }
 
+    #browser-switcher-disabled-container,
+    #browser-switcher-enabled-container,
     #xml-not-fetched-yet,
     #xml-last-fetch {
       display: none;
@@ -95,160 +97,171 @@
     run those sites.
   </p>
 
-  <!-- TODO(crbug/959379): Hide all this and show a message if
-                           BrowserSwitcherEnabled is false. -->
-
   <hr>
   </hr>
 
-  <section id="url-checker-section">
-    <h2>URL Checker</h2>
-
-    <label>
-      Enter a URL to see what LBS would do with it.
-      <input type="text" id="url-checker-input" placeholder="http://example.com/">
-    </label>
-
-    <ul>
-      <li id="output"></li>
-      <li id="reason"></li>
-    </ul>
-  </section>
-
-  <hr>
-  </hr>
-
-  <section id="xml-configuration-source">
-    <h2 class="tooltip">
-      XML configuration source
-      <span class="right">
-        XML files that are being used to set the policies.
-      </span>
-    </h2>
-
-    <table id="xml-sitelists"></table>
-
-    <div id="xml-description-wrapper">
-      <p id="xml-not-fetched-yet">
-        XML sitelists have not been fetched yet.
-      </p>
-
-      <p id="xml-last-fetch">
-        XML sitelists were last downloaded at
-        <span id="last-fetch-placeholder"></span>.
-      </p>
-
-      <p id="xml-next-fetch">
-        Next download is at
-        <span id="next-fetch-placeholder"></span>.
-      </p>
-
-      <p>
-        <button id="refresh-xml-button">Download now</button>
-      </p>
-    </div>
-  </section>
-
-  <hr>
-  </hr>
-
-  <section id="sitelist-section">
-    <h2 class="tooltip">
-      Force open in
-      <span class="right">
-        The list of websites that redirect to alternative browser.
-      </span>
-    </h2>
-    <h4>
-      This list is affected by
-      <a href="https://chromeenterprise.google/policies/#BrowserSwitcherUrlList"><span
-          class="policy-prop">{BrowserSwitcherUrlList}</span></a>,
-      <a
-        href="https://chromeenterprise.google/policies/#BrowserSwitcherExternalSitelistUrl"><span
-          class="policy-prop">{BrowserSwitcherExternalSitelistUrl}</span></a>,
-      and
-      <a
-        href="https://chromeenterprise.google/policies/#BrowserSwitcherUseIeSitelist"><span
-          class="policy-prop">{BrowserSwitcherUseIeSitelist}</span></a>
-    </h4>
+  <div id="browser-switcher-disabled-container">
+    <h2>Nothing to show</h2>
 
     <p>
-      URLs matching these rules will be forced to open in a specific browser.
+      LBS is currently disabled. You can enable LBS by setting the
+      <a href="https://chromeenterprise.google/policies/#BrowserSwitcherEnabled">
+        <span class="policy-prop">{BrowserSwitcherEnabled}</span>
+      </a>
+      policy.
     </p>
-    <table id="sitelist"></table>
-  </section>
+  </div>
 
-  <hr>
-  </hr>
+  <div id="browser-switcher-enabled-container">
+    <section id="url-checker-section">
+      <h2>URL Checker</h2>
 
-  <section id="greylist-section">
-    <h2 class="tooltip">
-      Ignore
-      <span class="right">
-        The list of websites that can open in either browser.
-      </span>
-    </h2>
-    <h4>
-      This list is affected by
-      <a
-        href="https://chromeenterprise.google/policies/#BrowserSwitcherExternalGreylistUrl"><span
-          class="policy-prop">{BrowserSwitcherUrlGreylist}</span></a>, and
-      <a
-        href="https://chromeenterprise.google/policies/#BrowserSwitcherUrlGreylist"><span
-          class="policy-prop">{BrowserSwitcherUrlGreylist}</span></a>
-    </h4>
+      <label>
+        Enter a URL to see what LBS would do with it.
+        <input type="text" id="url-checker-input" placeholder="http://example.com/">
+      </label>
 
-    <p id="greylist-description"></p>
-    <table id="greylist"></table>
-  </section>
+      <ul>
+        <li id="output"></li>
+        <li id="reason"></li>
+      </ul>
+    </section>
 
-  <template id="header-row-template-sitelist">
-    <tr>
-      <th>Rule</th>
-      <th>Source</th>
-      <th>Type</th>
-      <th>Opens in</th>
-    </tr>
-  </template>
+    <hr>
+    </hr>
 
-  <template id="header-row-template-greylist">
-    <tr>
-      <th>Rule</th>
-      <th>Source</th>
-      <th>Type</th>
-    </tr>
-  </template>
+    <section id="xml-configuration-source">
+      <h2 class="tooltip">
+        XML configuration source
+        <span class="right">
+          XML files that are being used to set the policies.
+        </span>
+      </h2>
 
-  <template id="rule-row-template-sitelist">
-    <tr>
-      <td></td>
-      <td></td>
-      <td></td>
-      <td></td>
-    </tr>
-  </template>
+      <table id="xml-sitelists"></table>
 
-  <template id="rule-row-template-greylist">
-    <tr>
-      <td></td>
-      <td></td>
-      <td></td>
-    </tr>
-  </template>
+      <div id="xml-description-wrapper">
+        <p id="xml-not-fetched-yet">
+          XML sitelists have not been fetched yet.
+        </p>
 
-  <template id="xml-header-row-template">
-    <tr>
-      <th>Source policy</th>
-      <th>URL</th>
-    </tr>
-  </template>
+        <p id="xml-last-fetch">
+          XML sitelists were last downloaded at
+          <span id="last-fetch-placeholder"></span>.
+        </p>
 
-  <template id="xml-row-template">
-    <tr>
-      <td></td>
-      <td></td>
-    </tr>
-  </template>
+        <p id="xml-next-fetch">
+          Next download is at
+          <span id="next-fetch-placeholder"></span>.
+        </p>
+
+        <p>
+          <button id="refresh-xml-button">Download now</button>
+        </p>
+      </div>
+    </section>
+
+    <hr>
+    </hr>
+
+    <section id="sitelist-section">
+      <h2 class="tooltip">
+        Force open in
+        <span class="right">
+          The list of websites that redirect to alternative browser.
+        </span>
+      </h2>
+      <h4>
+        This list is affected by
+        <a href="https://chromeenterprise.google/policies/#BrowserSwitcherUrlList"><span
+            class="policy-prop">{BrowserSwitcherUrlList}</span></a>,
+        <a
+          href="https://chromeenterprise.google/policies/#BrowserSwitcherExternalSitelistUrl"><span
+            class="policy-prop">{BrowserSwitcherExternalSitelistUrl}</span></a>,
+        and
+        <a
+          href="https://chromeenterprise.google/policies/#BrowserSwitcherUseIeSitelist"><span
+            class="policy-prop">{BrowserSwitcherUseIeSitelist}</span></a>
+      </h4>
+
+      <p>
+        URLs matching these rules will be forced to open in a specific browser.
+      </p>
+      <table id="sitelist"></table>
+    </section>
+
+    <hr>
+    </hr>
+
+    <section id="greylist-section">
+      <h2 class="tooltip">
+        Ignore
+        <span class="right">
+          The list of websites that can open in either browser.
+        </span>
+      </h2>
+      <h4>
+        This list is affected by
+        <a
+          href="https://chromeenterprise.google/policies/#BrowserSwitcherExternalGreylistUrl"><span
+            class="policy-prop">{BrowserSwitcherUrlGreylist}</span></a>, and
+        <a
+          href="https://chromeenterprise.google/policies/#BrowserSwitcherUrlGreylist"><span
+            class="policy-prop">{BrowserSwitcherUrlGreylist}</span></a>
+      </h4>
+
+      <p id="greylist-description"></p>
+      <table id="greylist"></table>
+    </section>
+
+    <template id="header-row-template-sitelist">
+      <tr>
+        <th>Rule</th>
+        <th>Source</th>
+        <th>Type</th>
+        <th>Opens in</th>
+      </tr>
+    </template>
+
+    <template id="header-row-template-greylist">
+      <tr>
+        <th>Rule</th>
+        <th>Source</th>
+        <th>Type</th>
+      </tr>
+    </template>
+
+    <template id="rule-row-template-sitelist">
+      <tr>
+        <td></td>
+        <td></td>
+        <td></td>
+        <td></td>
+      </tr>
+    </template>
+
+    <template id="rule-row-template-greylist">
+      <tr>
+        <td></td>
+        <td></td>
+        <td></td>
+      </tr>
+    </template>
+
+    <template id="xml-header-row-template">
+      <tr>
+        <th>Source policy</th>
+        <th>URL</th>
+      </tr>
+    </template>
+
+    <template id="xml-row-template">
+      <tr>
+        <td></td>
+        <td></td>
+      </tr>
+    </template>
+  </div>
 
   <script type="module" src="/internals/browser_switch_internals.js"></script>
 </body>
diff --git a/chrome/browser/resources/browser_switch/internals/browser_switch_internals.ts b/chrome/browser/resources/browser_switch/internals/browser_switch_internals.ts
index 6440fd6..b5e15acfc 100644
--- a/chrome/browser/resources/browser_switch/internals/browser_switch_internals.ts
+++ b/chrome/browser/resources/browser_switch/internals/browser_switch_internals.ts
@@ -126,9 +126,9 @@
  * Gets the English name of the alternate browser.
  */
 function getAltBrowserName(): string {
-  // TODO (crbug.com/1258133): if you change the AlternativeBrowserPath policy,
-  // then loadTimeData can contain stale data. It won't update until you refresh
-  // (despite the rest of the page auto-updating).
+  // TODO (crbug.com/1258133): if you change the AlternativeBrowserPath
+  // policy, then loadTimeData can contain stale data. It won't update
+  // until you refresh (despite the rest of the page auto-updating).
   return loadTimeData.getString('altBrowserName');
 }
 
@@ -136,9 +136,9 @@
  * Gets the English name of the browser.
  */
 function getBrowserName(): string {
-  // TODO (crbug.com/1258133): if you change the AlternativeBrowserPath policy,
-  // then loadTimeData can contain stale data. It won't update until you refresh
-  // (despite the rest of the page auto-updating).
+  // TODO (crbug.com/1258133): if you change the AlternativeBrowserPath
+  // policy, then loadTimeData can contain stale data. It won't update
+  // until you refresh (despite the rest of the page auto-updating).
   return loadTimeData.getString('browserName');
 }
 
@@ -162,9 +162,11 @@
   let reason = '';
   if (decision.matching_rule) {
     if (decision.matching_rule.startsWith('!')) {
-      reason += `Reason: The inverted rule ${JSON.stringify(decision.matching_rule)} was found in `;
+      reason += `Reason: The inverted rule ${
+          JSON.stringify(decision.matching_rule)} was found in `;
     } else {
-      reason += `Reason: ${JSON.stringify(decision.matching_rule)} was found in `;
+      reason +=
+          `Reason: ${JSON.stringify(decision.matching_rule)} was found in `;
     }
   }
   // if undefined - add nothing to the output
@@ -290,11 +292,18 @@
 /**
  * Called by C++ when we need to update everything on the page.
  */
-function updateEverything() {
-  sendWithPromise('getAllRulesets').then(updateTables);
-  sendWithPromise('getTimestamps').then(updateTimestamps);
-  sendWithPromise('getRulesetSources').then(updateXmlTable);
-  checkUrl();
+async function updateEverything() {
+  const isEnabled = await sendWithPromise('isBrowserSwitcherEnabled');
+  $('browser-switcher-disabled-container').style.display =
+      isEnabled ? 'none' : 'block';
+  $('browser-switcher-enabled-container').style.display =
+      isEnabled ? 'block' : 'none';
+  if (isEnabled) {
+    sendWithPromise('getAllRulesets').then(updateTables);
+    sendWithPromise('getTimestamps').then(updateTimestamps);
+    sendWithPromise('getRulesetSources').then(updateXmlTable);
+    checkUrl();
+  }
 }
 
 // TODO(crbug/959379): Keep the page up-to-date at all times: updateEverything()
diff --git a/chrome/browser/resources/chromeos/launcher_internals/results_table.html b/chrome/browser/resources/chromeos/launcher_internals/results_table.html
index 252b7c8..5c34e81 100644
--- a/chrome/browser/resources/chromeos/launcher_internals/results_table.html
+++ b/chrome/browser/resources/chromeos/launcher_internals/results_table.html
@@ -38,7 +38,7 @@
       <td>Result type</td>
       <td>Metrics type</td>
       <td>Display type</td>
-      <td class="sort-header" id="scoreHeader">Score</td>
+      <td class="sort-header" id="scoreHeader">Display score</td>
     </tr>
   </thead>
   <tbody id="resultsSection"></tbody>
diff --git a/chrome/browser/resources/chromeos/launcher_internals/results_table.ts b/chrome/browser/resources/chromeos/launcher_internals/results_table.ts
index 8e01ea7..df3fa00 100644
--- a/chrome/browser/resources/chromeos/launcher_internals/results_table.ts
+++ b/chrome/browser/resources/chromeos/launcher_internals/results_table.ts
@@ -10,7 +10,7 @@
   $: {
     'headerRow': HTMLTableRowElement,
     'resultsSection': HTMLTableSectionElement,
-    'scoreHeader': HTMLTableCellElement,
+    'displayScoreHeader': HTMLTableCellElement,
   };
 }
 
@@ -30,9 +30,10 @@
   // header row in insertion order.
   private headerCells: Map<string, HTMLTableCellElement> = new Map();
 
-  // The result property used to sort the table. 'Score' is the default key, and
-  // this will change whenever the user clicks on a new header to sort by.
-  private sortKey: string = 'Score';
+  // The result property used to sort the table. 'Display score' is the default
+  // key, and this will change whenever the user clicks on a new header to sort
+  // by.
+  private sortKey: string = 'Display score';
 
   // The IDs of results that are currently selected. This is used to persist
   // formatting when the table is sorted.
@@ -40,8 +41,9 @@
 
   connectedCallback() {
     super.connectedCallback();
-    this.$.scoreHeader.addEventListener(
-        'click', () => this.sortTable('Score', /*resultsChanged=*/ false));
+    this.$.displayScoreHeader.addEventListener(
+        'click',
+        () => this.sortTable('Display score', /*resultsChanged=*/ false));
   }
 
   clearResults() {
@@ -86,7 +88,7 @@
     this.sortKey = sortKey;
 
     let sortedResults = Array.from(this.results.values());
-    if (this.sortKey === 'Score') {
+    if (this.sortKey === 'Display score') {
       sortedResults.sort((a, b) => b.score - a.score);
     } else {
       const getSortValue = (result: Result): number => {
diff --git a/chrome/browser/resources/chromeos/login/BUILD.gn b/chrome/browser/resources/chromeos/login/BUILD.gn
index 2935d16..877a163 100644
--- a/chrome/browser/resources/chromeos/login/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -214,6 +214,8 @@
     "screens/common/fingerprint_setup.js",
     "screens/common/gesture_navigation.html",
     "screens/common/gesture_navigation.js",
+    "screens/common/guest_tos.html",
+    "screens/common/guest_tos.js",
     "screens/common/managed_terms_of_service.html",
     "screens/common/managed_terms_of_service.js",
     "screens/common/marketing_opt_in.html",
@@ -345,6 +347,7 @@
     "screens/common/family_link_notice.m.js",
     "screens/common/fingerprint_setup.m.js",
     "screens/common/gesture_navigation.m.js",
+    "screens/common/guest_tos.m.js",
     "screens/common/managed_terms_of_service.m.js",
     "screens/common/marketing_opt_in.m.js",
     "screens/common/oobe_reset.m.js",
@@ -431,7 +434,6 @@
 js_type_check("closure_compile_local") {
   uses_legacy_modules = true
   deps = [
-    ":guest_tos",
     ":multidevice_setup_first_run",
     ":notification_card",
     ":offline_ad_login",
@@ -565,22 +567,6 @@
   ]
 }
 
-js_library("guest_tos") {
-  deps = [
-    "components:web_view_helper",
-    "components:web_view_loader",
-    "components/behaviors:login_screen_behavior",
-    "components/behaviors:multi_step_behavior",
-    "components/behaviors:oobe_dialog_host_behavior",
-    "components/behaviors:oobe_i18n_behavior",
-    "components/buttons:oobe_back_button",
-    "components/buttons:oobe_next_button",
-    "components/buttons:oobe_text_button",
-    "components/dialogs:oobe_adaptive_dialog",
-    "components/dialogs:oobe_loading_dialog",
-  ]
-}
-
 js_library("i18n_setup") {
   deps = [ "//ui/webui/resources/js:load_time_data.m" ]
 }
diff --git a/chrome/browser/resources/chromeos/login/md_login_polymer3.html b/chrome/browser/resources/chromeos/login/md_login_polymer3.html
index 54d90e7..71d22ab4 100644
--- a/chrome/browser/resources/chromeos/login/md_login_polymer3.html
+++ b/chrome/browser/resources/chromeos/login/md_login_polymer3.html
@@ -62,6 +62,8 @@
           </encryption-migration-element>
           <consolidated-consent-element id="consolidated-consent" class="step hidden" hidden>
           </consolidated-consent-element>
+          <guest-tos-element id="guest-tos" class="step hidden" hidden>
+          </guest-tos-element>
           <!-- error elements -->
           <device-disabled-element id="device-disabled" class="step hidden" hidden>
           </device-disabled-element>
diff --git a/chrome/browser/resources/chromeos/login/oobe_polymer3.html b/chrome/browser/resources/chromeos/login/oobe_polymer3.html
index 0437de1..f4653ea2 100644
--- a/chrome/browser/resources/chromeos/login/oobe_polymer3.html
+++ b/chrome/browser/resources/chromeos/login/oobe_polymer3.html
@@ -76,6 +76,8 @@
           </oobe-reset-element>
           <consolidated-consent-element id="consolidated-consent" class="step hidden" hidden>
           </consolidated-consent-element>
+          <guest-tos-element id="guest-tos" class="step hidden" hidden>
+          </guest-tos-element>
           <!-- error elements -->
           <device-disabled-element id="device-disabled" class="step hidden" hidden>
           </device-disabled-element>
diff --git a/chrome/browser/resources/chromeos/login/oobe_polymer3.js b/chrome/browser/resources/chromeos/login/oobe_polymer3.js
index 4bbc301d..0040b18 100644
--- a/chrome/browser/resources/chromeos/login/oobe_polymer3.js
+++ b/chrome/browser/resources/chromeos/login/oobe_polymer3.js
@@ -13,6 +13,7 @@
 import 'chrome://oobe/screens/common/family_link_notice.m.js';
 import 'chrome://oobe/screens/common/fingerprint_setup.m.js';
 import 'chrome://oobe/screens/common/gesture_navigation.m.js';
+import 'chrome://oobe/screens/common/guest_tos.m.js';
 import 'chrome://oobe/screens/common/managed_terms_of_service.m.js';
 import 'chrome://oobe/screens/common/marketing_opt_in.m.js';
 import 'chrome://oobe/screens/common/parental_handoff.m.js';
diff --git a/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn b/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn
index 431cafff..3db79a0b 100644
--- a/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn
@@ -23,6 +23,7 @@
     ":family_link_notice_module",
     ":fingerprint_setup_module",
     ":gesture_navigation_module",
+    ":guest_tos_module",
     ":managed_terms_of_service_module",
     ":marketing_opt_in_module",
     ":oobe_reset_module",
@@ -62,6 +63,7 @@
     ":family_link_notice.m",
     ":fingerprint_setup.m",
     ":gesture_navigation.m",
+    ":guest_tos.m",
     ":managed_terms_of_service.m",
     ":marketing_opt_in.m",
     ":oobe_reset.m",
@@ -243,6 +245,31 @@
   extra_deps = [ ":gesture_navigation_module" ]
 }
 
+js_library("guest_tos.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/screens/common/guest_tos.m.js" ]
+  deps = [
+    "../..:display_manager.m",
+    "../../components:web_view_helper.m",
+    "../../components:web_view_loader.m",
+    "../../components/behaviors:login_screen_behavior.m",
+    "../../components/behaviors:multi_step_behavior.m",
+    "../../components/behaviors:oobe_i18n_behavior.m",
+    "../../components/buttons:oobe_back_button.m",
+    "../../components/buttons:oobe_next_button.m",
+    "../../components/buttons:oobe_text_button.m",
+    "../../components/dialogs:oobe_adaptive_dialog.m",
+    "../../components/dialogs:oobe_loading_dialog.m",
+    "../../components/dialogs:oobe_modal_dialog.m",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/cr_elements/cr_toggle:cr_toggle.m",
+  ]
+  extra_deps = [ ":guest_tos_module" ]
+  externs_list = [
+    "$externs_path/chrome_extensions.js",
+    "$externs_path/webview_tag.js",
+  ]
+}
+
 js_library("managed_terms_of_service.m") {
   sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/screens/common/managed_terms_of_service.m.js" ]
   deps = [
@@ -472,6 +499,14 @@
   namespace_rewrites = oobe_namespace_rewrites
 }
 
+polymer_modulizer("guest_tos") {
+  js_file = "guest_tos.js"
+  html_file = "guest_tos.html"
+  html_type = "dom-module"
+  auto_imports = oobe_auto_imports
+  namespace_rewrites = oobe_namespace_rewrites
+}
+
 polymer_modulizer("managed_terms_of_service") {
   js_file = "managed_terms_of_service.js"
   html_file = "managed_terms_of_service.html"
diff --git a/chrome/browser/resources/chromeos/login/guest_tos.html b/chrome/browser/resources/chromeos/login/screens/common/guest_tos.html
similarity index 77%
rename from chrome/browser/resources/chromeos/login/guest_tos.html
rename to chrome/browser/resources/chromeos/login/screens/common/guest_tos.html
index 4729bc9..fa70075 100644
--- a/chrome/browser/resources/chromeos/login/guest_tos.html
+++ b/chrome/browser/resources/chromeos/login/screens/common/guest_tos.html
@@ -4,18 +4,26 @@
 
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
 <link rel="import" href="chrome://resources/html/action_link.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 
-<link rel="import" href="/components/behaviors/login_screen_behavior.html">
-<link rel="import" href="/components/behaviors/oobe_dialog_host_behavior.html">
-<link rel="import" href="/components/behaviors/oobe_i18n_behavior.html">
-<link rel="import" href="/components/buttons/oobe_back_button.html">
-<link rel="import" href="/components/buttons/oobe_next_button.html">
-<link rel="import" href="/components/common_styles/common_styles.html">
-<link rel="import" href="/components/common_styles/oobe_dialog_host_styles.html">
-<link rel="import" href="/components/dialogs/oobe_adaptive_dialog.html">
-<link rel="import" href="/components/oobe_icons.html">
+<link rel="import" href="../../components/behaviors/login_screen_behavior.html">
+<link rel="import" href="../../components/behaviors/multi_step_behavior.html">
+<link rel="import" href="../../components/behaviors/oobe_i18n_behavior.html">
+<link rel="import" href="../../components/buttons/oobe_back_button.html">
+<link rel="import" href="../../components/buttons/oobe_next_button.html">
+<link rel="import" href="../../components/buttons/oobe_text_button.html">
+<link rel="import" href="../../components/common_styles/common_styles.html">
+<link rel="import" href="../../components/common_styles/oobe_dialog_host_styles.html">
+<link rel="import" href="../../components/display_manager_types.html">
+<link rel="import" href="../../components/oobe_icons.html">
+<link rel="import" href="../../components/web_view_loader.html">
+<link rel="import" href="../../components/web_view_helper.html">
+<link rel="import" href="../../components/dialogs/oobe_adaptive_dialog.html">
+<link rel="import" href="../../components/dialogs/oobe_loading_dialog.html">
+<link rel="import" href="../../components/dialogs/oobe_modal_dialog.html">
 
 <dom-module id="guest-tos-element">
   <template>
@@ -131,4 +139,5 @@
       </div>
     </oobe-modal-dialog>
   </template>
+  <script src="guest_tos.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/chromeos/login/guest_tos.js b/chrome/browser/resources/chromeos/login/screens/common/guest_tos.js
similarity index 61%
rename from chrome/browser/resources/chromeos/login/guest_tos.js
rename to chrome/browser/resources/chromeos/login/screens/common/guest_tos.js
index 06abe34..e995142 100644
--- a/chrome/browser/resources/chromeos/login/guest_tos.js
+++ b/chrome/browser/resources/chromeos/login/screens/common/guest_tos.js
@@ -5,10 +5,11 @@
 /**
  * @fileoverview guest tos screen implementation.
  */
-(function() {
 
-// Enum that describes the current state of the Consolidated Consent screen
-const UIState = {
+/* #js_imports_placeholder */
+
+// Enum that describes the current state of the Guest ToS screen
+const GuestTosScreenState = {
   LOADING: 'loading',
   LOADED: 'loaded',
   GOOGLE_EULA: 'google-eula',
@@ -19,26 +20,61 @@
  * URL to use when online page is not available.
  * @type {string}
  */
-const EULA_TERMS_URL = 'chrome://terms';
+const GUEST_TOS_EULA_TERMS_URL = 'chrome://terms';
 
-Polymer({
-  is: 'guest-tos-element',
+/**
+ * @constructor
+ * @extends {PolymerElement}
+ * @implements {LoginScreenBehaviorInterface}
+ * @implements {OobeI18nBehaviorInterface}
+ * @implements {MultiStepBehaviorInterface}
+ */
+const GuestTosScreenElementBase = Polymer.mixinBehaviors(
+    [OobeI18nBehavior, MultiStepBehavior, LoginScreenBehavior],
+    Polymer.Element);
 
-  behaviors: [OobeI18nBehavior, MultiStepBehavior, LoginScreenBehavior],
+/**
+ * @polymer
+ */
+class GuestTos extends GuestTosScreenElementBase {
+  static get is() {
+    return 'guest-tos-element';
+  }
 
-  properties: {
-    usageChecked: {
-      type: Boolean,
-      value: true,
-    },
-  },
+  /* #html_template_placeholder */
 
+  static get properties() {
+    return {
+      usageChecked: {
+        type: Boolean,
+        value: true,
+      },
+    };
+  }
+
+  constructor() {
+    super();
+    this.usageChecked = true;
+  }
+
+  /** @override */
+  defaultUIStep() {
+    return GuestTosScreenState.LOADING;
+  }
+
+  get UI_STEPS() {
+    return GuestTosScreenState;
+  }
+  // clang-format on
+
+  /** @override */
   ready() {
+    super.ready();
     this.initializeLoginScreen('GuestTosScreen', {
       resetAllowed: true,
     });
     this.updateLocalizedContent();
-  },
+  }
 
   onBeforeShow(data) {
     const googleEulaUrl = data['googleEulaUrl'];
@@ -48,36 +84,30 @@
         this.$.googleEulaWebview, googleEulaUrl, false /* clear_anchors */);
     this.loadEulaWebview_(
         this.$.crosEulaWebview, crosEulaUrl, true /* clear_anchors */);
-  },
+  }
 
   /** Initial UI State for screen */
   getOobeUIInitialState() {
     return OOBE_UI_STATE.HIDDEN;
-  },
-
-  defaultUIStep() {
-    return UIState.LOADING;
-  },
-
-  UI_STEPS: UIState,
+  }
 
   updateLocalizedContent() {
-    this.$$('#googleEulaLink')
+    this.shadowRoot.querySelector('#googleEulaLink')
         .addEventListener('click', () => this.onGoogleEulaLinkClick_());
-    this.$$('#crosEulaLink')
+    this.shadowRoot.querySelector('#crosEulaLink')
         .addEventListener('click', () => this.onCrosEulaLinkClick_());
-  },
+  }
 
   loadEulaWebview_(webview, online_tos_url, clear_anchors) {
     const loadFailureCallback = () => {
       WebViewHelper.loadUrlContentToWebView(
-          webview, EULA_TERMS_URL, WebViewHelper.ContentType.HTML);
+          webview, GUEST_TOS_EULA_TERMS_URL, WebViewHelper.ContentType.HTML);
     };
 
     const tosLoader = new WebViewLoader(
         webview, loadFailureCallback, clear_anchors, true /* inject_css */);
     tosLoader.setUrl(online_tos_url);
-  },
+  }
 
   getTerms_(locale) {
     const terms = document.createElement('div');
@@ -92,47 +122,48 @@
     crosEulaLink.classList.add('oobe-local-link');
 
     return terms.innerHTML;
-  },
+  }
 
   getUsageLearnMoreText_(locale) {
     return this.i18nAdvanced('guestTosUsageOptInLearnMore');
-  },
+  }
 
   onGoogleEulaLinkClick_() {
-    this.setUIStep(UIState.GOOGLE_EULA);
+    this.setUIStep(GuestTosScreenState.GOOGLE_EULA);
     this.$.googleEulaOkButton.focus();
-  },
+  }
 
   onCrosEulaLinkClick_() {
-    this.setUIStep(UIState.CROS_EULA);
+    this.setUIStep(GuestTosScreenState.CROS_EULA);
     this.$.crosEulaOkButton.focus();
-  },
+  }
 
   onGoogleEulaContentLoad_() {
-    if (this.uiStep == UIState.LOADING) {
-      this.setUIStep(UIState.LOADED);
+    if (this.uiStep == GuestTosScreenState.LOADING) {
+      this.setUIStep(GuestTosScreenState.LOADED);
     }
-  },
+  }
 
   onUsageLearnMoreClick_() {
     this.$.usageLearnMorePopUp.showDialog();
-  },
+  }
 
   onTermsStepOkClick_() {
-    this.setUIStep(UIState.LOADED);
+    this.setUIStep(GuestTosScreenState.LOADED);
     this.$.acceptButton.focus();
-  },
+  }
 
   onAcceptClick_() {
     chrome.send('GuestToSAccept', [this.usageChecked]);
-  },
+  }
 
   onBackClick_() {
     this.userActed('back-button');
-  },
+  }
 
   cancel() {
     this.userActed('cancel');
-  },
-});
-})();
+  }
+}
+
+customElements.define(GuestTos.is, GuestTos);
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.js b/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.js
index 19178ea..5b222f7 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.js
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.js
@@ -181,6 +181,13 @@
   setCountryList_(countries) {
     this.countries = countries;
     this.$.countryDropdownContainer.hidden = countries.length == 0;
+    for (let i = 0; i < countries.length; ++i) {
+      let country = countries[i];
+      if (country.selected && country.value !== this.country_not_selected_id_) {
+        this.is_country_selected_ = true;
+        return;
+      }
+    }
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/login/structure/components_common.html b/chrome/browser/resources/chromeos/login/structure/components_common.html
index 6aa6fc2..b786dbfb 100644
--- a/chrome/browser/resources/chromeos/login/structure/components_common.html
+++ b/chrome/browser/resources/chromeos/login/structure/components_common.html
@@ -18,13 +18,13 @@
 <link rel="import" href="/screens/common/error_message.html">
 <link rel="import" href="/screens/common/family_link_notice.html">
 <link rel="import" href="/screens/common/fingerprint_setup.html">
-<link rel="import" href="/screens/common/signin_fatal_error.html">
-<link rel="import" href="/screens/common/sync_consent.html">
+<link rel="import" href="/screens/common/guest_tos.html">
 <link rel="import" href="/screens/common/gesture_navigation.html">
 <link rel="import" href="/screens/common/managed_terms_of_service.html">
 <link rel="import" href="/screens/common/marketing_opt_in.html">
 <link rel="import" href="/screens/common/oobe_reset.html">
 <link rel="import" href="/screens/common/parental_handoff.html">
+<link rel="import" href="/screens/common/signin_fatal_error.html">
 <link rel="import" href="/screens/common/sync_consent.html">
 <link rel="import" href="/screens/common/tpm_error.html">
 <link rel="import" href="/screens/common/user_creation.html">
@@ -49,7 +49,6 @@
 <include src="../screen_multidevice_setup.html">
 <include src="../security_token_pin.html">
 <include src="../screen_app_launch_splash.html">
-<include src="../guest_tos.html">
 
 <include src="components_[OOBE].html">
 <include src="components_[OS_INSTALL].html">
diff --git a/chrome/browser/resources/chromeos/login/structure/components_common.js b/chrome/browser/resources/chromeos/login/structure/components_common.js
index de1f3cb..2996e48 100644
--- a/chrome/browser/resources/chromeos/login/structure/components_common.js
+++ b/chrome/browser/resources/chromeos/login/structure/components_common.js
@@ -24,7 +24,6 @@
 // <include src="../screen_multidevice_setup.js">
 // <include src="../security_token_pin.js">
 // <include src="../screen_app_launch_splash.js">
-// <include src="../guest_tos.js">
 
 // <include src="components_[OOBE].js">
 // <include src="components_[OS_INSTALL].js">
diff --git a/chrome/browser/resources/chromeos/password_change/lock_screen_network.html b/chrome/browser/resources/chromeos/password_change/lock_screen_network.html
index 9d9c3bb7..03ef837 100644
--- a/chrome/browser/resources/chromeos/password_change/lock_screen_network.html
+++ b/chrome/browser/resources/chromeos/password_change/lock_screen_network.html
@@ -119,7 +119,7 @@
 </head>
 
 <body>
-  <lock-screen-network-ui></lock-screen-network-ui>
+  <lock-screen-network-ui id="network-ui"></lock-screen-network-ui>
 </body>
 
 </html>
diff --git a/chrome/browser/resources/chromeos/password_change/lock_screen_network.js b/chrome/browser/resources/chromeos/password_change/lock_screen_network.js
index beb99560..daf7916 100644
--- a/chrome/browser/resources/chromeos/password_change/lock_screen_network.js
+++ b/chrome/browser/resources/chromeos/password_change/lock_screen_network.js
@@ -37,6 +37,11 @@
     ];
   },
 
+  /** @override */
+  ready() {
+    chrome.send('initialize');
+  },
+
   /**
    * Handles clicks on network items in the <network-select> element by
    * attempting a connection to the selected network or requesting a password
diff --git a/chrome/browser/resources/print_preview/print_preview.ts b/chrome/browser/resources/print_preview/print_preview.ts
index 4c984ab8..75d7cd37 100644
--- a/chrome/browser/resources/print_preview/print_preview.ts
+++ b/chrome/browser/resources/print_preview/print_preview.ts
@@ -7,7 +7,7 @@
 export {CloudPrintInterface, CloudPrintInterfaceEventType} from './cloud_print_interface.js';
 export {CloudPrintInterfaceImpl} from './cloud_print_interface_impl.js';
 export {Cdd, MediaSizeCapability, MediaSizeOption, VendorCapabilityValueType} from './data/cdd.js';
-export {ColorMode, createDestinationKey, Destination, DestinationCertificateStatus, DestinationConnectionStatus, DestinationOrigin, DestinationType, GooglePromotedDestinationId, makeRecentDestination} from './data/destination.js';
+export {ColorMode, createDestinationKey, Destination, DestinationCertificateStatus, DestinationConnectionStatus, DestinationOrigin, DestinationType, GooglePromotedDestinationId, makeRecentDestination, RecentDestination} from './data/destination.js';
 // <if expr="chromeos or lacros">
 export {SAVE_TO_DRIVE_CROS_DESTINATION_KEY} from './data/destination.js';
 // </if>
diff --git a/chrome/browser/resources/print_preview/ui/destination_dialog.ts b/chrome/browser/resources/print_preview/ui/destination_dialog.ts
index 37ee855..26f8bbc9c 100644
--- a/chrome/browser/resources/print_preview/ui/destination_dialog.ts
+++ b/chrome/browser/resources/print_preview/ui/destination_dialog.ts
@@ -245,6 +245,12 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'print-preview-destination-dialog': PrintPreviewDestinationDialogElement;
+  }
+}
+
 customElements.define(
     PrintPreviewDestinationDialogElement.is,
     PrintPreviewDestinationDialogElement);
diff --git a/chrome/browser/resources/print_preview/ui/destination_dialog_cros.ts b/chrome/browser/resources/print_preview/ui/destination_dialog_cros.ts
index 6f94f1afa..71ab3185 100644
--- a/chrome/browser/resources/print_preview/ui/destination_dialog_cros.ts
+++ b/chrome/browser/resources/print_preview/ui/destination_dialog_cros.ts
@@ -391,6 +391,13 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'print-preview-destination-dialog-cros':
+        PrintPreviewDestinationDialogCrosElement;
+  }
+}
+
 customElements.define(
     PrintPreviewDestinationDialogCrosElement.is,
     PrintPreviewDestinationDialogCrosElement);
diff --git a/chrome/browser/resources/print_preview/ui/destination_list.ts b/chrome/browser/resources/print_preview/ui/destination_list.ts
index c4bd54a..aaa4a11b 100644
--- a/chrome/browser/resources/print_preview/ui/destination_list.ts
+++ b/chrome/browser/resources/print_preview/ui/destination_list.ts
@@ -184,5 +184,11 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'print-preview-destination-list': PrintPreviewDestinationListElement;
+  }
+}
+
 customElements.define(
     PrintPreviewDestinationListElement.is, PrintPreviewDestinationListElement);
diff --git a/chrome/browser/resources/print_preview/ui/destination_list_item.ts b/chrome/browser/resources/print_preview/ui/destination_list_item.ts
index d23a752c..550be33 100644
--- a/chrome/browser/resources/print_preview/ui/destination_list_item.ts
+++ b/chrome/browser/resources/print_preview/ui/destination_list_item.ts
@@ -264,6 +264,13 @@
   // </if>
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'print-preview-destination-list-item':
+        PrintPreviewDestinationListItemElement;
+  }
+}
+
 customElements.define(
     PrintPreviewDestinationListItemElement.is,
     PrintPreviewDestinationListItemElement);
diff --git a/chrome/browser/resources/print_preview/ui/destination_settings.ts b/chrome/browser/resources/print_preview/ui/destination_settings.ts
index bacd860..fa85c62 100644
--- a/chrome/browser/resources/print_preview/ui/destination_settings.ts
+++ b/chrome/browser/resources/print_preview/ui/destination_settings.ts
@@ -618,6 +618,13 @@
   // </if>
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'print-preview-destination-settings':
+        PrintPreviewDestinationSettingsElement;
+  }
+}
+
 customElements.define(
     PrintPreviewDestinationSettingsElement.is,
     PrintPreviewDestinationSettingsElement);
diff --git a/chrome/browser/resources/print_preview/ui/provisional_destination_resolver.ts b/chrome/browser/resources/print_preview/ui/provisional_destination_resolver.ts
index 36efcea..13679d3 100644
--- a/chrome/browser/resources/print_preview/ui/provisional_destination_resolver.ts
+++ b/chrome/browser/resources/print_preview/ui/provisional_destination_resolver.ts
@@ -188,6 +188,13 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'print-preview-provisional-destination-resolver':
+        PrintPreviewProvisionalDestinationResolverElement;
+  }
+}
+
 customElements.define(
     PrintPreviewProvisionalDestinationResolverElement.is,
     PrintPreviewProvisionalDestinationResolverElement);
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index 3c86f6d..d8df5ecc 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -151,6 +151,7 @@
     "os_settings_v3.html",
     "images/computer_and_bluetooth_switch.svg",
     "images/error_badge.svg",
+    "images/error_badge_dark.svg",
     "images/icon_add_circle.svg",
     "images/icon_add_wifi.svg",
     "images/icon_pair_bluetooth.svg",
diff --git a/chrome/browser/resources/settings/chromeos/images/error_badge.svg b/chrome/browser/resources/settings/chromeos/images/error_badge.svg
index a5ec4c1..b2333e09 100644
--- a/chrome/browser/resources/settings/chromeos/images/error_badge.svg
+++ b/chrome/browser/resources/settings/chromeos/images/error_badge.svg
@@ -1 +1 @@
-<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path d="M10 2c-4.416 0-8 3.584-8 8s3.584 8 8 8 8-3.584 8-8-3.584-8-8-8zm.8 12H9.2v-1.6h1.6V14zm0-3.2H9.2V6h1.6v4.8z" id="a"/></defs><g fill="none" fill-rule="evenodd"><circle fill="#FFF" cx="10" cy="10" r="10"/><use fill="#D93025" fill-rule="nonzero" xlink:href="#a"/></g></svg>
\ No newline at end of file
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="10" cy="10" r="6" fill="#D93025"/><path fill-rule="evenodd" clip-rule="evenodd" d="M9 10H11V6H9V10ZM10 2C5.584 2 2 5.584 2 10C2 14.416 5.584 18 10 18C14.416 18 18 14.416 18 10C18 5.584 14.416 2 10 2ZM10 16C6.6925 16 4 13.3075 4 10C4 6.6925 6.6925 4 10 4C13.3075 4 16 6.6925 16 10C16 13.3075 13.3075 16 10 16ZM9 14H11V12H9V14Z" fill="white"/></svg>
diff --git a/chrome/browser/resources/settings/chromeos/images/error_badge_dark.svg b/chrome/browser/resources/settings/chromeos/images/error_badge_dark.svg
new file mode 100644
index 0000000..39413b2
--- /dev/null
+++ b/chrome/browser/resources/settings/chromeos/images/error_badge_dark.svg
@@ -0,0 +1 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="10" cy="10" r="6" fill="#F28B82"/><path fill-rule="evenodd" clip-rule="evenodd" d="M9 10H11V6H9V10ZM10 2C5.584 2 2 5.584 2 10C2 14.416 5.584 18 10 18C14.416 18 18 14.416 18 10C18 5.584 14.416 2 10 2ZM10 16C6.6925 16 4 13.3075 4 10C4 6.6925 6.6925 4 10 4C13.3075 4 16 6.6925 16 10C16 13.3075 13.3075 16 10 16ZM9 14H11V12H9V14Z" fill="#202124"/><path fill-rule="evenodd" clip-rule="evenodd" d="M9 10H11V6H9V10ZM10 2C5.584 2 2 5.584 2 10C2 14.416 5.584 18 10 18C14.416 18 18 14.416 18 10C18 5.584 14.416 2 10 2ZM10 16C6.6925 16 4 13.3075 4 10C4 6.6925 6.6925 4 10 4C13.3075 4 16 6.6925 16 10C16 13.3075 13.3075 16 10 16ZM9 14H11V12H9V14Z" fill="white" fill-opacity="0.04"/></svg>
diff --git a/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_accounts.html b/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_accounts.html
index a8ff1c5..a8c230a 100644
--- a/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_accounts.html
+++ b/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_accounts.html
@@ -54,6 +54,10 @@
   }
 </style>
 
+<iron-media-query query="(prefers-color-scheme: dark)"
+  query-matches="{{isDarkModeActive_}}">
+</iron-media-query>
+
 <div class="settings-box first">
   <h2 class="first">
     <!-- Inner div needed to get spacing right in front of 'Learn more'. -->
@@ -86,7 +90,7 @@
       <div class="account-icon"
           style="background-image: [[getIconImageSet_(item.pic)]]">
         <img class="error-badge" hidden$="[[item.isSignedIn]]"
-            src="chrome://os-settings/images/error_badge.svg">
+            src="[[getErrorBadgeIcon_(isDarkModeActive_)]]">
       </div>
 
       <div class="middle two-line no-min-width">
diff --git a/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_accounts.js b/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_accounts.js
index 98d0ad7f..11401d0 100644
--- a/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_accounts.js
+++ b/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_accounts.js
@@ -21,6 +21,7 @@
 import {getImage} from '//resources/js/icon.js';
 import {WebUIListenerBehavior} from '//resources/js/web_ui_listener_behavior.m.js';
 import '//resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js';
+import '//resources/polymer/v3_0/iron-media-query/iron-media-query.js';
 import {loadTimeData} from '../../i18n_setup.js';
 import {Account} from '../os_people_page/account_manager_browser_proxy.js';
 import {Router, Route} from '../../router.js';
@@ -56,6 +57,15 @@
     },
 
     /**
+     * Whether dark mode is currently active.
+     * @private
+     */
+    isDarkModeActive_: {
+      type: Boolean,
+      value: false,
+    },
+
+    /**
      * The targeted account for menu and other operations.
      * @private {?KerberosAccount}
      */
@@ -136,6 +146,16 @@
   },
 
   /**
+   * @return {string} the icon to use for the error badge.
+   * @private
+   */
+  getErrorBadgeIcon_() {
+    return this.isDarkModeActive_ ?
+        'chrome://os-settings/images/error_badge_dark.svg' :
+        'chrome://os-settings/images/error_badge.svg';
+  },
+
+  /**
    * @param {string} iconUrl
    * @return {string} A CSS image-set for multiple scale factors.
    * @private
diff --git a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_permissions_setup_dialog.html b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_permissions_setup_dialog.html
index f87e77fa..5a705dc 100644
--- a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_permissions_setup_dialog.html
+++ b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_permissions_setup_dialog.html
@@ -15,6 +15,7 @@
 <link rel="import" href="../os_icons.html">
 <link rel="import" href="../../settings_shared_css.html">
 
+<!-- TODO(crbug.com/1272362): The layout needs to be finalized .-->
 <dom-module id="settings-multidevice-permissions-setup-dialog">
   <template>
     <style include="cr-shared-style settings-shared">
@@ -205,12 +206,9 @@
         <template is="dom-if" if="[[shouldShowSetupInstructionsSeparately_]]"
             restamp>
           <div id="instruction">
-            <iron-icon id="instruction-icon" icon="os-settings:failure-alert">
-            </iron-icon>
-            <template is="dom-if" if="[[shouldShowScreenLockInstructions_(flowState_)]]" restamp>
-              $i18n{multideviceNotificationAccessSetupScreenLockInstruction}
-            </template>
             <template is="dom-if" if="[[!shouldShowScreenLockInstructions_(flowState_)]]" restamp>
+              <iron-icon id="instruction-icon" icon="os-settings:failure-alert">
+              </iron-icon>
               $i18n{multideviceNotificationAccessSetupInstructions}
             </template>
           </div>
@@ -219,9 +217,11 @@
       <div id="buttonContainer" slot="button-container">
         <div id="half-container">
           <template is="dom-if" if="[[!hasStartedSetupAttempt_]]" restamp>
-            <cr-button id="learnMore" on-click="onLearnMoreClicked_">
-              $i18n{multideviceLearnMoreWithoutURL}
-            </cr-button>
+            <template is="dom-if" if="[[!shouldShowScreenLockInstructions_(flowState_)]]" restamp>
+              <cr-button id="learnMore" on-click="onLearnMoreClicked_">
+                $i18n{multideviceLearnMoreWithoutURL}
+              </cr-button>
+            </template>
           </template>
         </div>
         <div id="button-detail">
diff --git a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_screen_lock_subpage.html b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_screen_lock_subpage.html
index 70b4071..c5f0b14 100644
--- a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_screen_lock_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_screen_lock_subpage.html
@@ -35,6 +35,13 @@
         max-width: 200px;
         width: 100%;
       }
+
+      #subtext {
+        color: var(--cr-secondary-text-color);
+        font-size: 13px;
+        font-weight: normal;
+        padding-inline-start: 36px;
+      }
     </style>
     <div id="screen-lock-description">
       <div id="illustration"></div>
@@ -50,6 +57,9 @@
             <cr-radio-button name="pin+password"
                 label=$i18n{lockScreenPinOrPassword}>
             </cr-radio-button>
+            <div id="subtext">
+              $i18n{multideviceNotificationAccessSetupScreenLockInstruction}
+            </div>
             <template is="dom-if"
                 if="[[showConfigurePinButton_(selectedUnlockType)]]">
               <div class="list-item-end">
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js
index e6d1ee7..d86ffe3 100644
--- a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js
+++ b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js
@@ -79,6 +79,17 @@
       },
     },
 
+    /**
+     * The domain of the organization managing the device.
+     * @private
+     */
+    deviceManager_: {
+      type: String,
+      value() {
+        return loadTimeData.getString('deviceManager');
+      },
+    },
+
     /** @private */
     hasCheckedForUpdates_: {
       type: Boolean,
@@ -439,7 +450,9 @@
           return this.i18nAdvanced('aboutUpgradeSuccessChannelSwitch');
         }
         if (this.currentUpdateStatusEvent_.rollback) {
-          return this.i18nAdvanced('aboutRollbackSuccess');
+          return this.i18nAdvanced('aboutRollbackSuccess', {
+            substitutions: [this.deviceManager_],
+          });
         }
         return this.i18nAdvanced('aboutUpgradeRelaunch');
       case UpdateStatus.UPDATED:
@@ -459,7 +472,7 @@
         }
         if (this.currentUpdateStatusEvent_.rollback) {
           return this.i18nAdvanced('aboutRollbackInProgress', {
-            substitutions: [progressPercent],
+            substitutions: [this.deviceManager_, progressPercent],
           });
         }
         if (this.currentUpdateStatusEvent_.progress > 0) {
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/account_manager.html b/chrome/browser/resources/settings/chromeos/os_people_page/account_manager.html
index 41ea6672..2c5d45d 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/account_manager.html
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/account_manager.html
@@ -155,6 +155,13 @@
         width: 20px;
       }
 
+      @media (prefers-color-scheme: dark) {
+        .error-badge {
+          background: url(chrome://os-settings/images/error_badge_dark.svg)
+              center / cover no-repeat;
+        }
+      }
+
       :host-context([dir='rtl']) .error-badge {
         left: auto;
         right: 60%;
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.ts b/chrome/browser/resources/settings/settings_menu/settings_menu.ts
index b35f17f3..f6c0336 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.ts
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.ts
@@ -19,6 +19,7 @@
 import '../settings_shared_css.js';
 
 import {assert} from 'chrome://resources/js/assert.m.js';
+import {IronCollapseElement} from 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js';
 import {IronSelectorElement} from 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -28,8 +29,12 @@
 
 export interface SettingsMenuElement {
   $: {
+    autofill: HTMLLinkElement,
+    advancedButton: HTMLElement,
+    advancedSubmenu: IronCollapseElement,
     topMenu: IronSelectorElement,
     subMenu: IronSelectorElement,
+    people: HTMLLinkElement,
   };
 }
 
@@ -143,4 +148,10 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'settings-menu': SettingsMenuElement;
+  }
+}
+
 customElements.define(SettingsMenuElement.is, SettingsMenuElement);
diff --git a/chrome/browser/resources/tab_strip/BUILD.gn b/chrome/browser/resources/tab_strip/BUILD.gn
index 7ddfedb..66338ac 100644
--- a/chrome/browser/resources/tab_strip/BUILD.gn
+++ b/chrome/browser/resources/tab_strip/BUILD.gn
@@ -7,13 +7,10 @@
 import("//tools/grit/grit_rule.gni")
 import("//tools/grit/preprocess_if_expr.gni")
 import("//tools/polymer/html_to_js.gni")
+import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
 preprocess_folder = "preprocessed"
-preprocess_manifest = "preprocessed_manifest.json"
-preprocess_mojo_manifest = "preprocessed_mojo_manifest.json"
-preprocess_gen_manifest = "preprocessed_gen_manifest.json"
-preprocess_tabs_manifest = "preprocessed_tabs_manifest.json"
 
 generate_grd("build_grd") {
   grd_prefix = "tab_strip"
@@ -33,25 +30,14 @@
   ]
   input_files_base_dir = rebase_path(".", "//")
 
-  deps = [
-    ":preprocess",
-    ":preprocess_generated",
-    ":preprocess_mojo",
-    ":preprocess_tabs",
-  ]
-  manifest_files = [
-    "$target_gen_dir/$preprocess_manifest",
-    "$target_gen_dir/$preprocess_mojo_manifest",
-    "$target_gen_dir/$preprocess_gen_manifest",
-    "$target_gen_dir/$preprocess_tabs_manifest",
-  ]
+  deps = [ ":build_ts" ]
+  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
 }
 
 preprocess_if_expr("preprocess_mojo") {
   deps = [ "//chrome/browser/ui/webui/tab_strip:mojo_bindings_webui_js" ]
   in_folder = "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/tab_strip/"
   out_folder = "$target_gen_dir/$preprocess_folder"
-  out_manifest = "$target_gen_dir/$preprocess_mojo_manifest"
   in_files = [ "tab_strip.mojom-webui.js" ]
 }
 
@@ -59,18 +45,17 @@
   deps = [ "//chrome/browser/ui/webui/tabs:mojo_bindings_webui_js" ]
   in_folder = "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/tabs/"
   out_folder = "$target_gen_dir/$preprocess_folder"
-  out_manifest = "$target_gen_dir/$preprocess_tabs_manifest"
   in_files = [ "tabs.mojom-webui.js" ]
 }
 
 preprocess_if_expr("preprocess") {
   in_folder = "./"
   out_folder = "$target_gen_dir/$preprocess_folder"
-  out_manifest = "$target_gen_dir/$preprocess_manifest"
   in_files = [
     "drag_manager.js",
-    "tab_swiper.js",
     "tabs_api_proxy.js",
+    "tab_strip_embedder_proxy.js",
+    "tab_swiper.js",
   ]
 }
 
@@ -78,7 +63,6 @@
   deps = [ ":web_components" ]
   in_folder = target_gen_dir
   out_folder = "$target_gen_dir/$preprocess_folder"
-  out_manifest = "$target_gen_dir/$preprocess_gen_manifest"
   in_files = [
     "alert_indicator.js",
     "alert_indicators.js",
@@ -215,3 +199,32 @@
     "tab.js",
   ]
 }
+
+ts_library("build_ts") {
+  root_dir = "$target_gen_dir/$preprocess_folder"
+  out_dir = "$target_gen_dir/tsc"
+  tsconfig_base = "tsconfig_base.json"
+  in_files = [
+    "alert_indicator.js",
+    "alert_indicators.js",
+    "drag_manager.js",
+    "tab_group.js",
+    "tab.js",
+    "tab_list.js",
+    "tabs_api_proxy.js",
+    "tabs.mojom-webui.js",
+    "tab_strip_embedder_proxy.js",
+    "tab_strip.mojom-webui.js",
+    "tab_swiper.js",
+  ]
+  deps = [
+    "//third_party/polymer/v3_0:library",
+    "//ui/webui/resources:library",
+  ]
+  extra_deps = [
+    ":preprocess",
+    ":preprocess_generated",
+    ":preprocess_mojo",
+    ":preprocess_tabs",
+  ]
+}
diff --git a/chrome/browser/resources/tab_strip/alert_indicators.js b/chrome/browser/resources/tab_strip/alert_indicators.js
index cfc348a0..1bf0182 100644
--- a/chrome/browser/resources/tab_strip/alert_indicators.js
+++ b/chrome/browser/resources/tab_strip/alert_indicators.js
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import './alert_indicator.js';
+
 import {CustomElement} from 'chrome://resources/js/custom_element.js';
 
 import {AlertIndicatorElement} from './alert_indicator.js';
diff --git a/chrome/browser/resources/tab_strip/tab.js b/chrome/browser/resources/tab_strip/tab.js
index 19eb536..5a3d99a 100644
--- a/chrome/browser/resources/tab_strip/tab.js
+++ b/chrome/browser/resources/tab_strip/tab.js
@@ -4,6 +4,8 @@
 
 import './strings.m.js';
 
+import './alert_indicators.js';
+
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {CustomElement} from 'chrome://resources/js/custom_element.js';
 import {getFavicon} from 'chrome://resources/js/icon.js';
diff --git a/chrome/browser/resources/tab_strip/tab_list.js b/chrome/browser/resources/tab_strip/tab_list.js
index 393b5ebc..9adab5b 100644
--- a/chrome/browser/resources/tab_strip/tab_list.js
+++ b/chrome/browser/resources/tab_strip/tab_list.js
@@ -4,6 +4,7 @@
 
 import './strings.m.js';
 import './tab.js';
+import './tab_group.js';
 
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {addWebUIListener, removeWebUIListener, WebUIListener} from 'chrome://resources/js/cr.m.js';
diff --git a/chrome/browser/resources/tab_strip/tsconfig_base.json b/chrome/browser/resources/tab_strip/tsconfig_base.json
new file mode 100644
index 0000000..862320d
--- /dev/null
+++ b/chrome/browser/resources/tab_strip/tsconfig_base.json
@@ -0,0 +1,10 @@
+{
+  "extends": "../../../../tools/typescript/tsconfig_base.json",
+  "compilerOptions": {
+    "allowJs": true,
+    "noPropertyAccessFromIndexSignature": false,
+    "noUnusedLocals": false,
+    "noUnusedParameters": false,
+    "strictPropertyInitialization": false
+  }
+}
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_report_uploader_impl.h b/chrome/browser/safe_browsing/incident_reporting/incident_report_uploader_impl.h
index 74010d7..27489ed6 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_report_uploader_impl.h
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_report_uploader_impl.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/time/time.h"
 #include "chrome/browser/safe_browsing/incident_reporting/incident_report_uploader.h"
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h
index 2ad2868..38726011b 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h
@@ -11,7 +11,6 @@
 #include <memory>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/feature_list.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/safe_browsing/incident_reporting/last_download_finder.h b/chrome/browser/safe_browsing/incident_reporting/last_download_finder.h
index b49f791f..14c31ee 100644
--- a/chrome/browser/safe_browsing/incident_reporting/last_download_finder.h
+++ b/chrome/browser/safe_browsing/incident_reporting/last_download_finder.h
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_multi_source_observation.h"
 #include "chrome/browser/profiles/profile_manager_observer.h"
diff --git a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.h b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.h
index 6f7657ad..c3c7773 100644
--- a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.h
+++ b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/values.h"
 #include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chrome/browser/safety_check/android/BUILD.gn b/chrome/browser/safety_check/android/BUILD.gn
index f74b0b3..f6bac818 100644
--- a/chrome/browser/safety_check/android/BUILD.gn
+++ b/chrome/browser/safety_check/android/BUILD.gn
@@ -41,10 +41,13 @@
     "//chrome/browser/password_check:public_java",
     "//chrome/browser/password_check/android:password_check_java_enums",
     "//chrome/browser/password_manager/android:java",
+    "//chrome/browser/password_manager/android:settings_interface_java",
     "//chrome/browser/preferences:java",
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/safe_browsing/android:java",
     "//chrome/browser/settings:java",
+    "//chrome/browser/signin/services/android:java",
+    "//chrome/browser/sync/android:java",
     "//chrome/browser/ui/android/signin:java",
     "//components/browser_ui/settings/android:java",
     "//components/password_manager/core/browser:password_manager_java_enums",
diff --git a/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckMediator.java b/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckMediator.java
index a9fa523..8572f71 100644
--- a/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckMediator.java
+++ b/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckMediator.java
@@ -24,15 +24,19 @@
 import org.chromium.chrome.browser.password_check.PasswordCheckFactory;
 import org.chromium.chrome.browser.password_check.PasswordCheckReferrer;
 import org.chromium.chrome.browser.password_check.PasswordCheckUIStatus;
+import org.chromium.chrome.browser.password_manager.CredentialManagerLauncherFactory;
 import org.chromium.chrome.browser.password_manager.ManagePasswordsReferrer;
 import org.chromium.chrome.browser.password_manager.PasswordManagerHelper;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.safe_browsing.metrics.SettingsAccessPoint;
 import org.chromium.chrome.browser.safe_browsing.settings.SafeBrowsingSettingsFragment;
 import org.chromium.chrome.browser.safety_check.SafetyCheckProperties.PasswordsState;
 import org.chromium.chrome.browser.safety_check.SafetyCheckProperties.SafeBrowsingState;
 import org.chromium.chrome.browser.safety_check.SafetyCheckProperties.UpdatesState;
+import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
+import org.chromium.chrome.browser.sync.SyncService;
 import org.chromium.chrome.browser.ui.signin.SyncConsentActivityLauncher;
 import org.chromium.components.browser_ui.settings.SettingsLauncher;
 import org.chromium.components.signin.metrics.SigninAccessPoint;
@@ -495,9 +499,13 @@
             };
         } else {
             listener = (p) -> {
-                // Open the Passwords settings.
-                PasswordManagerHelper.showPasswordSettings(
-                        p.getContext(), ManagePasswordsReferrer.SAFETY_CHECK, mSettingsLauncher);
+                // Open the Password Manager.
+                PasswordManagerHelper.showPasswordSettings(p.getContext(),
+                        ManagePasswordsReferrer.SAFETY_CHECK, mSettingsLauncher,
+                        CredentialManagerLauncherFactory.getInstance().createLauncher(),
+                        IdentityServicesProvider.get().getIdentityManager(
+                                Profile.getLastUsedRegularProfile()),
+                        SyncService.get());
                 return true;
             };
         }
diff --git a/chrome/browser/search_engines/ui_thread_search_terms_data.h b/chrome/browser/search_engines/ui_thread_search_terms_data.h
index 8541954e..6f032cd 100644
--- a/chrome/browser/search_engines/ui_thread_search_terms_data.h
+++ b/chrome/browser/search_engines/ui_thread_search_terms_data.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "components/search_engines/search_terms_data.h"
 
 // Implementation of SearchTermsData that is only usable on the UI thread.
diff --git a/chrome/browser/sharesheet/sharesheet_service.cc b/chrome/browser/sharesheet/sharesheet_service.cc
index e5cdd949..217f2790 100644
--- a/chrome/browser/sharesheet/sharesheet_service.cc
+++ b/chrome/browser/sharesheet/sharesheet_service.cc
@@ -67,8 +67,7 @@
                                    SharesheetMetrics::LaunchSource source,
                                    DeliveredCallback delivered_callback,
                                    CloseCallback close_callback) {
-  DCHECK(intent->action == apps_util::kIntentActionSend ||
-         intent->action == apps_util::kIntentActionSendMultiple);
+  DCHECK(apps_util::IsShareIntent(intent));
   SharesheetMetrics::RecordSharesheetLaunchSource(source);
   PrepareToShowBubble(web_contents->GetWeakPtr(), std::move(intent),
                       contains_hosted_document, std::move(delivered_callback),
@@ -91,8 +90,7 @@
     DeliveredCallback delivered_callback,
     CloseCallback close_callback,
     ActionCleanupCallback action_cleanup_callback) {
-  DCHECK(intent->action == apps_util::kIntentActionSend ||
-         intent->action == apps_util::kIntentActionSendMultiple);
+  DCHECK(apps_util::IsShareIntent(intent));
 
   ShareAction* share_action = share_action_cache_->GetActionFromName(
       l10n_util::GetStringUTF16(IDS_NEARBY_SHARE_FEATURE_NAME));
diff --git a/chrome/browser/signin/chrome_signin_client.h b/chrome/browser/signin/chrome_signin_client.h
index dd11980..2511900 100644
--- a/chrome/browser/signin/chrome_signin_client.h
+++ b/chrome/browser/signin/chrome_signin_client.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/signin/logout_tab_helper.cc b/chrome/browser/signin/logout_tab_helper.cc
index f975493a..db560b21 100644
--- a/chrome/browser/signin/logout_tab_helper.cc
+++ b/chrome/browser/signin/logout_tab_helper.cc
@@ -9,7 +9,6 @@
 #include "components/signin/public/base/signin_metrics.h"
 #include "components/signin/public/identity_manager/accounts_mutator.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
-#include "content/public/browser/navigation_handle.h"
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(LogoutTabHelper);
 
@@ -19,22 +18,15 @@
 
 LogoutTabHelper::~LogoutTabHelper() = default;
 
-void LogoutTabHelper::DidFinishNavigation(
-    content::NavigationHandle* navigation_handle) {
-  // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
-  // frames. This caller was converted automatically to the primary main frame
-  // to preserve its semantics. Follow up to confirm correctness.
-  if (!navigation_handle->IsInPrimaryMainFrame())
-    return;
-
-  if (navigation_handle->IsErrorPage()) {
+void LogoutTabHelper::PrimaryPageChanged(content::Page& page) {
+  if (page.GetMainDocument().IsErrorDocument()) {
     // Failed to load the logout page, fallback to local signout.
     Profile* profile =
         Profile::FromBrowserContext(web_contents()->GetBrowserContext());
     IdentityManagerFactory::GetForProfile(profile)
         ->GetAccountsMutator()
         ->RemoveAllAccounts(signin_metrics::SourceForRefreshTokenOperation::
-                                kLogoutTabHelper_DidFinishNavigation);
+                                kLogoutTabHelper_PrimaryPageChanged);
   }
 
   // Delete this.
diff --git a/chrome/browser/signin/logout_tab_helper.h b/chrome/browser/signin/logout_tab_helper.h
index 40c2d6e..4f2974c 100644
--- a/chrome/browser/signin/logout_tab_helper.h
+++ b/chrome/browser/signin/logout_tab_helper.h
@@ -8,10 +8,6 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
-namespace content {
-class NavigationHandle;
-}
-
 // Tab helper used for logout tabs. Monitors if the logout tab loaded correctly
 // and fallbacks to local signout in case of failure.
 // Only the first navigation is monitored. Even though the logout page sometimes
@@ -32,8 +28,7 @@
   explicit LogoutTabHelper(content::WebContents* web_contents);
 
   // content::WebContentsObserver:
-  void DidFinishNavigation(
-      content::NavigationHandle* navigation_handle) override;
+  void PrimaryPageChanged(content::Page& page) override;
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
diff --git a/chrome/browser/signin/logout_tab_helper_unittest.cc b/chrome/browser/signin/logout_tab_helper_unittest.cc
new file mode 100644
index 0000000..7717ade
--- /dev/null
+++ b/chrome/browser/signin/logout_tab_helper_unittest.cc
@@ -0,0 +1,24 @@
+// 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/signin/logout_tab_helper.h"
+
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "content/public/test/navigation_simulator.h"
+#include "google_apis/gaia/gaia_urls.h"
+
+class LogoutTabHelperTest : public ChromeRenderViewHostTestHarness {};
+
+TEST_F(LogoutTabHelperTest, SelfDeleteInPrimaryPageChanged) {
+  LogoutTabHelper::CreateForWebContents(web_contents());
+
+  EXPECT_NE(nullptr, LogoutTabHelper::FromWebContents(web_contents()));
+
+  // Load the logout page.
+  content::NavigationSimulator::NavigateAndCommitFromBrowser(
+      web_contents(), GaiaUrls::GetInstance()->service_logout_url());
+
+  // The helper was deleted in PrimaryPageChanged.
+  EXPECT_EQ(nullptr, LogoutTabHelper::FromWebContents(web_contents()));
+}
diff --git a/chrome/browser/signin/signin_global_error.h b/chrome/browser/signin/signin_global_error.h
index 76651009..d33904568 100644
--- a/chrome/browser/signin/signin_global_error.h
+++ b/chrome/browser/signin/signin_global_error.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_SIGNIN_SIGNIN_GLOBAL_ERROR_H_
 
 #include <set>
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "chrome/browser/ui/global_error/global_error.h"
 #include "components/keyed_service/core/keyed_service.h"
diff --git a/chrome/browser/site_isolation/site_details_browsertest.cc b/chrome/browser/site_isolation/site_details_browsertest.cc
index 62fd17e4..085a173d 100644
--- a/chrome/browser/site_isolation/site_details_browsertest.cc
+++ b/chrome/browser/site_isolation/site_details_browsertest.cc
@@ -896,7 +896,8 @@
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), initial_url));
 
   // Load a fenced frame.
-  GURL fenced_frame_url = embedded_test_server()->GetURL("/iframe.html");
+  GURL fenced_frame_url =
+      embedded_test_server()->GetURL("/fenced_frames/iframe.html");
   content::RenderFrameHost* fenced_frame_host =
       fenced_frame_test_helper().CreateFencedFrame(
           web_contents()->GetMainFrame(), fenced_frame_url);
diff --git a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.h b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.h
index ecf63ab..8780122b 100644
--- a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.h
+++ b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_SPEECH_CHROME_SPEECH_RECOGNITION_MANAGER_DELEGATE_H_
 #define CHROME_BROWSER_SPEECH_CHROME_SPEECH_RECOGNITION_MANAGER_DELEGATE_H_
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/speech_recognition_event_listener.h"
 #include "content/public/browser/speech_recognition_manager_delegate.h"
 #include "content/public/browser/speech_recognition_session_config.h"
diff --git a/chrome/browser/status_icons/desktop_notification_balloon.h b/chrome/browser/status_icons/desktop_notification_balloon.h
index 44e426c..4a0bb66f 100644
--- a/chrome/browser/status_icons/desktop_notification_balloon.h
+++ b/chrome/browser/status_icons/desktop_notification_balloon.h
@@ -8,8 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
-
 namespace gfx {
 class ImageSkia;
 }
diff --git a/chrome/browser/subresource_filter/BUILD.gn b/chrome/browser/subresource_filter/BUILD.gn
index b50aaad0..77f802c2 100644
--- a/chrome/browser/subresource_filter/BUILD.gn
+++ b/chrome/browser/subresource_filter/BUILD.gn
@@ -39,10 +39,12 @@
       "//components/subresource_filter/android:java",
       "//content/public/test/android:content_java_test_support",
       "//net/android:net_java_test_support",
+      "//third_party/android_deps:espresso_java",
       "//third_party/android_support_test_runner:rules_java",
       "//third_party/android_support_test_runner:runner_java",
       "//third_party/androidx:androidx_test_runner_java",
       "//third_party/junit",
+      "//ui/android:ui_java_test_support",
       "//ui/android:ui_no_recycler_view_java",
       "//url:gurl_java",
     ]
diff --git a/chrome/browser/subresource_redirect/android/previews_android_bridge.h b/chrome/browser/subresource_redirect/android/previews_android_bridge.h
index 6339253e..17a73c94 100644
--- a/chrome/browser/subresource_redirect/android/previews_android_bridge.h
+++ b/chrome/browser/subresource_redirect/android/previews_android_bridge.h
@@ -9,7 +9,6 @@
 #include "base/android/jni_string.h"
 #include "base/android/jni_weak_ref.h"
 #include "base/android/scoped_java_ref.h"
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 
 namespace content {
diff --git a/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.h b/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.h
index 51ba97f..c930095 100644
--- a/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.h
+++ b/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.h
@@ -8,7 +8,6 @@
 #include <memory>
 
 #include "base/callback_list.h"
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/supervised_user/supervised_users.h"
 #include "content/public/browser/navigation_throttle.h"
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_throttle.h b/chrome/browser/supervised_user/supervised_user_navigation_throttle.h
index 9ba93545..ce0e90c 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_throttle.h
+++ b/chrome/browser/supervised_user/supervised_user_navigation_throttle.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/supervised_user/supervised_user_error_page/supervised_user_error_page.h"
 #include "chrome/browser/supervised_user/supervised_user_url_filter.h"
diff --git a/chrome/browser/support_tool/data_collector.h b/chrome/browser/support_tool/data_collector.h
index 93a50fad..f19a7f4 100644
--- a/chrome/browser/support_tool/data_collector.h
+++ b/chrome/browser/support_tool/data_collector.h
@@ -7,9 +7,12 @@
 
 #include <map>
 #include <memory>
+#include <set>
 #include <string>
 
 #include "base/callback.h"
+#include "base/files/file_path.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 // PII (Personally Identifiable Information) types that can exist in the debug
 // data and logs DataCollector collects.
@@ -18,8 +21,21 @@
   kUIHierarchyWindowTitles,
 };
 
+// The error code that a Support Tool component can return.
+enum class SupportToolError {
+  kUIHierarchyDataCollectorError,
+  // Error for testing.
+  kTestDataCollectorError,
+  kDataExportTempDirCreationFailed,
+  kDataExportCreateArchiveFailed,
+};
+
 using PIIMap = std::multimap<PIIType, std::string>;
 
+// Returns a SupportToolError if an error occurs to the callback.
+using DataCollectorDoneCallback =
+    base::OnceCallback<void(absl::optional<SupportToolError> error_code)>;
+
 // The DataCollector provides an interface for data sources that the
 // SupportToolHandler uses to collect debug data from multiple sources in Chrome
 // or Chrome OS with Support Tool.
@@ -37,9 +53,19 @@
   virtual const PIIMap& GetDetectedPII() = 0;
 
   // Collects all data that can be collected and detects the PII in the
-  // collected data.
+  // collected data. `on_data_collected_callback` won't be run if the
+  // DataCollector instance is deleted.
   virtual void CollectDataAndDetectPII(
-      base::OnceClosure on_data_collected_callback) = 0;
+      DataCollectorDoneCallback on_data_collected_callback) = 0;
+
+  // Masks all PII found in the collected data except `pii_types_to_keep`.
+  // Exports the collected data into file(s) in `target_directory`. Calls
+  // `on_exported_callback` when done. `on_exported_callback` won't be called
+  // if the DataCollector instance is deleted.
+  virtual void ExportCollectedDataWithPII(
+      std::set<PIIType> pii_types_to_keep,
+      base::FilePath target_directory,
+      DataCollectorDoneCallback on_exported_callback) = 0;
 };
 
 #endif  // CHROME_BROWSER_SUPPORT_TOOL_DATA_COLLECTOR_H_
diff --git a/chrome/browser/support_tool/support_tool_handler.cc b/chrome/browser/support_tool/support_tool_handler.cc
index 2ff927c..7bde6a5c 100644
--- a/chrome/browser/support_tool/support_tool_handler.cc
+++ b/chrome/browser/support_tool/support_tool_handler.cc
@@ -8,16 +8,69 @@
 #include <cstddef>
 #include <map>
 #include <memory>
+#include <set>
 #include <vector>
 
 #include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/check.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/task/bind_post_task.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/support_tool/data_collector.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/zlib/google/zip.h"
+
+// Zip archieves the contents of `src_path` into `target_path`. Adds ".zip"
+// extension to target file path. Returns true on success, false otherwise.
+bool ZipOutput(base::FilePath src_path, base::FilePath target_path) {
+  base::FilePath zip_path = target_path.AddExtension(FILE_PATH_LITERAL(".zip"));
+  if (!zip::Zip(src_path, zip_path, true)) {
+    LOG(ERROR) << "Couldn't zip files";
+    return false;
+  }
+  return true;
+}
+
+// Creates a unique temp directory to store the output files. The caller is
+// responsible for deleting the returned directory. Returns an empty FilePath in
+// case of an error.
+base::FilePath CreateTempDirForOutput() {
+  base::ScopedTempDir temp_dir;
+  if (!temp_dir.CreateUniqueTempDir()) {
+    LOG(ERROR) << "Unable to create temp dir.";
+    return base::FilePath{};
+  }
+  return temp_dir.Take();
+}
 
 SupportToolHandler::SupportToolHandler() = default;
-SupportToolHandler::~SupportToolHandler() = default;
+SupportToolHandler::~SupportToolHandler() {
+  CleanUp();
+}
+
+void SupportToolHandler::CleanUp() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Clean the temporary directory in a worker thread if it hasn't been removed
+  // yet.
+  if (!temp_dir_.empty()) {
+    base::ThreadPool::PostTask(
+        FROM_HERE,
+        {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+         base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
+        base::BindOnce(base::GetDeletePathRecursivelyCallback(),
+                       std::move(temp_dir_)));
+    temp_dir_.clear();
+  }
+}
 
 void SupportToolHandler::AddDataCollector(
     std::unique_ptr<DataCollector> collector) {
@@ -48,8 +101,12 @@
 }
 
 void SupportToolHandler::OnDataCollected(
-    base::RepeatingClosure barrier_closure) {
+    base::RepeatingClosure barrier_closure,
+    absl::optional<SupportToolError> error) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (error) {
+    collected_errors_.insert(error.value());
+  }
   std::move(barrier_closure).Run();
 }
 
@@ -60,5 +117,84 @@
     // Use std::multipmap.merge() function after migration to C++17.
     detected_pii_.insert(collected.begin(), collected.end());
   }
-  std::move(on_data_collection_done_callback_).Run(detected_pii_);
+
+  std::move(on_data_collection_done_callback_)
+      .Run(detected_pii_, collected_errors_);
+}
+
+void SupportToolHandler::ExportCollectedData(
+    std::set<PIIType> pii_types_to_keep,
+    base::FilePath target_path,
+    SupportToolDataExportedCallback on_data_exported_callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Clear the set of previously collected errors.
+  collected_errors_.clear();
+
+  on_data_export_done_callback_ = std::move(on_data_exported_callback);
+
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock()}, base::BindOnce(&CreateTempDirForOutput),
+      base::BindOnce(&SupportToolHandler::ExportIntoTempDir,
+                     weak_ptr_factory_.GetWeakPtr(), pii_types_to_keep,
+                     target_path));
+}
+
+void SupportToolHandler::ExportIntoTempDir(std::set<PIIType> pii_types_to_keep,
+                                           base::FilePath target_path,
+                                           base::FilePath tmp_path) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (tmp_path.empty()) {
+    collected_errors_.insert(
+        SupportToolError::kDataExportTempDirCreationFailed);
+    std::move(on_data_export_done_callback_).Run(collected_errors_);
+    return;
+  }
+
+  temp_dir_ = tmp_path;
+
+  base::RepeatingClosure export_data_barrier_closure = base::BarrierClosure(
+      data_collectors_.size(),
+      base::BindOnce(&SupportToolHandler::OnAllDataCollectorsDoneExporting,
+                     weak_ptr_factory_.GetWeakPtr(), temp_dir_, target_path));
+
+  for (auto& data_collector : data_collectors_) {
+    data_collector->ExportCollectedDataWithPII(
+        pii_types_to_keep, temp_dir_,
+        base::BindOnce(&SupportToolHandler::OnDataCollectorDoneExporting,
+                       weak_ptr_factory_.GetWeakPtr(),
+                       export_data_barrier_closure));
+  }
+}
+
+void SupportToolHandler::OnDataCollectorDoneExporting(
+    base::RepeatingClosure barrier_closure,
+    absl::optional<SupportToolError> error) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (error) {
+    collected_errors_.insert(error.value());
+  }
+  std::move(barrier_closure).Run();
+}
+
+void SupportToolHandler::OnAllDataCollectorsDoneExporting(
+    base::FilePath tmp_path,
+    base::FilePath path) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Archive the contents in the `tmp_path` into `path` in a zip file.
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock()}, base::BindOnce(&ZipOutput, tmp_path, path),
+      base::BindOnce(&SupportToolHandler::OnDataExportDone,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SupportToolHandler::OnDataExportDone(bool success) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Clean-up the temporary directory after exporting the data.
+  CleanUp();
+  if (!success) {
+    collected_errors_.insert(SupportToolError::kDataExportCreateArchiveFailed);
+  }
+  std::move(on_data_export_done_callback_).Run(collected_errors_);
 }
diff --git a/chrome/browser/support_tool/support_tool_handler.h b/chrome/browser/support_tool/support_tool_handler.h
index 0323184..f8c3835 100644
--- a/chrome/browser/support_tool/support_tool_handler.h
+++ b/chrome/browser/support_tool/support_tool_handler.h
@@ -6,31 +6,60 @@
 #define CHROME_BROWSER_SUPPORT_TOOL_SUPPORT_TOOL_HANDLER_H_
 
 #include <memory>
+#include <set>
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "chrome/browser/support_tool/data_collector.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 using SupportToolDataCollectedCallback =
-    base::OnceCallback<void(const PIIMap&)>;
+    base::OnceCallback<void(const PIIMap&, std::set<SupportToolError>)>;
+
+using SupportToolDataExportedCallback =
+    base::OnceCallback<void(std::set<SupportToolError>)>;
 
 // The SupportToolHandler collects debug data from a list of DataCollectors.
 //
 // EXAMPLE:
 // class Foo {
 //  public:
-//   void ProcessCollectedData(const PIIMap& detected) {
-//     // do something with the detected PII.
+//  void ProcessCollectedData(const PIIMap& detected,
+//                           std::set<SupportToolError> errors)
+//                           {
+//     // Do something with the detected PII.
+//     // Check if error is returned.
+//     if(!errors.empty()) {
+//       // do something with the error.
+//     }
 //   }
 //   void GetSupportData() {
-//     SupportToolHandler* handler = new SupportToolHandler();
-//     handler->AddSource(std::make_unique<DataCollectorOne>());
-//     handler->AddSource(std::make_unique<DataCollectorTwo>());
-//     handler->CollectSupportData(
-//         base::BindOnce(&Foo::ProcessCollectedData, this));
+//     handler_.AddSource(std::make_unique<DataCollectorOne>());
+//     handler_.AddSource(std::make_unique<DataCollectorTwo>());
+//     handler_.CollectSupportData(base::BindOnce(&Foo::ProcessCollectedData,
+//                                           weak_ptr_factory_.GetWeakPtr()));
 //   }
+//   void OnDataExported(std::set<SupportToolError>) {
+//     // Do something about the data that has been exported.
+//     // Check and do something if any errors returned.
+//   }
+//   void ExportSupportData() {
+//     std::set<PIIMap> pii_to_keep;
+//     // Add some PIITypes to keep into the pii_to_keep set.
+//     base::FilePath target_path{"directory_to_export_data"};
+//     handler_.ExportCollectedData(pii_to_keep,
+//                             target_path,
+//                             base::BindOnce(&Foo::OnDataExported,
+//                                            weak_ptr_factory_.GetWeakPtr()));
+//   }
+//  private:
+//   // The class has a SupportToolHandler member.
+//   SupportToolHandler handler_;
+//   base::WeakPtrFactory<Foo> weak_ptr_factory_{this};
 // };
 
 class SupportToolHandler {
@@ -42,25 +71,74 @@
   // will collect data from.
   void AddDataCollector(std::unique_ptr<DataCollector> collector);
 
-  // Collects data from the DataCollectors added to the handler.
+  // Collects data from the DataCollectors added to the handler. This function
+  // should be called only once on an instance of SupportToolHandler.
   void CollectSupportData(
       SupportToolDataCollectedCallback on_data_collection_done_callback);
 
+  // Exports collected data to the `target_path` and archives the file. This
+  // function should be called only once on an instance of SupportToolHandler.
+  void ExportCollectedData(
+      std::set<PIIType> pii_types_to_keep,
+      base::FilePath target_path,
+      SupportToolDataExportedCallback on_data_exported_callback);
+
  private:
   // OnDataCollected is called when a single DataCollector finished collecting
   // data. Runs `barrier_closure` to make the handler wait until all
   // DataCollectors finish collecting.
-  void OnDataCollected(base::RepeatingClosure barrier_closure);
+  void OnDataCollected(base::RepeatingClosure barrier_closure,
+                       absl::optional<SupportToolError> error);
 
   // OnAllDataCollected is called by a BarrierClosure when all DataCollectors
   // finish collecting data. Returns the detected PII by running
   // `on_data_collection_done_callback_`.
   void OnAllDataCollected();
 
+  // Exports collected data into the `tmp_path`. Creates a path for each
+  // DataCollector with their name. The DataCollectors will export their output
+  // to that path then the contents of the `tmp_path` will be put inside a zip
+  // archive on `target_path`.
+  void ExportIntoTempDir(std::set<PIIType> pii_types_to_keep,
+                         base::FilePath target_path,
+                         base::FilePath tmp_path);
+
+  // OnDataCollectorDoneExporting is called when a single DataCollector finished
+  // exporting data. Runs `barrier_closure` to make the handler wait until all
+  // DataCollectors finish collecting.
+  void OnDataCollectorDoneExporting(base::RepeatingClosure barrier_closure,
+                                    absl::optional<SupportToolError> error);
+
+  // OnAllDataCollectorsDoneExporting is called by a BarrierClosure when all
+  // DataCollectors finish exporting data to their given filepaths. Archives
+  // the data exported by DataCollectors inside a .zip archive and calls
+  // OnDataExportDone().
+  void OnAllDataCollectorsDoneExporting(base::FilePath tmp_path,
+                                        base::FilePath path);
+
+  // Cleans up the temporary directory created to store the output files and
+  // then calls `on_data_export_done_callback_`.
+  void OnDataExportDone(bool success);
+
+  // Cleans up `this.temp_dir_`. We need to clean-up the temporary directory
+  // explicitly since SupportToolHandler will work on UI thread and all file
+  // operation must be done in a worker thread to not block UI thread. We can
+  // only pass the file path between threads as sharing the ScopedTempDir object
+  // is not safe to pass between threads.
+  void CleanUp();
+
   SEQUENCE_CHECKER(sequence_checker_);
   PIIMap detected_pii_;
   std::vector<std::unique_ptr<DataCollector>> data_collectors_;
+  // Stores the set of errors that are returned from DataCollector calls. Reset
+  // the set each time SupportToolHandler starts executing a function.
+  std::set<SupportToolError> collected_errors_;
   SupportToolDataCollectedCallback on_data_collection_done_callback_;
+  SupportToolDataExportedCallback on_data_export_done_callback_;
+  // Temporary directory for storing the output files. Will be deleted when the
+  // data export is done or on destruction of the SupportToolHandler instance if
+  // it hasn't been removed before.
+  base::FilePath temp_dir_;
   base::WeakPtrFactory<SupportToolHandler> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/support_tool/support_tool_handler_unittest.cc b/chrome/browser/support_tool/support_tool_handler_unittest.cc
index f9a026c..cee0c37 100644
--- a/chrome/browser/support_tool/support_tool_handler_unittest.cc
+++ b/chrome/browser/support_tool/support_tool_handler_unittest.cc
@@ -4,20 +4,42 @@
 
 #include "chrome/browser/support_tool/support_tool_handler.h"
 
+#include <algorithm>
+#include <cstddef>
 #include <memory>
+#include <set>
 #include <string>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/callback.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/task/bind_post_task.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
 #include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/support_tool/data_collector.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/zlib/google/zip_reader.h"
+
+using testing::Pair;
+using testing::UnorderedElementsAre;
+
+const char kTestDataToWriteOnFile[] = "fake data to write to file for testing";
 
 // TestDataCollector implements DataCollector functions for testing.
 class TestDataCollector : public DataCollector {
  public:
-  explicit TestDataCollector(std::string name) : DataCollector(), name_(name) {}
+  explicit TestDataCollector(std::string name, bool error)
+      : DataCollector(), name_(name), error_(error) {}
   ~TestDataCollector() override = default;
 
   // Overrides from DataCollector.
@@ -30,70 +52,254 @@
   const PIIMap& GetDetectedPII() override { return pii_map_; }
 
   void CollectDataAndDetectPII(
-      base::OnceCallback<void()> on_data_collected_callback) override {
-    // Add fake PII for testing.
-    AddPIIForTesting();
-    std::move(on_data_collected_callback).Run();
+      DataCollectorDoneCallback on_data_collected_callback) override {
+    // Add fake PII for testing and return error to the callback if required.
+    PrepareDataCollectionOutput(std::move(on_data_collected_callback));
+  }
+
+  void ExportCollectedDataWithPII(
+      std::set<PIIType> pii_types_to_keep,
+      base::FilePath target_directory,
+      DataCollectorDoneCallback on_exported_callback) override {
+    on_exported_callback = base::BindPostTask(
+        base::ThreadTaskRunnerHandle::Get(), std::move(on_exported_callback));
+    base::ThreadPool::PostTask(
+        FROM_HERE, {base::MayBlock()},
+        base::BindOnce(&TestDataCollector::WriteFileForTesting,
+                       base::Unretained(this), target_directory,
+                       std::move(on_exported_callback)));
   }
 
  private:
   // Adds an entry to the PIIMap with the name of the data collector. The
-  // PIIType is not significant at this point so we use a random one.
-  void AddPIIForTesting() {
-    pii_map_.insert(std::pair<PIIType, std::string>(
-        PIIType::kUIHierarchyWindowTitles, name_));
+  // PIIType is not significant at this point so we use a random one. Then runs
+  // `callback`. Adds errors when running `callback` if this.error_ is true.
+  void PrepareDataCollectionOutput(DataCollectorDoneCallback callback) {
+    if (error_) {
+      std::move(callback).Run(SupportToolError::kTestDataCollectorError);
+    } else {
+      pii_map_.insert(std::pair<PIIType, std::string>(
+          PIIType::kUIHierarchyWindowTitles, name_));
+      std::move(callback).Run(absl::nullopt);
+    }
+  }
+
+  // Writes fake test data to the given `target_directory` under a file named as
+  // `TestDataCollector.name_`.
+  void WriteFileForTesting(base::FilePath target_directory,
+                           DataCollectorDoneCallback callback) {
+    if (error_) {
+      std::move(callback).Run(SupportToolError::kTestDataCollectorError);
+    } else {
+      base::FilePath target_file = target_directory.AppendASCII(name_);
+      base::WriteFile(target_file, kTestDataToWriteOnFile);
+      std::move(callback).Run(absl::nullopt);
+    }
   }
 
   // Name of the TestDataCollector. It will be used to create fake PII inside
   // the PIIMap.
   std::string name_;
+  // If error is true, the TestDataCollector will return error messages to the
+  // callbacks in the CollectDataAndDetectPII and ExportCollectedDataWithPII
+  // functions.
+  bool error_;
   PIIMap pii_map_;
+  base::WeakPtrFactory<TestDataCollector> weak_ptr_factory_{this};
 };
 
 class SupportToolHandlerTest : public ::testing::Test {
  public:
-  SupportToolHandlerTest() {
-    // Create and set up SupportToolHandler.
-    handler_ = std::make_unique<SupportToolHandler>();
-    SetUpHandler();
-  }
+  SupportToolHandlerTest() = default;
 
   SupportToolHandlerTest(const SupportToolHandlerTest&) = delete;
   SupportToolHandlerTest& operator=(const SupportToolHandlerTest&) = delete;
 
-  // Run SupportToolHandler's CollectSupportData and returns the result.
-  const PIIMap& CollectData() {
-    base::RunLoop run_loop;
-    handler_->CollectSupportData(
-        base::BindOnce(&SupportToolHandlerTest::OnDataCollected,
-                       base::Unretained(this), run_loop.QuitClosure()));
-    run_loop.Run();
-    return pii_result_;
+  void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
+
+  void TearDown() override {
+    if (!temp_dir_.IsValid())
+      return;
+    EXPECT_TRUE(temp_dir_.Delete());
   }
 
+  // Returns the contents of `zip_file` as a map [filename -> file contents].
+  std::map<std::string, std::string> ReadZipFileContents(
+      base::FilePath zip_file) {
+    const int64_t kMaxEntrySize = 10 * 1024;
+    std::map<std::string, std::string> result;
+    zip::ZipReader reader;
+    if (!reader.Open(zip_file)) {
+      ADD_FAILURE() << "Could not open " << zip_file;
+      return {};
+    }
+    while (reader.HasMore()) {
+      if (!reader.OpenCurrentEntryInZip()) {
+        ADD_FAILURE() << "Could not open entry in zip";
+        return {};
+      }
+      const zip::ZipReader::EntryInfo* entry = reader.current_entry_info();
+      std::string entry_file_name =
+          entry->file_path().BaseName().MaybeAsASCII();
+      if (entry->original_size() > kMaxEntrySize) {
+        ADD_FAILURE() << "Zip entry " << entry_file_name
+                      << " was too large: " << entry->original_size();
+        return {};
+      }
+
+      std::string entry_contents;
+      if (!reader.ExtractCurrentEntryToString(kMaxEntrySize, &entry_contents)) {
+        ADD_FAILURE() << "Can't read zip entry " << entry_file_name
+                      << " contents into string";
+        return {};
+      }
+      result[entry_file_name] = entry_contents;
+
+      if (!reader.AdvanceToNextEntry()) {
+        ADD_FAILURE() << "Could not advance to next entry";
+        return {};
+      }
+    }
+    return result;
+  }
+
+ protected:
+  base::FilePath GetPathForOutput() { return temp_dir_.GetPath(); }
+
  private:
-  // Adds TestDataCollectors to SupportToolHandler.
-  void SetUpHandler() {
-    handler_->AddDataCollector(
-        std::make_unique<TestDataCollector>("test_data_collector_1"));
-    handler_->AddDataCollector(
-        std::make_unique<TestDataCollector>("test_data_collector_2"));
-  }
-
-  void OnDataCollected(base::OnceClosure quit_closure, const PIIMap& result) {
-    pii_result_ = result;
-    std::move(quit_closure).Run();
-  }
-
-  std::unique_ptr<SupportToolHandler> handler_;
-  PIIMap pii_result_;
+  // The temporary directory that we'll store the output files.
+  base::ScopedTempDir temp_dir_;
+  base::test::TaskEnvironment task_environment;
 };
 
 TEST_F(SupportToolHandlerTest, CollectSupportData) {
-  base::test::TaskEnvironment task_environment;
+  // Set-up SupportToolHandler and add DataCollectors.
+  std::unique_ptr<SupportToolHandler> handler =
+      std::make_unique<SupportToolHandler>();
+  handler->AddDataCollector(
+      std::make_unique<TestDataCollector>("test_data_collector_1", false));
+  handler->AddDataCollector(
+      std::make_unique<TestDataCollector>("test_data_collector_2", false));
 
-  const PIIMap& detected_pii = CollectData();
+  // Collect support data.
+  base::test::TestFuture<PIIMap, std::set<SupportToolError>> test_future;
+  handler->CollectSupportData(
+      test_future.GetCallback<const PIIMap&, std::set<SupportToolError>>());
+  const PIIMap& detected_pii = test_future.Get<0>();
+  std::set<SupportToolError> errors = test_future.Get<1>();
+
   // Check if the detected PII map returned from the SupportToolHandler is
   // empty.
   EXPECT_FALSE(detected_pii.empty());
+  // Check if the error message returned is empty.
+  EXPECT_TRUE(errors.empty());
+}
+
+TEST_F(SupportToolHandlerTest, ExportSupportDataTest) {
+  // Set-up SupportToolHandler and add DataCollectors.
+  std::unique_ptr<SupportToolHandler> handler =
+      std::make_unique<SupportToolHandler>();
+  handler->AddDataCollector(
+      std::make_unique<TestDataCollector>("test_data_collector_1", false));
+  handler->AddDataCollector(
+      std::make_unique<TestDataCollector>("test_data_collector_2", false));
+
+  // Export collected data into a file in temporary directory.
+  base::FilePath target_path = GetPathForOutput().Append(
+      FILE_PATH_LITERAL("support-tool-export-success"));
+  base::test::TestFuture<std::set<SupportToolError>> test_future;
+  std::set<PIIType> pii_types{PIIType::kUIHierarchyWindowTitles};
+  handler->ExportCollectedData(pii_types, target_path,
+                               test_future.GetCallback());
+  std::set<SupportToolError> errors = test_future.Get();
+  EXPECT_TRUE(errors.empty());
+
+  // SupportToolHandler will achieve the data into a .zip archieve.
+  target_path = target_path.AddExtension(FILE_PATH_LITERAL(".zip"));
+  EXPECT_TRUE(base::PathExists(target_path));
+  // Read the output file contents.
+  std::map<std::string, std::string> zip_contents =
+      ReadZipFileContents(target_path);
+  // Each TestDataCollector should write the output contents on a file in the
+  // .zip file which has a same name as the data collector.
+  EXPECT_THAT(zip_contents,
+              UnorderedElementsAre(
+                  Pair("test_data_collector_1", kTestDataToWriteOnFile),
+                  Pair("test_data_collector_2", kTestDataToWriteOnFile)));
+}
+
+TEST_F(SupportToolHandlerTest, ErrorMessageOnCollectData) {
+  // Set-up SupportToolHandler and add DataCollectors.
+  std::unique_ptr<SupportToolHandler> handler =
+      std::make_unique<SupportToolHandler>();
+  handler->AddDataCollector(
+      std::make_unique<TestDataCollector>("test_data_collector_1", false));
+  handler->AddDataCollector(
+      std::make_unique<TestDataCollector>("test_data_collector_2", false));
+  handler->AddDataCollector(
+      std::make_unique<TestDataCollector>("test_data_collector_3", true));
+
+  base::test::TestFuture<PIIMap, std::set<SupportToolError>> test_future;
+  handler->CollectSupportData(
+      test_future.GetCallback<const PIIMap&, std::set<SupportToolError>>());
+  const PIIMap& detected_pii = test_future.Get<0>();
+  std::set<SupportToolError> errors = test_future.Get<1>();
+
+  // Check if the detected PII map returned from the SupportToolHandler is
+  // empty.
+  EXPECT_FALSE(detected_pii.empty());
+  // Check if the error message returned contains the expected result.
+  EXPECT_FALSE(errors.empty());
+  // SupportToolError::kTestDataCollectorError should be present in the errors
+  // returned.
+  size_t expected_size = 1;
+  EXPECT_EQ(errors.size(), expected_size);
+  EXPECT_NE(errors.find(SupportToolError::kTestDataCollectorError),
+            errors.end());
+}
+
+TEST_F(SupportToolHandlerTest, ErrorMessageOnExportSupportData) {
+  // Set-up SupportToolHandler and add DataCollectors.
+  std::unique_ptr<SupportToolHandler> handler =
+      std::make_unique<SupportToolHandler>();
+  handler->AddDataCollector(
+      std::make_unique<TestDataCollector>("test_data_collector_1", false));
+  handler->AddDataCollector(
+      std::make_unique<TestDataCollector>("test_data_collector_2", false));
+  handler->AddDataCollector(
+      std::make_unique<TestDataCollector>("test_data_collector_3", true));
+
+  // Create the path inside a temporary directory to store the output files.
+  base::FilePath target_path =
+      GetPathForOutput().Append(FILE_PATH_LITERAL("support-tool-export-error"));
+
+  // Export collected data into the target temporary directory.
+  base::test::TestFuture<std::set<SupportToolError>> test_future;
+  std::set<PIIType> pii_types{PIIType::kUIHierarchyWindowTitles};
+  handler->ExportCollectedData(pii_types, target_path,
+                               test_future.GetCallback());
+
+  // Check the error message.
+  std::set<SupportToolError> errors = test_future.Get();
+  EXPECT_FALSE(errors.empty());
+  // SupportToolError::kTestDataCollectorError should be present in the errors
+  // returned.
+  size_t expected_size = 1;
+  EXPECT_EQ(errors.size(), expected_size);
+  EXPECT_NE(errors.find(SupportToolError::kTestDataCollectorError),
+            errors.end());
+
+  // SupportToolHandler will archive the data into a .zip archive.
+  target_path = target_path.AddExtension(FILE_PATH_LITERAL(".zip"));
+  EXPECT_TRUE(base::PathExists(target_path));
+  // Read the output file contents.
+  std::map<std::string, std::string> zip_contents =
+      ReadZipFileContents(target_path);
+  // Each TestDataCollector should write the output contents on a file in the
+  // .zip file which has a same name as the data collector. The data collectors
+  // with error won't create and write to any file.
+  EXPECT_THAT(zip_contents,
+              UnorderedElementsAre(
+                  Pair("test_data_collector_1", kTestDataToWriteOnFile),
+                  Pair("test_data_collector_2", kTestDataToWriteOnFile)));
 }
diff --git a/chrome/browser/support_tool/ui_hierarchy_data_collector.cc b/chrome/browser/support_tool/ui_hierarchy_data_collector.cc
index 8cebe8f..3d7d3a4 100644
--- a/chrome/browser/support_tool/ui_hierarchy_data_collector.cc
+++ b/chrome/browser/support_tool/ui_hierarchy_data_collector.cc
@@ -9,14 +9,32 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/files/file_path.h"
 #include "base/location.h"
 #include "base/task/post_task.h"
 #include "base/task/thread_pool.h"
 #include "chrome/browser/support_tool/data_collector.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 UiHierarchyDataCollector::UiHierarchyDataCollector() = default;
 UiHierarchyDataCollector::~UiHierarchyDataCollector() = default;
 
+namespace {
+absl::optional<PIIMap> CollectUiHierarchyData() {
+  // Just an empty function to create the skeleton for the DataCollector.
+  // Data will be collected and PIIMap will be filled here.
+  PIIMap map;
+  return map;
+}
+
+bool WriteOutputFile(std::string data, base::FilePath target_directory) {
+  // Just an empty function. This will create output file in given
+  // `target_directory` and write the data to it. Return success for now.
+  return true;
+}
+
+}  // namespace
+
 std::string UiHierarchyDataCollector::GetName() const {
   return "UI Hierarchy";
 }
@@ -30,9 +48,50 @@
 }
 
 void UiHierarchyDataCollector::CollectDataAndDetectPII(
-    base::OnceCallback<void()> on_data_collected_callback) {
-  // This function Will be filled later.
-  // Data will be collected and this.pii_map_ will be filled here.
-  base::ThreadPool::PostTask(
-      FROM_HERE, base::BindOnce(std::move(on_data_collected_callback)));
+    DataCollectorDoneCallback on_data_collected_callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, base::BindOnce(&CollectUiHierarchyData),
+      base::BindOnce(&UiHierarchyDataCollector::OnDataCollectedAndPIIDetected,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(on_data_collected_callback)));
+}
+
+void UiHierarchyDataCollector::OnDataCollectedAndPIIDetected(
+    DataCollectorDoneCallback on_data_collected_callback,
+    absl::optional<PIIMap> pii_map) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (pii_map) {
+    pii_map_ = pii_map.value();
+    std::move(on_data_collected_callback).Run(absl::nullopt);
+  } else {
+    std::move(on_data_collected_callback)
+        .Run(SupportToolError::kUIHierarchyDataCollectorError);
+  }
+}
+
+void UiHierarchyDataCollector::ExportCollectedDataWithPII(
+    std::set<PIIType> pii_types_to_keep,
+    base::FilePath target_directory,
+    DataCollectorDoneCallback on_exported_callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock()},
+      base::BindOnce(&WriteOutputFile, "some place holder data",
+                     target_directory),
+      base::BindOnce(&UiHierarchyDataCollector::OnDataExportDone,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(on_exported_callback)));
+}
+
+void UiHierarchyDataCollector::OnDataExportDone(
+    DataCollectorDoneCallback on_exported_callback,
+    bool success) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (success) {
+    std::move(on_exported_callback).Run(absl::nullopt);
+  } else {
+    std::move(on_exported_callback)
+        .Run(SupportToolError::kUIHierarchyDataCollectorError);
+  }
 }
diff --git a/chrome/browser/support_tool/ui_hierarchy_data_collector.h b/chrome/browser/support_tool/ui_hierarchy_data_collector.h
index fc018ff8..c5d802c 100644
--- a/chrome/browser/support_tool/ui_hierarchy_data_collector.h
+++ b/chrome/browser/support_tool/ui_hierarchy_data_collector.h
@@ -5,7 +5,11 @@
 #ifndef CHROME_BROWSER_SUPPORT_TOOL_UI_HIERARCHY_DATA_COLLECTOR_H_
 #define CHROME_BROWSER_SUPPORT_TOOL_UI_HIERARCHY_DATA_COLLECTOR_H_
 
+#include <set>
+
 #include "base/callback_forward.h"
+#include "base/files/file_path.h"
+#include "base/sequence_checker.h"
 #include "chrome/browser/support_tool/data_collector.h"
 
 class UiHierarchyDataCollector : public DataCollector {
@@ -21,10 +25,28 @@
   const PIIMap& GetDetectedPII() override;
 
   void CollectDataAndDetectPII(
-      base::OnceCallback<void()> on_data_collected_callback) override;
+      DataCollectorDoneCallback on_data_collected_callback) override;
+
+  void ExportCollectedDataWithPII(
+      std::set<PIIType> pii_types_to_keep,
+      base::FilePath target_directory,
+      DataCollectorDoneCallback on_exported_callback) override;
 
  private:
+  // Runs `on_data_collected_callback` when data collection is done. Returns an
+  // error message to the callback if the optional `pii_map` is nullopt.
+  void OnDataCollectedAndPIIDetected(
+      DataCollectorDoneCallback on_data_collected_callback,
+      absl::optional<PIIMap> pii_map);
+
+  // Runs `on_exported_callback` when the data export is done. Returns an error
+  // to the callback if `success` is false.
+  void OnDataExportDone(DataCollectorDoneCallback on_exported_callback,
+                        bool success);
+
+  SEQUENCE_CHECKER(sequence_checker_);
   PIIMap pii_map_;
+  base::WeakPtrFactory<UiHierarchyDataCollector> weak_ptr_factory_{this};
 };
 
 #endif  // CHROME_BROWSER_SUPPORT_TOOL_UI_HIERARCHY_DATA_COLLECTOR_H_
diff --git a/chrome/browser/sync/glue/synced_window_delegate_android.h b/chrome/browser/sync/glue/synced_window_delegate_android.h
index 5af7298..563879b 100644
--- a/chrome/browser/sync/glue/synced_window_delegate_android.h
+++ b/chrome/browser/sync/glue/synced_window_delegate_android.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_SYNC_GLUE_SYNCED_WINDOW_DELEGATE_ANDROID_H_
 #define CHROME_BROWSER_SYNC_GLUE_SYNCED_WINDOW_DELEGATE_ANDROID_H_
 
-#include "base/compiler_specific.h"
 #include "components/sessions/core/session_id.h"
 #include "components/sync_sessions/synced_window_delegate.h"
 
diff --git a/chrome/browser/sync/sync_startup_tracker.h b/chrome/browser/sync/sync_startup_tracker.h
index aef7260..5769a434 100644
--- a/chrome/browser/sync/sync_startup_tracker.h
+++ b/chrome/browser/sync/sync_startup_tracker.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_SYNC_SYNC_STARTUP_TRACKER_H_
 #define CHROME_BROWSER_SYNC_SYNC_STARTUP_TRACKER_H_
 
-#include "base/compiler_specific.h"
 #include "components/sync/driver/sync_service_observer.h"
 
 // SyncStartupTracker provides a centralized way for observers to detect when
diff --git a/chrome/browser/sync/test/integration/await_match_status_change_checker.h b/chrome/browser/sync/test/integration/await_match_status_change_checker.h
index c46fcf4..227268d 100644
--- a/chrome/browser/sync/test/integration/await_match_status_change_checker.h
+++ b/chrome/browser/sync/test/integration/await_match_status_change_checker.h
@@ -8,7 +8,6 @@
 #include <iosfwd>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h"
 
 // Helper class used in the datatype specific AwaitAllModelsMatch
diff --git a/chrome/browser/sync/test/integration/quiesce_status_change_checker.h b/chrome/browser/sync/test/integration/quiesce_status_change_checker.h
index 4046133..6d9778b 100644
--- a/chrome/browser/sync/test/integration/quiesce_status_change_checker.h
+++ b/chrome/browser/sync/test/integration/quiesce_status_change_checker.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h"
 
 namespace syncer {
diff --git a/chrome/browser/sync/test/integration/sessions_helper.h b/chrome/browser/sync/test/integration/sessions_helper.h
index 56cfdad..60289f5 100644
--- a/chrome/browser/sync/test/integration/sessions_helper.h
+++ b/chrome/browser/sync/test/integration/sessions_helper.h
@@ -11,7 +11,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "components/sessions/core/session_types.h"
diff --git a/chrome/browser/sync/test/integration/single_client_status_change_checker.h b/chrome/browser/sync/test/integration/single_client_status_change_checker.h
index 7788c1e..9a50f77 100644
--- a/chrome/browser/sync/test/integration/single_client_status_change_checker.h
+++ b/chrome/browser/sync/test/integration/single_client_status_change_checker.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_SYNC_TEST_INTEGRATION_SINGLE_CLIENT_STATUS_CHANGE_CHECKER_H_
 #define CHROME_BROWSER_SYNC_TEST_INTEGRATION_SINGLE_CLIENT_STATUS_CHANGE_CHECKER_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h"
 #include "components/sync/driver/sync_service_observer.h"
 
diff --git a/chrome/browser/sync/test/integration/sync_extension_installer.h b/chrome/browser/sync/test/integration/sync_extension_installer.h
index a4a582b..fac81ec 100644
--- a/chrome/browser/sync/test/integration/sync_extension_installer.h
+++ b/chrome/browser/sync/test/integration/sync_extension_installer.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_SYNC_TEST_INTEGRATION_SYNC_EXTENSION_INSTALLER_H_
 #define CHROME_BROWSER_SYNC_TEST_INTEGRATION_SYNC_EXTENSION_INSTALLER_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/sync/test/integration/sync_service_impl_harness.h b/chrome/browser/sync/test/integration/sync_service_impl_harness.h
index cf5ad9d..ea6806c 100644
--- a/chrome/browser/sync/test/integration/sync_service_impl_harness.h
+++ b/chrome/browser/sync/test/integration/sync_service_impl_harness.h
@@ -9,7 +9,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "build/chromeos_buildflags.h"
 #include "components/sync/base/user_selectable_type.h"
 #include "components/sync/driver/sync_service_impl.h"
diff --git a/chrome/browser/sync_file_system/local/local_file_change_tracker.h b/chrome/browser/sync_file_system/local/local_file_change_tracker.h
index 0fbb554..40cfd5c 100644
--- a/chrome/browser/sync_file_system/local/local_file_change_tracker.h
+++ b/chrome/browser/sync_file_system/local/local_file_change_tracker.h
@@ -10,7 +10,6 @@
 #include <map>
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/containers/circular_deque.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
diff --git a/chrome/browser/sync_file_system/local/local_file_sync_status.h b/chrome/browser/sync_file_system/local/local_file_sync_status.h
index 9b44316..ad59adc 100644
--- a/chrome/browser/sync_file_system/local/local_file_sync_status.h
+++ b/chrome/browser/sync_file_system/local/local_file_sync_status.h
@@ -11,7 +11,6 @@
 #include <set>
 #include <utility>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/observer_list.h"
 #include "storage/browser/file_system/file_system_url.h"
diff --git a/chrome/browser/translate/chrome_translate_client.cc b/chrome/browser/translate/chrome_translate_client.cc
index 7273bcc3..ff1e4a7 100644
--- a/chrome/browser/translate/chrome_translate_client.cc
+++ b/chrome/browser/translate/chrome_translate_client.cc
@@ -95,12 +95,11 @@
   if (translate::IsSubFrameTranslationEnabled()) {
     per_frame_translate_driver_ =
         std::make_unique<translate::PerFrameContentTranslateDriver>(
-            *web_contents, &web_contents->GetController(),
-            UrlLanguageHistogramFactory::GetForBrowserContext(
-                web_contents->GetBrowserContext()));
+            *web_contents, UrlLanguageHistogramFactory::GetForBrowserContext(
+                               web_contents->GetBrowserContext()));
   } else {
     translate_driver_ = std::make_unique<translate::ContentTranslateDriver>(
-        *web_contents, &web_contents->GetController(),
+        *web_contents,
         UrlLanguageHistogramFactory::GetForBrowserContext(
             web_contents->GetBrowserContext()),
         TranslateModelServiceFactory::GetForProfile(
diff --git a/chrome/browser/translate/translate_frame_binder_browsertest.cc b/chrome/browser/translate/translate_frame_binder_browsertest.cc
index 5e379c5..973baf05 100644
--- a/chrome/browser/translate/translate_frame_binder_browsertest.cc
+++ b/chrome/browser/translate/translate_frame_binder_browsertest.cc
@@ -173,8 +173,10 @@
   content::test::FencedFrameTestHelper fenced_frame_helper_;
 };
 
+// TODO(crbug.com/1270474): Make this test work properly with
+// `FencedFrameTestHelper`, as it appears to fail on certain platforms.
 IN_PROC_BROWSER_TEST_F(TranslateFrameBinderFencedFrameBrowserTest,
-                       NotBindingInFencedFrame) {
+                       DISABLED_NotBindingInFencedFrame) {
   TestTranslateDriverBindingContentBrowserClient test_browser_client;
   auto* old_browser_client = SetBrowserClientForTesting(&test_browser_client);
 
@@ -183,7 +185,8 @@
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), initial_url));
 
   // Create a fenced frame.
-  const GURL fenced_frame_url = embedded_test_server()->GetURL("/title1.html");
+  const GURL fenced_frame_url =
+      embedded_test_server()->GetURL("/fenced_frames/title1.html");
   content::RenderFrameHost* fenced_frame_host =
       fenced_frame_test_helper().CreateFencedFrame(
           web_contents()->GetMainFrame(), fenced_frame_url);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 9dd903f..2987967e 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -15,7 +15,7 @@
 import("//chrome/common/features.gni")
 import("//chromeos/assistant/assistant.gni")
 import("//chromeos/components/chromebox_for_meetings/buildflags/buildflags.gni")
-import("//chromeos/dbus/use_real_dbus_clients.gni")
+import("//chromeos/dbus/config/use_real_dbus_clients.gni")
 import("//components/feed/features.gni")
 import("//components/nacl/features.gni")
 import("//components/offline_pages/buildflags/features.gni")
@@ -2454,6 +2454,8 @@
       "webui/chromeos/in_session_password_change/confirm_password_change_handler.h",
       "webui/chromeos/in_session_password_change/lock_screen_network_dialog.cc",
       "webui/chromeos/in_session_password_change/lock_screen_network_dialog.h",
+      "webui/chromeos/in_session_password_change/lock_screen_network_handler.cc",
+      "webui/chromeos/in_session_password_change/lock_screen_network_handler.h",
       "webui/chromeos/in_session_password_change/lock_screen_network_ui.cc",
       "webui/chromeos/in_session_password_change/lock_screen_network_ui.h",
       "webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.cc",
@@ -2935,6 +2937,7 @@
       "//chromeos/components/multidevice/logging",
       "//chromeos/components/proximity_auth",
       "//chromeos/components/quick_answers",
+      "//chromeos/components/quick_answers/public/cpp:cpp",
       "//chromeos/components/quick_answers/public/cpp:prefs",
       "//chromeos/components/string_matching",
       "//chromeos/components/tether",
@@ -4571,10 +4574,10 @@
       "views/toolbar/chrome_labs_utils.h",
       "views/toolbar/home_button.cc",
       "views/toolbar/home_button.h",
-      "views/toolbar/read_later_toolbar_button.cc",
-      "views/toolbar/read_later_toolbar_button.h",
       "views/toolbar/reload_button.cc",
       "views/toolbar/reload_button.h",
+      "views/toolbar/side_panel_toolbar_button.cc",
+      "views/toolbar/side_panel_toolbar_button.h",
       "views/toolbar/toolbar_account_icon_container_view.cc",
       "views/toolbar/toolbar_account_icon_container_view.h",
       "views/toolbar/toolbar_action_view.cc",
diff --git a/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.h b/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.h
index c16cb83..051cb178 100644
--- a/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.h
+++ b/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.h
@@ -11,7 +11,6 @@
 
 #include "base/android/scoped_java_ref.h"
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/autofill/autofill_keyboard_accessory_adapter.h"
 #include "chrome/browser/ui/autofill/autofill_popup_view.h"
 
diff --git a/chrome/browser/ui/android/autofill/autofill_popup_view_android.h b/chrome/browser/ui/android/autofill/autofill_popup_view_android.h
index b3f7ea2..12f2ec6 100644
--- a/chrome/browser/ui/android/autofill/autofill_popup_view_android.h
+++ b/chrome/browser/ui/android/autofill/autofill_popup_view_android.h
@@ -9,7 +9,6 @@
 #include <stddef.h>
 
 #include "base/android/scoped_java_ref.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/autofill/autofill_popup_view.h"
 #include "ui/android/view_android.h"
 
diff --git a/chrome/browser/ui/android/autofill/snackbar/autofill_snackbar_view_android.h b/chrome/browser/ui/android/autofill/snackbar/autofill_snackbar_view_android.h
index 43fbdaa..26d9c8f 100644
--- a/chrome/browser/ui/android/autofill/snackbar/autofill_snackbar_view_android.h
+++ b/chrome/browser/ui/android/autofill/snackbar/autofill_snackbar_view_android.h
@@ -9,7 +9,6 @@
 #include <stddef.h>
 
 #include "base/android/scoped_java_ref.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/autofill/payments/autofill_snackbar_controller.h"
 #include "chrome/browser/ui/autofill/payments/autofill_snackbar_view.h"
 
diff --git a/chrome/browser/ui/android/infobars/infobar_container_android.h b/chrome/browser/ui/android/infobars/infobar_container_android.h
index 4fb01ff..fc9d566 100644
--- a/chrome/browser/ui/android/infobars/infobar_container_android.h
+++ b/chrome/browser/ui/android/infobars/infobar_container_android.h
@@ -9,7 +9,6 @@
 
 #include "base/android/jni_weak_ref.h"
 #include "base/android/scoped_java_ref.h"
-#include "base/compiler_specific.h"
 #include "components/infobars/core/infobar_container.h"
 
 class InfoBarContainerAndroid : public infobars::InfoBarContainer {
diff --git a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/WebContentsDarkModeMessageController.java b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/WebContentsDarkModeMessageController.java
index 2a227f26..812daf50 100644
--- a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/WebContentsDarkModeMessageController.java
+++ b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/WebContentsDarkModeMessageController.java
@@ -46,8 +46,6 @@
  * feature.
  */
 public class WebContentsDarkModeMessageController {
-    private static final String FEEDBACK_CATEGORY_TAG = "USER_INITIATED_FEEDBACK_REPORT_AUTO_DARK";
-    private static final String FEEDBACK_CONTEXT = "chrome_auto_dark";
     @VisibleForTesting
     static final String FEEDBACK_DIALOG_PARAM = "feedback_dialog";
 
@@ -224,9 +222,8 @@
             HelpAndFeedbackLauncher launcher, Activity activity, Profile profile, String url) {
         // TODO(crbug.com/1260152): Import ScreenshotMode instead of hardcoding value once new build
         //  target added.
-        launcher.showFeedback(activity, profile, url,
-                activity.getPackageName() + FEEDBACK_CATEGORY_TAG,
-                /* ScreenshotMode.DEFAULT */ 0, FEEDBACK_CONTEXT);
+        launcher.showFeedback(activity, profile, url, null,
+                /* ScreenshotMode.DEFAULT */ 0, null);
     }
 
     /**
diff --git a/chrome/browser/ui/android/omnibox/BUILD.gn b/chrome/browser/ui/android/omnibox/BUILD.gn
index 7c2d169..4d9de4f 100644
--- a/chrome/browser/ui/android/omnibox/BUILD.gn
+++ b/chrome/browser/ui/android/omnibox/BUILD.gn
@@ -151,6 +151,7 @@
     "//chrome/browser/ui/android/layouts:java",
     "//chrome/browser/ui/android/native_page:java",
     "//chrome/browser/ui/android/night_mode:java",
+    "//chrome/browser/ui/android/page_info:java",
     "//chrome/browser/ui/android/searchactivityutils:java",
     "//chrome/browser/ui/android/theme:java",
     "//chrome/browser/user_education:java",
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusCoordinator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusCoordinator.java
index b8360cf..6e94f520 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusCoordinator.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusCoordinator.java
@@ -21,13 +21,13 @@
 import org.chromium.chrome.browser.omnibox.R;
 import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
+import org.chromium.chrome.browser.page_info.ChromePageInfoHighlight;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider;
 import org.chromium.chrome.browser.user_education.IPHCommandBuilder;
 import org.chromium.chrome.browser.user_education.UserEducationHelper;
-import org.chromium.components.content_settings.ContentSettingsType;
 import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.components.permissions.PermissionDialogController;
@@ -47,14 +47,11 @@
 public class StatusCoordinator implements View.OnClickListener, LocationBarDataProvider.Observer {
     /** Interface for displaying page info popup on omnibox. */
     public interface PageInfoAction {
-        // TODO(crbug.com/1257656): Create a class to pass highlight info instead of adding more
-        // parameters.
         /**
          * @param tab Tab containing the content to show page info for.
-         * @param highlightedPermission The ContentSettingsType to be highlighted on the page.
-         * @param fromStoreIcon Whether user enters page info via the store icon in omnibox.
+         * @param pageInfoHighlight Providing the highlight row info related to this dialog.
          */
-        void show(Tab tab, @ContentSettingsType int highlightedPermission, boolean fromStoreIcon);
+        void show(Tab tab, ChromePageInfoHighlight pageInfoHighlight);
     }
 
     // TODO(crbug.com/1109369): Do not store the StatusView
@@ -299,8 +296,7 @@
             return;
         }
 
-        mPageInfoAction.show(mLocationBarDataProvider.getTab(), mMediator.getLastPermission(),
-                mMediator.isStoreIconShowing());
+        mPageInfoAction.show(mLocationBarDataProvider.getTab(), mMediator.getPageInfoHighlight());
         mMediator.onPageInfoOpened();
     }
 
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java
index 45be116..00d4a8e 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java
@@ -29,6 +29,7 @@
 import org.chromium.chrome.browser.omnibox.status.StatusProperties.PermissionIconResource;
 import org.chromium.chrome.browser.omnibox.status.StatusProperties.StatusIconResource;
 import org.chromium.chrome.browser.omnibox.status.StatusView.IconTransitionType;
+import org.chromium.chrome.browser.page_info.ChromePageInfoHighlight;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.theme.ThemeUtils;
 import org.chromium.components.browser_ui.site_settings.ContentSettingsResources;
@@ -36,6 +37,7 @@
 import org.chromium.components.content_settings.ContentSettingValues;
 import org.chromium.components.content_settings.ContentSettingsType;
 import org.chromium.components.embedder_support.util.UrlUtilities;
+import org.chromium.components.page_info.PageInfoController;
 import org.chromium.components.page_info.PageInfoDiscoverabilityMetrics;
 import org.chromium.components.page_info.PageInfoDiscoverabilityMetrics.DiscoverabilityAction;
 import org.chromium.components.permissions.PermissionDialogController;
@@ -734,6 +736,20 @@
         return mIsStoreIconShowing;
     }
 
+    /**
+     * @return {@link ChromePageInfoHighlight} which provides the PageInfo highlight row info when
+     *         user clicks the omnibox icon.
+     */
+    ChromePageInfoHighlight getPageInfoHighlight() {
+        if (mLastPermission != PageInfoController.NO_HIGHLIGHTED_PERMISSION) {
+            return ChromePageInfoHighlight.forPermission(mLastPermission);
+        } else if (mIsStoreIconShowing) {
+            return ChromePageInfoHighlight.forStoreInfo(true);
+        } else {
+            return ChromePageInfoHighlight.noHighlight();
+        }
+    }
+
     @Override
     public void onTemplateURLServiceChanged() {
         updateLocationBarIcon(IconTransitionType.CROSSFADE);
diff --git a/chrome/browser/ui/android/passwords/password_generation_editing_popup_view_android.h b/chrome/browser/ui/android/passwords/password_generation_editing_popup_view_android.h
index dc63ace..d61e728 100644
--- a/chrome/browser/ui/android/passwords/password_generation_editing_popup_view_android.h
+++ b/chrome/browser/ui/android/passwords/password_generation_editing_popup_view_android.h
@@ -8,7 +8,6 @@
 #include <jni.h>
 
 #include "base/android/scoped_java_ref.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/passwords/password_generation_popup_view.h"
 #include "ui/android/view_android.h"
 
diff --git a/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.h b/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.h
index 676b400..e54372b3 100644
--- a/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.h
+++ b/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_ANDROID_TAB_CONTENTS_CHROME_WEB_CONTENTS_VIEW_DELEGATE_ANDROID_H_
 #define CHROME_BROWSER_UI_ANDROID_TAB_CONTENTS_CHROME_WEB_CONTENTS_VIEW_DELEGATE_ANDROID_H_
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/web_contents_view_delegate.h"
 
 namespace content {
diff --git a/chrome/browser/ui/android/tab_model/android_live_tab_context.h b/chrome/browser/ui/android/tab_model/android_live_tab_context.h
index 0562d88..5b62ab73 100644
--- a/chrome/browser/ui/android/tab_model/android_live_tab_context.h
+++ b/chrome/browser/ui/android/tab_model/android_live_tab_context.h
@@ -9,7 +9,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "components/sessions/core/live_tab_context.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
diff --git a/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.h b/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.h
index 8648580..8301273 100644
--- a/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.h
+++ b/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.h
@@ -10,7 +10,6 @@
 
 #include "base/android/jni_weak_ref.h"
 #include "base/android/scoped_java_ref.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/flags/android/chrome_session_state.h"
 #include "chrome/browser/ui/android/tab_model/tab_model.h"
 
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
index be5de17..eff96a6 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -29,8 +29,6 @@
 import org.chromium.base.TraceEvent;
 import org.chromium.base.supplier.BooleanSupplier;
 import org.chromium.base.supplier.ObservableSupplier;
-import org.chromium.chrome.browser.flags.CachedFeatureFlags;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.omnibox.LocationBar;
 import org.chromium.chrome.browser.omnibox.LocationBarCoordinator;
 import org.chromium.chrome.browser.omnibox.NewTabPageDelegate;
@@ -850,9 +848,6 @@
      * @param toolbarColor The toolbar color to base the hairline color on.
      */
     protected void setToolbarHairlineColor(@ColorInt int toolbarColor) {
-        // The refactor replaces the shadow with a hairline.
-        if (!CachedFeatureFlags.isEnabled(ChromeFeatureList.THEME_REFACTOR_ANDROID)) return;
-
         final ImageView shadow = getRootView().findViewById(R.id.toolbar_shadow);
         final int hairlineColor =
                 ThemeUtils.getToolbarHairlineColor(getContext(), toolbarColor, isIncognito());
diff --git a/chrome/browser/ui/app_list/app_sync_ui_state.h b/chrome/browser/ui/app_list/app_sync_ui_state.h
index 8be7afd..4c814ef 100644
--- a/chrome/browser/ui/app_list/app_sync_ui_state.h
+++ b/chrome/browser/ui/app_list/app_sync_ui_state.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_APP_LIST_APP_SYNC_UI_STATE_H_
 #define CHROME_BROWSER_UI_APP_LIST_APP_SYNC_UI_STATE_H_
 
-#include "base/compiler_specific.h"
 #include "base/observer_list.h"
 #include "base/timer/timer.h"
 #include "components/keyed_service/core/keyed_service.h"
diff --git a/chrome/browser/ui/app_list/app_sync_ui_state_factory.h b/chrome/browser/ui/app_list/app_sync_ui_state_factory.h
index 56019a6..71e19b8b 100644
--- a/chrome/browser/ui/app_list/app_sync_ui_state_factory.h
+++ b/chrome/browser/ui/app_list/app_sync_ui_state_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_APP_LIST_APP_SYNC_UI_STATE_FACTORY_H_
 #define CHROME_BROWSER_UI_APP_LIST_APP_SYNC_UI_STATE_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/ui/app_list/app_sync_ui_state_watcher.h b/chrome/browser/ui/app_list/app_sync_ui_state_watcher.h
index 2e55204..779b5b38 100644
--- a/chrome/browser/ui/app_list/app_sync_ui_state_watcher.h
+++ b/chrome/browser/ui/app_list/app_sync_ui_state_watcher.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_APP_LIST_APP_SYNC_UI_STATE_WATCHER_H_
 #define CHROME_BROWSER_UI_APP_LIST_APP_SYNC_UI_STATE_WATCHER_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/app_list/app_sync_ui_state_observer.h"
 
 class AppListModelUpdater;
diff --git a/chrome/browser/ui/app_list/arc/arc_app_test.cc b/chrome/browser/ui/app_list/arc/arc_app_test.cc
index 01fe4071..f8d4104 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_test.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_test.cc
@@ -9,7 +9,6 @@
 #include "ash/components/arc/test/connection_holder_util.h"
 #include "ash/components/arc/test/fake_app_instance.h"
 #include "ash/components/arc/test/fake_arc_session.h"
-#include "ash/components/arc/test/fake_intent_helper_instance.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/containers/cxx20_erase.h"
@@ -32,6 +31,7 @@
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/session/arc_service_manager.h"
 #include "components/arc/session/arc_session_runner.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
index 8227674a..2f224939 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -17,7 +17,6 @@
 #include "ash/components/arc/metrics/arc_metrics_constants.h"
 #include "ash/components/arc/test/arc_util_test_support.h"
 #include "ash/components/arc/test/fake_app_instance.h"
-#include "ash/components/arc/test/fake_intent_helper_instance.h"
 #include "ash/constants/ash_switches.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/shelf_model.h"
@@ -79,6 +78,7 @@
 #include "components/arc/mojom/app.mojom.h"
 #include "components/arc/mojom/compatibility_mode.mojom.h"
 #include "components/arc/session/arc_service_manager.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
 #include "components/services/app_service/public/cpp/app_registry_cache.h"
 #include "components/services/app_service/public/cpp/app_types.h"
 #include "components/services/app_service/public/cpp/app_update.h"
diff --git a/chrome/browser/ui/apps/chrome_app_window_client.h b/chrome/browser/ui/apps/chrome_app_window_client.h
index 24c4f7e..284869d0 100644
--- a/chrome/browser/ui/apps/chrome_app_window_client.h
+++ b/chrome/browser/ui/apps/chrome_app_window_client.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_APPS_CHROME_APP_WINDOW_CLIENT_H_
 #define CHROME_BROWSER_UI_APPS_CHROME_APP_WINDOW_CLIENT_H_
 
-#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "extensions/browser/app_window/app_window_client.h"
 
diff --git a/chrome/browser/ui/ash/chrome_desks_templates_delegate.cc b/chrome/browser/ui/ash/chrome_desks_templates_delegate.cc
index 02411aa..c016ec4 100644
--- a/chrome/browser/ui/ash/chrome_desks_templates_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_desks_templates_delegate.cc
@@ -19,6 +19,8 @@
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/common/chrome_features.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/theme_resources.h"
 #include "components/app_restore/app_launch_info.h"
 #include "components/app_restore/app_restore_data.h"
 #include "components/app_restore/full_restore_save_handler.h"
@@ -33,6 +35,8 @@
 #include "extensions/common/constants.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image_skia.h"
 #include "url/gurl.h"
 
 namespace {
@@ -136,6 +140,17 @@
   return DesksClient::Get()->GetDeskModel();
 }
 
+absl::optional<gfx::ImageSkia>
+ChromeDesksTemplatesDelegate::MaybeRetrieveChromeIconForNTPUrl(
+    const std::string& page_url) const {
+  if (page_url != chrome::kChromeUINewTabURL)
+    return absl::nullopt;
+
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  return absl::make_optional<gfx::ImageSkia>(
+      rb.GetImageNamed(IDR_PRODUCT_LOGO_32).AsImageSkia());
+}
+
 void ChromeDesksTemplatesDelegate::GetFaviconForUrl(
     const std::string& page_url,
     int desired_icon_size,
@@ -184,36 +199,7 @@
 // Returns true if `window` is supported in desk templates feature.
 bool ChromeDesksTemplatesDelegate::IsWindowSupportedForDeskTemplate(
     aura::Window* window) const {
-  // For now we'll crostini and lacros windows in desk template. We'll also
-  // ignore ARC apps unless the flag is turned on.
-  const ash::AppType app_type =
-      static_cast<ash::AppType>(window->GetProperty(aura::client::kAppType));
-  switch (app_type) {
-    case ash::AppType::NON_APP:
-    case ash::AppType::CROSTINI_APP:
-    case ash::AppType::LACROS:
-      return false;
-    case ash::AppType::ARC_APP:
-      if (!ash::features::AreDesksTemplatesEnabled())
-        return false;
-      break;
-    case ash::AppType::BROWSER:
-    case ash::AppType::CHROME_APP:
-    case ash::AppType::SYSTEM_APP:
-      break;
-  }
-
-  const user_manager::User* active_user =
-      user_manager::UserManager::Get()->GetActiveUser();
-  DCHECK(active_user);
-  Profile* user_profile =
-      ash::ProfileHelper::Get()->GetProfileByUser(active_user);
-  if (!user_profile)
-    return false;
-
-  // Exclude window that does not asscociate with a full restore app id.
-  const std::string app_id = full_restore::GetAppId(window);
-  if (app_id.empty())
+  if (!ash::DeskTemplate::IsAppTypeSupported(window))
     return false;
 
   // Exclude incognito browser window.
diff --git a/chrome/browser/ui/ash/chrome_desks_templates_delegate.h b/chrome/browser/ui/ash/chrome_desks_templates_delegate.h
index a0350c6..78e1325 100644
--- a/chrome/browser/ui/ash/chrome_desks_templates_delegate.h
+++ b/chrome/browser/ui/ash/chrome_desks_templates_delegate.h
@@ -28,6 +28,8 @@
   std::unique_ptr<app_restore::AppLaunchInfo> GetAppLaunchDataForDeskTemplate(
       aura::Window* window) const override;
   desks_storage::DeskModel* GetDeskModel() override;
+  absl::optional<gfx::ImageSkia> MaybeRetrieveChromeIconForNTPUrl(
+      const std::string& page_url) const override;
   void GetFaviconForUrl(const std::string& page_url,
                         int desired_icon_size,
                         favicon_base::FaviconRawBitmapCallback callback,
diff --git a/chrome/browser/ui/ash/network/network_state_notifier.h b/chrome/browser/ui/ash/network/network_state_notifier.h
index e467394..11157a7 100644
--- a/chrome/browser/ui/ash/network/network_state_notifier.h
+++ b/chrome/browser/ui/ash/network/network_state_notifier.h
@@ -10,7 +10,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "base/values.h"
diff --git a/chrome/browser/ui/ash/quick_answers/quick_answers_browser_client_impl.h b/chrome/browser/ui/ash/quick_answers/quick_answers_browser_client_impl.h
index fa1dbff..4b57f37 100644
--- a/chrome/browser/ui/ash/quick_answers/quick_answers_browser_client_impl.h
+++ b/chrome/browser/ui/ash/quick_answers/quick_answers_browser_client_impl.h
@@ -8,10 +8,10 @@
 #include <string>
 #include <vector>
 
-#include "ash/public/cpp/quick_answers/controller/quick_answers_browser_client.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "chromeos/components/quick_answers/public/cpp/controller/quick_answers_browser_client.h"
 
 class GoogleServiceAuthError;
 
diff --git a/chrome/browser/ui/ash/quick_answers/quick_answers_controller_impl.cc b/chrome/browser/ui/ash/quick_answers/quick_answers_controller_impl.cc
index 48b6a6f..049baef 100644
--- a/chrome/browser/ui/ash/quick_answers/quick_answers_controller_impl.cc
+++ b/chrome/browser/ui/ash/quick_answers/quick_answers_controller_impl.cc
@@ -6,13 +6,13 @@
 
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/new_window_delegate.h"
-#include "ash/public/cpp/quick_answers/quick_answers_state.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/ui/ash/quick_answers/quick_answers_ui_controller.h"
 #include "chromeos/components/quick_answers/public/cpp/quick_answers_prefs.h"
+#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h"
 #include "components/prefs/pref_service.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/ui/ash/quick_answers/quick_answers_controller_impl.h b/chrome/browser/ui/ash/quick_answers/quick_answers_controller_impl.h
index 94ca2d9..84f98d1 100644
--- a/chrome/browser/ui/ash/quick_answers/quick_answers_controller_impl.h
+++ b/chrome/browser/ui/ash/quick_answers/quick_answers_controller_impl.h
@@ -8,8 +8,8 @@
 #include <memory>
 #include <string>
 
-#include "ash/public/cpp/quick_answers/controller/quick_answers_controller.h"
 #include "chrome/browser/ui/ash/quick_answers/quick_answers_state_controller.h"
+#include "chromeos/components/quick_answers/public/cpp/controller/quick_answers_controller.h"
 #include "chromeos/components/quick_answers/quick_answers_client.h"
 #include "chromeos/components/quick_answers/quick_answers_model.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/chrome/browser/ui/ash/quick_answers/quick_answers_controller_unittest.cc b/chrome/browser/ui/ash/quick_answers/quick_answers_controller_unittest.cc
index a067ece..628a713 100644
--- a/chrome/browser/ui/ash/quick_answers/quick_answers_controller_unittest.cc
+++ b/chrome/browser/ui/ash/quick_answers/quick_answers_controller_unittest.cc
@@ -4,12 +4,12 @@
 
 #include "chrome/browser/ui/ash/quick_answers/quick_answers_controller_impl.h"
 
-#include "ash/public/cpp/quick_answers/quick_answers_state.h"
 #include "base/memory/scoped_refptr.h"
 #include "chrome/browser/ui/ash/quick_answers/quick_answers_ui_controller.h"
 #include "chrome/browser/ui/ash/quick_answers/test/chrome_quick_answers_test_base.h"
 #include "chrome/browser/ui/ash/quick_answers/ui/quick_answers_view.h"
 #include "chrome/browser/ui/ash/quick_answers/ui/user_consent_view.h"
+#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h"
 #include "chromeos/components/quick_answers/quick_answers_client.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
diff --git a/chrome/browser/ui/ash/quick_answers/quick_answers_state_controller.cc b/chrome/browser/ui/ash/quick_answers/quick_answers_state_controller.cc
index 4ee45ec..48bc50c 100644
--- a/chrome/browser/ui/ash/quick_answers/quick_answers_state_controller.cc
+++ b/chrome/browser/ui/ash/quick_answers/quick_answers_state_controller.cc
@@ -4,19 +4,61 @@
 
 #include "chrome/browser/ui/ash/quick_answers/quick_answers_state_controller.h"
 
+#include "ash/public/cpp/assistant/assistant_state.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
+#include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
+#include "components/prefs/pref_service.h"
 
 namespace ash {
 
+namespace {
+
+using chromeos::assistant::prefs::kAssistantContextEnabled;
+using chromeos::assistant::prefs::kAssistantEnabled;
+using quick_answers::prefs::ConsentStatus;
+using quick_answers::prefs::kQuickAnswersConsentStatus;
+using quick_answers::prefs::kQuickAnswersEnabled;
+using quick_answers::prefs::kQuickAnswersNoticeImpressionCount;
+
+void MigrateQuickAnswersConsentStatus(PrefService* prefs) {
+  // If the consented status has not been set, migrate the current context
+  // enabled value.
+  if (prefs->FindPreference(kQuickAnswersConsentStatus)->IsDefaultValue()) {
+    if (!prefs->FindPreference(kAssistantContextEnabled)->IsDefaultValue()) {
+      // Set the consent status based on current feature eligibility.
+      bool consented =
+          ash::AssistantState::Get()->allowed_state() ==
+              chromeos::assistant::AssistantAllowedState::ALLOWED &&
+          prefs->GetBoolean(kAssistantEnabled) &&
+          prefs->GetBoolean(kAssistantContextEnabled);
+      prefs->SetInteger(
+          kQuickAnswersConsentStatus,
+          consented ? ConsentStatus::kAccepted : ConsentStatus::kRejected);
+      // Enable Quick Answers settings for existing users.
+      if (consented)
+        prefs->SetBoolean(kQuickAnswersEnabled, true);
+    } else {
+      // Set the consent status to unknown for new users.
+      prefs->SetInteger(kQuickAnswersConsentStatus, ConsentStatus::kUnknown);
+      // Reset the impression count for new users.
+      prefs->SetInteger(kQuickAnswersNoticeImpressionCount, 0);
+    }
+  }
+}
+
+}  // namespace
+
 QuickAnswersStateController::QuickAnswersStateController()
     : session_observer_(this) {}
 
 QuickAnswersStateController::~QuickAnswersStateController() = default;
 
 void QuickAnswersStateController::OnFirstSessionStarted() {
-  state_.RegisterPrefChanges(
-      Shell::Get()->session_controller()->GetPrimaryUserPrefService());
+  PrefService* prefs =
+      Shell::Get()->session_controller()->GetPrimaryUserPrefService();
+  state_.RegisterPrefChanges(prefs);
+  MigrateQuickAnswersConsentStatus(prefs);
 }
 
 }  // namespace ash
diff --git a/chrome/browser/ui/ash/quick_answers/quick_answers_state_controller.h b/chrome/browser/ui/ash/quick_answers/quick_answers_state_controller.h
index 0b5ed079..e158589 100644
--- a/chrome/browser/ui/ash/quick_answers/quick_answers_state_controller.h
+++ b/chrome/browser/ui/ash/quick_answers/quick_answers_state_controller.h
@@ -5,8 +5,8 @@
 #ifndef CHROME_BROWSER_UI_ASH_QUICK_ANSWERS_QUICK_ANSWERS_STATE_CONTROLLER_H_
 #define CHROME_BROWSER_UI_ASH_QUICK_ANSWERS_QUICK_ANSWERS_STATE_CONTROLLER_H_
 
-#include "ash/public/cpp/quick_answers/quick_answers_state.h"
 #include "ash/public/cpp/session/session_observer.h"
+#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h"
 
 namespace ash {
 
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_instance_registry_helper.cc b/chrome/browser/ui/ash/shelf/app_service/app_service_instance_registry_helper.cc
index 61edd10..34ee58c8 100644
--- a/chrome/browser/ui/ash/shelf/app_service/app_service_instance_registry_helper.cc
+++ b/chrome/browser/ui/ash/shelf/app_service/app_service_instance_registry_helper.cc
@@ -191,6 +191,9 @@
   instance->SetLaunchId(launch_id);
   instance->UpdateState(state, base::Time::Now());
 
+  std::vector<std::unique_ptr<apps::Instance>> deltas;
+  deltas.push_back(std::move(instance));
+
   // The window could be teleported from the inactive user's profile to the
   // current active user, so search all proxies. If the instance is found from a
   // proxy, still save to that proxy, otherwise, save to the current active user
@@ -204,7 +207,7 @@
       break;
     }
   }
-  proxy->InstanceRegistry().OnInstance(std::move(instance));
+  proxy->InstanceRegistry().OnInstances(std::move(deltas));
 }
 
 void AppServiceInstanceRegistryHelper::OnSetShelfIDForBrowserWindowContents(
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller.h b/chrome/browser/ui/autofill/autofill_popup_controller.h
index 9fe8755..a5310e9 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller.h
+++ b/chrome/browser/ui/autofill/autofill_popup_controller.h
@@ -10,7 +10,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/autofill/autofill_popup_view_delegate.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index 1d6281e7..22767be4 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/i18n/rtl.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h
index 4b2b2985..5670e27 100644
--- a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h
+++ b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_BUBBLE_SIGN_IN_DELEGATE_H_
 #define CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_BUBBLE_SIGN_IN_DELEGATE_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/sync/bubble_sync_promo_delegate.h"
 
diff --git a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h
index 4ef99c3a..b8d5e15 100644
--- a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h
+++ b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h
@@ -7,7 +7,6 @@
 
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/observer_list.h"
 #include "components/bookmarks/browser/bookmark_model_observer.h"
 #include "ui/base/models/combobox_model.h"
diff --git a/chrome/browser/ui/browser_content_setting_bubble_model_delegate.h b/chrome/browser/ui/browser_content_setting_bubble_model_delegate.h
index 115589c..81e8ec5 100644
--- a/chrome/browser/ui/browser_content_setting_bubble_model_delegate.h
+++ b/chrome/browser/ui/browser_content_setting_bubble_model_delegate.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_BROWSER_CONTENT_SETTING_BUBBLE_MODEL_DELEGATE_H_
 #define CHROME_BROWSER_UI_BROWSER_CONTENT_SETTING_BUBBLE_MODEL_DELEGATE_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h"
 
 class Browser;
diff --git a/chrome/browser/ui/browser_instant_controller.h b/chrome/browser/ui/browser_instant_controller.h
index 04c1d55..a7375dfc5 100644
--- a/chrome/browser/ui/browser_instant_controller.h
+++ b/chrome/browser/ui/browser_instant_controller.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "chrome/browser/search/search_engine_base_url_tracker.h"
 #include "chrome/browser/ui/search/instant_controller.h"
diff --git a/chrome/browser/ui/browser_live_tab_context.h b/chrome/browser/ui/browser_live_tab_context.h
index 80b77a37..af211d93 100644
--- a/chrome/browser/ui/browser_live_tab_context.h
+++ b/chrome/browser/ui/browser_live_tab_context.h
@@ -9,7 +9,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "components/sessions/core/live_tab_context.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
diff --git a/chrome/browser/ui/browser_location_bar_model_delegate.h b/chrome/browser/ui/browser_location_bar_model_delegate.h
index 2681a525..6cb9996 100644
--- a/chrome/browser/ui/browser_location_bar_model_delegate.h
+++ b/chrome/browser/ui/browser_location_bar_model_delegate.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_BROWSER_LOCATION_BAR_MODEL_DELEGATE_H_
 #define CHROME_BROWSER_UI_BROWSER_LOCATION_BAR_MODEL_DELEGATE_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h"
 
 class Browser;
diff --git a/chrome/browser/ui/browser_tab_strip_model_delegate.h b/chrome/browser/ui/browser_tab_strip_model_delegate.h
index 8ab37de8..ae8c25b 100644
--- a/chrome/browser/ui/browser_tab_strip_model_delegate.h
+++ b/chrome/browser/ui/browser_tab_strip_model_delegate.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_BROWSER_TAB_STRIP_MODEL_DELEGATE_H_
 #define CHROME_BROWSER_UI_BROWSER_TAB_STRIP_MODEL_DELEGATE_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
 
diff --git a/chrome/browser/ui/chrome_select_file_policy.h b/chrome/browser/ui/chrome_select_file_policy.h
index 29b1751..cce49a8 100644
--- a/chrome/browser/ui/chrome_select_file_policy.h
+++ b/chrome/browser/ui/chrome_select_file_policy.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_CHROME_SELECT_FILE_POLICY_H_
 #define CHROME_BROWSER_UI_CHROME_SELECT_FILE_POLICY_H_
 
-#include "base/compiler_specific.h"
 #include "ui/shell_dialogs/select_file_policy.h"
 
 namespace content {
diff --git a/chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h b/chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h
index d40e83e..d536a65 100644
--- a/chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h
+++ b/chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_CHROME_WEB_MODAL_DIALOG_MANAGER_DELEGATE_H_
 #define CHROME_BROWSER_UI_CHROME_WEB_MODAL_DIALOG_MANAGER_DELEGATE_H_
 
-#include "base/compiler_specific.h"
 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
 
 class ChromeWebModalDialogManagerDelegate
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
index a9ce117..65ca089b 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
@@ -9,7 +9,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/status_icons/desktop_notification_balloon.h"
diff --git a/chrome/browser/ui/cocoa/status_icons/status_tray_mac.h b/chrome/browser/ui/cocoa/status_icons/status_tray_mac.h
index c45c219..7d1951a 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_tray_mac.h
+++ b/chrome/browser/ui/cocoa/status_icons/status_tray_mac.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_COCOA_STATUS_ICONS_STATUS_TRAY_MAC_H_
 #define CHROME_BROWSER_UI_COCOA_STATUS_ICONS_STATUS_TRAY_MAC_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/status_icons/status_tray.h"
 
 class StatusTrayMac : public StatusTray {
diff --git a/chrome/browser/ui/cocoa/tab_contents/web_drag_bookmark_handler_mac.h b/chrome/browser/ui/cocoa/tab_contents/web_drag_bookmark_handler_mac.h
index d357e20a..bf23bb4 100644
--- a/chrome/browser/ui/cocoa/tab_contents/web_drag_bookmark_handler_mac.h
+++ b/chrome/browser/ui/cocoa/tab_contents/web_drag_bookmark_handler_mac.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_WEB_DRAG_BOOKMARK_HANDLER_MAC_H_
 #define CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_WEB_DRAG_BOOKMARK_HANDLER_MAC_H_
 
-#include "base/compiler_specific.h"
 #include "components/bookmarks/browser/bookmark_node_data.h"
 #include "content/public/browser/web_drag_dest_delegate.h"
 
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.h b/chrome/browser/ui/content_settings/content_setting_bubble_model.h
index 7834c70f..5ac7eb9 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.h
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.h
@@ -12,7 +12,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/scoped_observation.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.h b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.h
index 6d326d1..b9ce093 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.h
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <sstream>
 
-#include "base/compiler_specific.h"
 #include "build/build_config.h"
 
 class Browser;
diff --git a/chrome/browser/ui/extensions/extension_enable_flow.h b/chrome/browser/ui/extensions/extension_enable_flow.h
index dc336d81..eacd8e2 100644
--- a/chrome/browser/ui/extensions/extension_enable_flow.h
+++ b/chrome/browser/ui/extensions/extension_enable_flow.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
diff --git a/chrome/browser/ui/extensions/extension_install_ui_default.h b/chrome/browser/ui/extensions/extension_install_ui_default.h
index f8abf78..b984be9 100644
--- a/chrome/browser/ui/extensions/extension_install_ui_default.h
+++ b/chrome/browser/ui/extensions/extension_install_ui_default.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_INSTALL_UI_DEFAULT_H_
 #define CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_INSTALL_UI_DEFAULT_H_
 
-#include "base/compiler_specific.h"
 #include "extensions/browser/install/extension_install_ui.h"
 
 namespace content {
diff --git a/chrome/browser/ui/global_error/global_error_service_factory.h b/chrome/browser/ui/global_error/global_error_service_factory.h
index bb00f4c..3d76abe 100644
--- a/chrome/browser/ui/global_error/global_error_service_factory.h
+++ b/chrome/browser/ui/global_error/global_error_service_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_GLOBAL_ERROR_GLOBAL_ERROR_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_UI_GLOBAL_ERROR_GLOBAL_ERROR_SERVICE_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.h b/chrome/browser/ui/omnibox/chrome_omnibox_client.h
index a690ff0..bcaaae8 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.h
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
diff --git a/chrome/browser/ui/passwords/bubble_controllers/OWNERS b/chrome/browser/ui/passwords/bubble_controllers/OWNERS
new file mode 100644
index 0000000..00a22ca
--- /dev/null
+++ b/chrome/browser/ui/passwords/bubble_controllers/OWNERS
@@ -0,0 +1 @@
+mamir@chromium.org
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper.h b/chrome/browser/ui/prefs/prefs_tab_helper.h
index 0d135c4e..33c43ed8 100644
--- a/chrome/browser/ui/prefs/prefs_tab_helper.h
+++ b/chrome/browser/ui/prefs/prefs_tab_helper.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_PREFS_PREFS_TAB_HELPER_H_
 #define CHROME_BROWSER_UI_PREFS_PREFS_TAB_HELPER_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
 #include "chrome/browser/font_pref_change_notifier.h"
diff --git a/chrome/browser/ui/sad_tab_helper.h b/chrome/browser/ui/sad_tab_helper.h
index a90c899c..041d435 100644
--- a/chrome/browser/ui/sad_tab_helper.h
+++ b/chrome/browser/ui/sad_tab_helper.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
diff --git a/chrome/browser/ui/search_engines/template_url_table_model.h b/chrome/browser/ui/search_engines/template_url_table_model.h
index 6a4fe3ed..9004706 100644
--- a/chrome/browser/ui/search_engines/template_url_table_model.h
+++ b/chrome/browser/ui/search_engines/template_url_table_model.h
@@ -9,7 +9,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "components/search_engines/template_url_service_observer.h"
 #include "ui/base/models/table_model.h"
 
diff --git a/chrome/browser/ui/simple_message_box.h b/chrome/browser/ui/simple_message_box.h
index 34b1e1a..2f9c9bb 100644
--- a/chrome/browser/ui/simple_message_box.h
+++ b/chrome/browser/ui/simple_message_box.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/callback_forward.h"
-#include "base/compiler_specific.h"
 #include "ui/gfx/native_widget_types.h"
 
 namespace chrome {
diff --git a/chrome/browser/ui/startup/automation_infobar_delegate.h b/chrome/browser/ui/startup/automation_infobar_delegate.h
index 8f0962d..f5c6979 100644
--- a/chrome/browser/ui/startup/automation_infobar_delegate.h
+++ b/chrome/browser/ui/startup/automation_infobar_delegate.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/ui/sync/browser_synced_window_delegate.h b/chrome/browser/ui/sync/browser_synced_window_delegate.h
index 7c649997..256564a 100644
--- a/chrome/browser/ui/sync/browser_synced_window_delegate.h
+++ b/chrome/browser/ui/sync/browser_synced_window_delegate.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_SYNC_BROWSER_SYNCED_WINDOW_DELEGATE_H_
 #define CHROME_BROWSER_UI_SYNC_BROWSER_SYNCED_WINDOW_DELEGATE_H_
 
-#include "base/compiler_specific.h"
 #include "components/sessions/core/session_id.h"
 #include "components/sync_sessions/synced_window_delegate.h"
 
diff --git a/chrome/browser/ui/sync/one_click_signin_links_delegate_impl.h b/chrome/browser/ui/sync/one_click_signin_links_delegate_impl.h
index 7062b64..d1cde35 100644
--- a/chrome/browser/ui/sync/one_click_signin_links_delegate_impl.h
+++ b/chrome/browser/ui/sync/one_click_signin_links_delegate_impl.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_SYNC_ONE_CLICK_SIGNIN_LINKS_DELEGATE_IMPL_H_
 #define CHROME_BROWSER_UI_SYNC_ONE_CLICK_SIGNIN_LINKS_DELEGATE_IMPL_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/sync/one_click_signin_links_delegate.h"
 
 class Browser;
diff --git a/chrome/browser/ui/tab_modal_confirm_dialog_browsertest.h b/chrome/browser/ui/tab_modal_confirm_dialog_browsertest.h
index bc263b6..6258ca3 100644
--- a/chrome/browser/ui/tab_modal_confirm_dialog_browsertest.h
+++ b/chrome/browser/ui/tab_modal_confirm_dialog_browsertest.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_TAB_MODAL_CONFIRM_DIALOG_BROWSERTEST_H_
 #define CHROME_BROWSER_UI_TAB_MODAL_CONFIRM_DIALOG_BROWSERTEST_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
 #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/ui/tab_modal_confirm_dialog_delegate.h b/chrome/browser/ui/tab_modal_confirm_dialog_delegate.h
index 251cf86..f520cc3 100644
--- a/chrome/browser/ui/tab_modal_confirm_dialog_delegate.h
+++ b/chrome/browser/ui/tab_modal_confirm_dialog_delegate.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/window_open_disposition.h"
diff --git a/chrome/browser/ui/tabs/pinned_tab_service_factory.h b/chrome/browser/ui/tabs/pinned_tab_service_factory.h
index 088bc39..74423a3 100644
--- a/chrome/browser/ui/tabs/pinned_tab_service_factory.h
+++ b/chrome/browser/ui/tabs/pinned_tab_service_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_TABS_PINNED_TAB_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_UI_TABS_PINNED_TAB_SERVICE_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
diff --git a/chrome/browser/ui/tabs/test_tab_strip_model_delegate.h b/chrome/browser/ui/tabs/test_tab_strip_model_delegate.h
index 6ac6266..1dcca589 100644
--- a/chrome/browser/ui/tabs/test_tab_strip_model_delegate.h
+++ b/chrome/browser/ui/tabs/test_tab_strip_model_delegate.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_TABS_TEST_TAB_STRIP_MODEL_DELEGATE_H_
 #define CHROME_BROWSER_UI_TABS_TEST_TAB_STRIP_MODEL_DELEGATE_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chrome/browser/ui/test/test_confirm_bubble_model.h b/chrome/browser/ui/test/test_confirm_bubble_model.h
index dc71ab5..c0dabf71 100644
--- a/chrome/browser/ui/test/test_confirm_bubble_model.h
+++ b/chrome/browser/ui/test/test_confirm_bubble_model.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_TEST_TEST_CONFIRM_BUBBLE_MODEL_H_
 #define CHROME_BROWSER_UI_TEST_TEST_CONFIRM_BUBBLE_MODEL_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/confirm_bubble_model.h"
 
 // A test version of the model for confirmation bubbles.
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.h b/chrome/browser/ui/toolbar/toolbar_actions_model.h
index e09ba4e..c246768 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model.h
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.h
@@ -8,7 +8,6 @@
 #include <stddef.h>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/containers/flat_set.h"
 #include "base/observer_list.h"
 #include "base/scoped_observation.h"
diff --git a/chrome/browser/ui/translate/source_language_combobox_model.h b/chrome/browser/ui/translate/source_language_combobox_model.h
index 9727d50..a939c85 100644
--- a/chrome/browser/ui/translate/source_language_combobox_model.h
+++ b/chrome/browser/ui/translate/source_language_combobox_model.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/combobox_model.h"
 
diff --git a/chrome/browser/ui/translate/target_language_combobox_model.h b/chrome/browser/ui/translate/target_language_combobox_model.h
index 0c0b088..947d9cea 100644
--- a/chrome/browser/ui/translate/target_language_combobox_model.h
+++ b/chrome/browser/ui/translate/target_language_combobox_model.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "ui/base/models/combobox_model.h"
 
 class TranslateBubbleModel;
diff --git a/chrome/browser/ui/user_education/tutorial/tutorial.cc b/chrome/browser/ui/user_education/tutorial/tutorial.cc
index 91e2fdb3..603484a5 100644
--- a/chrome/browser/ui/user_education/tutorial/tutorial.cc
+++ b/chrome/browser/ui/user_education/tutorial/tutorial.cc
@@ -94,6 +94,12 @@
   return *this;
 }
 
+Tutorial::StepBuilder& Tutorial::StepBuilder::SetTransitionOnlyOnEvent(
+    bool transition_only_on_event_) {
+  step_.transition_only_on_event = transition_only_on_event_;
+  return *this;
+}
+
 Tutorial::StepBuilder& Tutorial::StepBuilder::SetNameElementsCallback(
     TutorialDescription::NameElementsCallback name_elements_callback_) {
   step_.name_elements_callback = name_elements_callback_;
@@ -119,6 +125,9 @@
     interaction_sequence_step_builder->SetMustRemainVisible(
         step_.must_remain_visible.value());
 
+  interaction_sequence_step_builder->SetTransitionOnlyOnEvent(
+      step_.transition_only_on_event);
+
   interaction_sequence_step_builder->SetStartCallback(
       BuildStartCallback(tutorial_service, bubble_factory_registry));
   interaction_sequence_step_builder->SetEndCallback(
diff --git a/chrome/browser/ui/user_education/tutorial/tutorial.h b/chrome/browser/ui/user_education/tutorial/tutorial.h
index 238dc1f..25009bb 100644
--- a/chrome/browser/ui/user_education/tutorial/tutorial.h
+++ b/chrome/browser/ui/user_education/tutorial/tutorial.h
@@ -75,6 +75,7 @@
     StepBuilder& SetProgress(absl::optional<std::pair<int, int>> progress_);
     StepBuilder& SetIsLastStep(bool is_last_step_);
     StepBuilder& SetMustRemainVisible(bool must_remain_visible_);
+    StepBuilder& SetTransitionOnlyOnEvent(bool transition_only_on_event_);
     StepBuilder& SetNameElementsCallback(
         TutorialDescription::NameElementsCallback name_elements_callback_);
 
diff --git a/chrome/browser/ui/user_education/tutorial/tutorial_description.cc b/chrome/browser/ui/user_education/tutorial/tutorial_description.cc
index dd9e3a97..43a5f7d 100644
--- a/chrome/browser/ui/user_education/tutorial/tutorial_description.cc
+++ b/chrome/browser/ui/user_education/tutorial/tutorial_description.cc
@@ -25,6 +25,7 @@
     std::string element_name_,
     Arrow arrow_,
     absl::optional<bool> must_remain_visible_,
+    bool transition_only_on_event_,
     TutorialDescription::NameElementsCallback name_elements_callback_)
     : title_text(title_text_),
       body_text(body_text_),
@@ -33,6 +34,7 @@
       element_name(element_name_),
       arrow(arrow_),
       must_remain_visible(must_remain_visible_),
+      transition_only_on_event(transition_only_on_event_),
       name_elements_callback(name_elements_callback_) {}
 TutorialDescription::Step::Step(const TutorialDescription::Step& description) =
     default;
diff --git a/chrome/browser/ui/user_education/tutorial/tutorial_description.h b/chrome/browser/ui/user_education/tutorial/tutorial_description.h
index 4507ba7e..93d659f 100644
--- a/chrome/browser/ui/user_education/tutorial/tutorial_description.h
+++ b/chrome/browser/ui/user_education/tutorial/tutorial_description.h
@@ -43,6 +43,7 @@
          std::string element_name_,
          Arrow arrow_,
          absl::optional<bool> must_remain_visible_ = absl::nullopt,
+         bool transition_only_on_event_ = false,
          NameElementsCallback name_elements_callback_ = NameElementsCallback());
     Step(const Step& step);
     Step& operator=(const Step& step) = default;
@@ -73,6 +74,11 @@
     // InteractionSequence::StepBuilder
     absl::optional<bool> must_remain_visible;
 
+    // Should the step only be completed when an event like shown or hidden only
+    // happens during current step. for more information on the implementation
+    // take a look at transition_only_on_event in InteractionSequence::Step
+    bool transition_only_on_event = false;
+
     // lambda which is called on the start callback of the InteractionSequence
     // which provides the interaction sequence and the current element that
     // belongs to the step. The intention for this functionality is to name one
diff --git a/chrome/browser/ui/user_education/tutorial/tutorial_unittest.cc b/chrome/browser/ui/user_education/tutorial/tutorial_unittest.cc
index 8be2a5d..a086487 100644
--- a/chrome/browser/ui/user_education/tutorial/tutorial_unittest.cc
+++ b/chrome/browser/ui/user_education/tutorial/tutorial_unittest.cc
@@ -54,10 +54,18 @@
           .SetAnchorElementName(std::string(kTestElementName1))
           .Build(service.get(), bubble_factory_registry.get());
 
+  // transition event
+  std::unique_ptr<ui::InteractionSequence::Step> step4 =
+      Tutorial::StepBuilder()
+          .SetAnchorElementID(kTestIdentifier1)
+          .SetTransitionOnlyOnEvent(true)
+          .Build(service.get(), bubble_factory_registry.get());
+
   builder.SetContext(kTestContext1)
       .AddStep(std::move(step1))
       .AddStep(std::move(step2))
       .AddStep(std::move(step3))
+      .AddStep(std::move(step4))
       .Build();
 }
 
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_base_view.cc b/chrome/browser/ui/views/autofill/autofill_popup_base_view.cc
index 79baad9..7e75372 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_base_view.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_base_view.cc
@@ -347,7 +347,7 @@
 std::unique_ptr<views::Border> AutofillPopupBaseView::CreateBorder() {
   auto border = std::make_unique<views::BubbleBorder>(
       views::BubbleBorder::NONE, views::BubbleBorder::STANDARD_SHADOW,
-      SK_ColorWHITE);
+      GetBackgroundColor());
   border->SetCornerRadius(GetCornerRadius());
   border->set_md_shadow_elevation(
       ChromeLayoutProvider::Get()->GetShadowElevationMetric(
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h
index 0571a78..5d777aa 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h
@@ -9,7 +9,6 @@
 #include <set>
 
 #include "base/callback_forward.h"
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "chrome/browser/ui/bookmarks/bookmark_bar.h"
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_context_menu.h b/chrome/browser/ui/views/bookmarks/bookmark_context_menu.h
index 39a043c..9bb225d8 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_context_menu.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_context_menu.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_CONTEXT_MENU_H_
 
 #include "base/callback_forward.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/bookmarks/bookmark_context_menu_controller.h"
 #include "chrome/browser/ui/bookmarks/bookmark_stats.h"
 #include "ui/views/controls/menu/menu_delegate.h"
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.h b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.h
index 42d6b13..e9f851f 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.h
@@ -12,7 +12,6 @@
 #include <vector>
 
 #include "base/callback_forward.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/bookmarks/bookmark_editor.h"
 #include "components/bookmarks/browser/bookmark_expanded_state_tracker.h"
 #include "components/bookmarks/browser/bookmark_model_observer.h"
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.h b/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.h
index 5dfb302..01d3ff8 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.h
@@ -8,7 +8,6 @@
 #include <set>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "components/bookmarks/browser/base_bookmark_model_observer.h"
 #include "components/bookmarks/browser/bookmark_node_data.h"
 #include "ui/views/controls/menu/menu_delegate.h"
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h
index cd07b7f..babd52c 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h
@@ -9,7 +9,6 @@
 #include <set>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/bookmarks/bookmark_stats.h"
 #include "chrome/browser/ui/toolbar/app_menu_model.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_context_menu.h"
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h
index 4021bbd..8ce283d 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h"
 #include "ui/display/display_observer.h"
diff --git a/chrome/browser/ui/views/chrome_views_delegate.h b/chrome/browser/ui/views/chrome_views_delegate.h
index 3bb5650d..bfdc1a6 100644
--- a/chrome/browser/ui/views/chrome_views_delegate.h
+++ b/chrome/browser/ui/views/chrome_views_delegate.h
@@ -10,7 +10,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/location.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
diff --git a/chrome/browser/ui/views/collected_cookies_views.h b/chrome/browser/ui/views/collected_cookies_views.h
index abfc0466..6454ee88 100644
--- a/chrome/browser/ui/views/collected_cookies_views.h
+++ b/chrome/browser/ui/views/collected_cookies_views.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h"
diff --git a/chrome/browser/ui/views/confirm_bubble_views.h b/chrome/browser/ui/views/confirm_bubble_views.h
index 5e21cf9..cdb5e10 100644
--- a/chrome/browser/ui/views/confirm_bubble_views.h
+++ b/chrome/browser/ui/views/confirm_bubble_views.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/window/dialog_delegate.h"
 
diff --git a/chrome/browser/ui/views/content_setting_bubble_contents.cc b/chrome/browser/ui/views/content_setting_bubble_contents.cc
index 103ba6c..9c5dec86 100644
--- a/chrome/browser/ui/views/content_setting_bubble_contents.cc
+++ b/chrome/browser/ui/views/content_setting_bubble_contents.cc
@@ -659,15 +659,7 @@
   GetWidget()->Close();
 }
 
-void ContentSettingBubbleContents::DidFinishNavigation(
-    content::NavigationHandle* navigation_handle) {
-  // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
-  // frames. This caller was converted automatically to the primary main frame
-  // to preserve its semantics. Follow up to confirm correctness.
-  if (!navigation_handle->IsInPrimaryMainFrame() ||
-      !navigation_handle->HasCommitted())
-    return;
-
+void ContentSettingBubbleContents::PrimaryPageChanged(content::Page& page) {
   // Content settings are based on the main frame, so if it switches then
   // close up shop.
   GetWidget()->Close();
diff --git a/chrome/browser/ui/views/content_setting_bubble_contents.h b/chrome/browser/ui/views/content_setting_bubble_contents.h
index cfddcff..dda9b6b 100644
--- a/chrome/browser/ui/views/content_setting_bubble_contents.h
+++ b/chrome/browser/ui/views/content_setting_bubble_contents.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -95,8 +94,7 @@
   void OnPerformAction(views::Combobox* combobox);
 
   // content::WebContentsObserver:
-  void DidFinishNavigation(
-      content::NavigationHandle* navigation_handle) override;
+  void PrimaryPageChanged(content::Page& page) override;
   void OnVisibilityChanged(content::Visibility visibility) override;
   void WebContentsDestroyed() override;
 
diff --git a/chrome/browser/ui/views/content_setting_bubble_contents_interactive_uitest.cc b/chrome/browser/ui/views/content_setting_bubble_contents_interactive_uitest.cc
new file mode 100644
index 0000000..c71c36f
--- /dev/null
+++ b/chrome/browser/ui/views/content_setting_bubble_contents_interactive_uitest.cc
@@ -0,0 +1,153 @@
+// 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/ui/views/content_setting_bubble_contents.h"
+
+#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
+#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/interactive_test_utils.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/permissions/permission_request_manager.h"
+#include "components/permissions/test/permission_request_observer.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/prerender_test_util.h"
+#include "ui/views/test/widget_test.h"
+
+class ContentSettingBubbleContentsInteractiveTest
+    : public InProcessBrowserTest {
+ public:
+  ContentSettingBubbleContentsInteractiveTest()
+      : prerender_helper_(base::BindRepeating(
+            &ContentSettingBubbleContentsInteractiveTest::web_contents,
+            base::Unretained(this))) {}
+  ~ContentSettingBubbleContentsInteractiveTest() override = default;
+
+  void SetUp() override {
+    prerender_helper_.SetUp(embedded_test_server());
+    InProcessBrowserTest::SetUp();
+  }
+
+  content::WebContents* web_contents() {
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  ContentSettingImageView& GetContentSettingImageView(
+      ContentSettingImageModel::ImageType image_type) {
+    LocationBarView* location_bar_view =
+        BrowserView::GetBrowserViewForBrowser(browser())->GetLocationBarView();
+    return **std::find_if(
+        location_bar_view->GetContentSettingViewsForTest().begin(),
+        location_bar_view->GetContentSettingViewsForTest().end(),
+        [image_type](ContentSettingImageView* view) {
+          return view->GetTypeForTesting() == image_type;
+        });
+  }
+
+  content::test::PrerenderTestHelper* prerender_helper() {
+    return &prerender_helper_;
+  }
+
+ private:
+  content::test::PrerenderTestHelper prerender_helper_;
+};
+
+class BubbleWidgetObserver : public views::WidgetObserver {
+ public:
+  explicit BubbleWidgetObserver(views::Widget* widget) : widget_(widget) {
+    if (!widget_)
+      return;
+    widget_->AddObserver(this);
+  }
+
+  ~BubbleWidgetObserver() override { CleanupWidget(); }
+
+  void WaitForClose() {
+    if (!widget_)
+      return;
+    run_loop_ = std::make_unique<base::RunLoop>();
+    run_loop_->Run();
+  }
+
+  // views::WidgetObserver:
+  void OnWidgetDestroyed(views::Widget* widget) override {
+    CleanupWidget();
+    if (run_loop_)
+      run_loop_->Quit();
+  }
+
+  void CleanupWidget() {
+    if (!widget_)
+      return;
+    widget_->RemoveObserver(this);
+    widget_ = nullptr;
+  }
+
+ private:
+  views::Widget* widget_;
+  std::unique_ptr<base::RunLoop> run_loop_;
+};
+
+IN_PROC_BROWSER_TEST_F(ContentSettingBubbleContentsInteractiveTest,
+                       PrerenderDoesNotCloseBubble) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // Dismiss any prompts so that content setting icons appear.
+  permissions::PermissionRequestManager::FromWebContents(web_contents())
+      ->set_auto_response_for_test(
+          permissions::PermissionRequestManager::DISMISS);
+
+  // Navigate to the test page.
+  EXPECT_TRUE(content::NavigateToURL(
+      web_contents(), embedded_test_server()->GetURL(
+                          "/content_setting_bubble/geolocation.html")));
+  EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
+
+  // Get the geolocation icon on the omnibox.
+  ContentSettingImageView& geolocation_icon = GetContentSettingImageView(
+      ContentSettingImageModel::ImageType::GEOLOCATION);
+  // Geolocation icon should be off in the beginning.
+  EXPECT_FALSE(geolocation_icon.GetVisible());
+
+  // Attempt to use geolocation but the permission request will be dismissed.
+  ASSERT_TRUE(content::ExecJs(web_contents(), "geolocate();"));
+  permissions::PermissionRequestObserver(web_contents()).Wait();
+
+  // Geolocation icon should be on since geolocation API is used.
+  EXPECT_TRUE(geolocation_icon.GetVisible());
+  // Make sure its content setting bubble doesn't show yet.
+  EXPECT_FALSE(geolocation_icon.IsBubbleShowing());
+
+  // Press the geolocation icon.
+  base::RunLoop run_loop;
+  ui_test_utils::MoveMouseToCenterAndPress(&geolocation_icon, ui_controls::LEFT,
+                                           ui_controls::DOWN | ui_controls::UP,
+                                           run_loop.QuitClosure());
+  run_loop.Run();
+
+  // Make sure its content setting bubble is shown.
+  EXPECT_TRUE(geolocation_icon.IsBubbleShowing());
+
+  // Start a prerender.
+  auto prerender_url = embedded_test_server()->GetURL("/empty.html");
+  int host_id = prerender_helper()->AddPrerender(prerender_url);
+  content::test::PrerenderHostObserver host_observer(*web_contents(), host_id);
+  EXPECT_FALSE(host_observer.was_activated());
+
+  // Make sure the bubble is still shown after prerender navigation.
+  EXPECT_TRUE(geolocation_icon.IsBubbleShowing());
+
+  BubbleWidgetObserver widget_close_observer(
+      geolocation_icon.GetBubbleWidgetForTesting());
+
+  // Activate the page from the prerendering.
+  prerender_helper()->NavigatePrimaryPage(prerender_url);
+  EXPECT_TRUE(host_observer.was_activated());
+
+  // Wait for the bubble widget to be closed.
+  widget_close_observer.WaitForClose();
+
+  // Make sure the bubble is not shown.
+  EXPECT_FALSE(geolocation_icon.IsBubbleShowing());
+}
diff --git a/chrome/browser/ui/views/cookie_info_view.h b/chrome/browser/ui/views/cookie_info_view.h
index 779d155..edc06e4 100644
--- a/chrome/browser/ui/views/cookie_info_view.h
+++ b/chrome/browser/ui/views/cookie_info_view.h
@@ -10,7 +10,6 @@
 #include <unordered_map>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/controls/scroll_view.h"
 
diff --git a/chrome/browser/ui/views/download/download_in_progress_dialog_view.h b/chrome/browser/ui/views/download/download_in_progress_dialog_view.h
index 01efff029..779c05c 100644
--- a/chrome/browser/ui/views/download/download_in_progress_dialog_view.h
+++ b/chrome/browser/ui/views/download/download_in_progress_dialog_view.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_DOWNLOAD_DOWNLOAD_IN_PROGRESS_DIALOG_VIEW_H_
 #define CHROME_BROWSER_UI_VIEWS_DOWNLOAD_DOWNLOAD_IN_PROGRESS_DIALOG_VIEW_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/browser.h"
 #include "ui/views/window/dialog_delegate.h"
 
diff --git a/chrome/browser/ui/views/download/download_shelf_context_menu_view.h b/chrome/browser/ui/views/download/download_shelf_context_menu_view.h
index 916fd9bf..ad1939b 100644
--- a/chrome/browser/ui/views/download/download_shelf_context_menu_view.h
+++ b/chrome/browser/ui/views/download/download_shelf_context_menu_view.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/time/time.h"
 #include "chrome/browser/download/download_shelf_context_menu.h"
 #include "ui/base/ui_base_types.h"
diff --git a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
index 199f7c1b..221dec1 100644
--- a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
+++ b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
@@ -529,6 +529,10 @@
     expected_effect_allowed_ = value;
   }
 
+  void set_expected_file_names(const std::string& value) {
+    expected_file_names_ = value;
+  }
+
   void set_expected_mime_types(const std::string& value) {
     expected_mime_types_ = value;
   }
@@ -549,6 +553,7 @@
         FieldMatches("client_position", expected_client_position_),
         FieldMatches("drop_effect", expected_drop_effect_),
         FieldMatches("effect_allowed", expected_effect_allowed_),
+        FieldMatches("file_names", expected_file_names_),
         FieldMatches("mime_types", expected_mime_types_),
         FieldMatches("page_position", expected_page_position_),
         FieldMatches("screen_position", expected_screen_position_));
@@ -567,6 +572,7 @@
 
   std::string expected_drop_effect_ = "<no expectation>";
   std::string expected_effect_allowed_ = "<no expectation>";
+  std::string expected_file_names_ = "<no expectation>";
   std::string expected_mime_types_ = "<no expectation>";
   std::string expected_client_position_ = "<no expectation>";
   std::string expected_page_position_ = "<no expectation>";
@@ -663,8 +669,7 @@
 
   struct DragImageBetweenFrames_TestState;
   void DragImageBetweenFrames_Start(bool image_same_origin,
-                                    bool image_crossorigin_attr,
-                                    const std::string& expected_mime_types);
+                                    bool image_crossorigin_attr);
   void DragImageBetweenFrames_Step2(DragImageBetweenFrames_TestState*);
   void DragImageBetweenFrames_Step3(DragImageBetweenFrames_TestState*);
 
@@ -1209,11 +1214,16 @@
   expected_dom_event_data.set_expected_effect_allowed("copy");
   expected_dom_event_data.set_expected_page_position("(55, 50)");
 
-  // TODO(lukasza): Figure out why the dragstart event
-  // - lists "Files" on the mime types list,
-  // - doesn't list "text/plain" on the mime types list.
-  // (i.e. why expectations below differ from expectations for dragenter,
-  // dragover, dragend and/or drop events in DragImageBetweenFrames test).
+  // The dragstart event can have different mime types to the following events.
+  // It is created by the renderer with the original DataTransfer object which
+  // is then sent to the browser which initiates subsequent events.
+  // The dragstart mime types will always include 'File', but access to the file
+  // will not be allowed if the image is cross-origin (getAsFile() is null).
+  // When the browser receives the DataTransfer, it copies data into
+  // OSExchangeData and uses this for following events. Copying in text/html
+  // will also populate text/plain. The File object may or may not be included
+  // in following events depending on whether the image is cross-origin, and
+  // whether the drop target is to a different page.
   expected_dom_event_data.set_expected_mime_types(
       "Files,text/html,text/uri-list");
 
@@ -1270,6 +1280,7 @@
 // Data that needs to be shared across multiple test steps below
 // (i.e. across DragImageBetweenFrames_Step2 and DragImageBetweenFrames_Step3).
 struct DragAndDropBrowserTest::DragImageBetweenFrames_TestState {
+  bool expect_image_accessible = false;
   DOMDragEventVerifier expected_dom_event_data;
   std::unique_ptr<DOMDragEventWaiter> dragstart_event_waiter;
   std::unique_ptr<DOMDragEventWaiter> drop_event_waiter;
@@ -1283,8 +1294,7 @@
 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,
                        MAYBE_DragSameOriginImageBetweenFrames) {
   DragImageBetweenFrames_Start(/*image_same_origin=*/true,
-                               /*image_crossorigin_attr=*/false,
-                               "Files,text/html,text/plain,text/uri-list");
+                               /*image_crossorigin_attr=*/false);
 }
 
 #if defined(OS_WIN)
@@ -1305,8 +1315,7 @@
 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,
                        MAYBE_DragCorsSameOriginImageBetweenFrames) {
   DragImageBetweenFrames_Start(/*image_same_origin=*/false,
-                               /*image_crossorigin_attr=*/true,
-                               "Files,text/html,text/plain,text/uri-list");
+                               /*image_crossorigin_attr=*/true);
 }
 
 #if defined(OS_WIN)
@@ -1327,15 +1336,12 @@
 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,
                        MAYBE_DragCrossOriginImageBetweenFrames) {
   DragImageBetweenFrames_Start(/*image_same_origin=*/false,
-                               /*image_crossorigin_attr=*/false,
-                               // No 'Files' in expected mime types.
-                               "text/html,text/plain,text/uri-list");
+                               /*image_crossorigin_attr=*/false);
 }
 
 void DragAndDropBrowserTest::DragImageBetweenFrames_Start(
     bool image_same_origin,
-    bool image_crossorigin_attr,
-    const std::string& expected_mime_types) {
+    bool image_crossorigin_attr) {
   // Note that drag and drop will not expose data across cross-site frames on
   // the same page - this is why the same |frame_site| is used below both for
   // the left and the right frame.  See also https://crbug.com/59081.
@@ -1348,6 +1354,7 @@
 
   // Setup test expectations.
   DragAndDropBrowserTest::DragImageBetweenFrames_TestState state;
+  state.expect_image_accessible = image_same_origin || image_crossorigin_attr;
   state.left_frame_events_counter =
       std::make_unique<DOMDragEventCounter>(GetLeftFrame());
   state.right_frame_events_counter =
@@ -1356,7 +1363,10 @@
   state.expected_dom_event_data.set_expected_drop_effect("none");
   // (dragstart event handler in image_source.html is asking for "copy" only).
   state.expected_dom_event_data.set_expected_effect_allowed("copy");
-  state.expected_dom_event_data.set_expected_mime_types(expected_mime_types);
+  state.expected_dom_event_data.set_expected_file_names(
+      state.expect_image_accessible ? "cors-allowed.jpg" : "");
+  state.expected_dom_event_data.set_expected_mime_types(
+      "Files,text/html,text/uri-list");
   state.expected_dom_event_data.set_expected_page_position("(55, 50)");
 
   // Start the drag in the left frame.
@@ -1383,6 +1393,7 @@
     std::string dragstart_event;
     EXPECT_TRUE(state->dragstart_event_waiter->WaitForNextMatchingEvent(
         &dragstart_event));
+    EXPECT_THAT(dragstart_event, state->expected_dom_event_data.Matches());
     state->dragstart_event_waiter.reset();
 
     // Only a single "dragstart" should have fired in the left frame since the
@@ -1416,6 +1427,11 @@
 
       state->expected_dom_event_data.set_expected_client_position("(355, 150)");
       state->expected_dom_event_data.set_expected_page_position("(355, 150)");
+      state->expected_dom_event_data.set_expected_file_names("");
+      state->expected_dom_event_data.set_expected_mime_types(
+          state->expect_image_accessible
+              ? "Files,text/html,text/plain,text/uri-list"
+              : "text/html,text/plain,text/uri-list");
 
       EXPECT_TRUE(
           dragleave_event_waiter.WaitForNextMatchingEvent(&dragleave_event));
@@ -1488,6 +1504,14 @@
     DragAndDropBrowserTest::DragImageBetweenFrames_TestState* state) {
   // Verify drop DOM event.
   {
+    // File contents is sent in drop event.
+    state->expected_dom_event_data.set_expected_file_names(
+        state->expect_image_accessible ? "cors-allowed.jpg" : "");
+    state->expected_dom_event_data.set_expected_mime_types(
+        state->expect_image_accessible
+            ? "Files,text/html,text/plain,text/uri-list"
+            : "text/html,text/plain,text/uri-list");
+
     std::string drop_event;
     EXPECT_TRUE(
         state->drop_event_waiter->WaitForNextMatchingEvent(&drop_event));
@@ -1508,6 +1532,8 @@
         "<no expectation>");
     state->expected_dom_event_data.set_expected_page_position(
         "<no expectation>");
+    // File contents is not sent in dragend.
+    state->expected_dom_event_data.set_expected_file_names("");
 
     std::string dragend_event;
     EXPECT_TRUE(
diff --git a/chrome/browser/ui/views/dropdown_bar_host.h b/chrome/browser/ui/views/dropdown_bar_host.h
index f7c5907..162b901 100644
--- a/chrome/browser/ui/views/dropdown_bar_host.h
+++ b/chrome/browser/ui/views/dropdown_bar_host.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.h b/chrome/browser/ui/views/exclusive_access_bubble_views.h
index 09a804b..85bdef6f 100644
--- a/chrome/browser/ui/views/exclusive_access_bubble_views.h
+++ b/chrome/browser/ui/views/exclusive_access_bubble_views.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/scoped_observation.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_hide_callback.h"
diff --git a/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h b/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h
index 30021c44..632f8680 100644
--- a/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h
+++ b/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/extensions/extension_keybinding_registry.h"
 #include "ui/base/accelerators/accelerator.h"
 
diff --git a/chrome/browser/ui/views/extensions/extension_popup.h b/chrome/browser/ui/views/extensions/extension_popup.h
index 3e09cc1..9a5b281 100644
--- a/chrome/browser/ui/views/extensions/extension_popup.h
+++ b/chrome/browser/ui/views/extensions/extension_popup.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSION_POPUP_H_
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/scoped_observation.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
diff --git a/chrome/browser/ui/views/extensions/extension_view_views.h b/chrome/browser/ui/views/extensions/extension_view_views.h
index 0a85af44..72527bb3 100644
--- a/chrome/browser/ui/views/extensions/extension_view_views.h
+++ b/chrome/browser/ui/views/extensions/extension_view_views.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSION_VIEW_VIEWS_H_
 #define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSION_VIEW_VIEWS_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/extensions/extension_view.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h
index 48ccd3b..d3fb5be9 100644
--- a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h
+++ b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h
@@ -7,7 +7,6 @@
 
 #include <map>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
 #include "ui/views/context_menu_controller.h"
diff --git a/chrome/browser/ui/views/find_bar_host.h b/chrome/browser/ui/views/find_bar_host.h
index 2ce8d0c..ca152dd 100644
--- a/chrome/browser/ui/views/find_bar_host.h
+++ b/chrome/browser/ui/views/find_bar_host.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_FIND_BAR_HOST_H_
 #define CHROME_BROWSER_UI_VIEWS_FIND_BAR_HOST_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/find_bar/find_bar.h"
 #include "chrome/browser/ui/views/dropdown_bar_host.h"
 #include "chrome/browser/ui/views/find_bar_view.h"
diff --git a/chrome/browser/ui/views/find_bar_view.h b/chrome/browser/ui/views/find_bar_view.h
index 1f649dba4..b632554 100644
--- a/chrome/browser/ui/views/find_bar_view.h
+++ b/chrome/browser/ui/views/find_bar_view.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/views/chrome_views_export.h"
 #include "chrome/browser/ui/views/dropdown_bar_host_delegate.h"
 #include "ui/views/controls/button/button.h"
diff --git a/chrome/browser/ui/views/frame/browser_frame.h b/chrome/browser/ui/views/frame/browser_frame.h
index 696534e..5afdf4c 100644
--- a/chrome/browser/ui/views/frame/browser_frame.h
+++ b/chrome/browser/ui/views/frame/browser_frame.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_FRAME_H_
 #define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_FRAME_H_
 
-#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "content/public/browser/keyboard_event_processing_result.h"
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 720c109..eac6f2c 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -3284,7 +3284,7 @@
   // the ToolbarView does not create a button for them. This specifically seems
   // to hit web apps. See https://crbug.com/1267781.
   if (base::FeatureList::IsEnabled(features::kSidePanelBorder) &&
-      toolbar_->read_later_button() &&
+      toolbar_->side_panel_button() &&
       (lens_side_panel_ || right_aligned_side_panel_)) {
     std::vector<View*> panels;
     if (lens_side_panel_)
@@ -3293,7 +3293,7 @@
       panels.push_back(right_aligned_side_panel_);
     side_panel_button_highlighter_ =
         std::make_unique<SidePanelButtonHighlighter>(
-            toolbar_->read_later_button(), panels);
+            toolbar_->side_panel_button(), panels);
   }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 20bf11d..72454b4 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -11,7 +11,6 @@
 #include <vector>
 
 #include "base/callback_list.h"
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/scoped_observation.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.h b/chrome/browser/ui/views/frame/browser_view_layout.h
index 4c9b06e..fa8b5ca 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.h
+++ b/chrome/browser/ui/views/frame/browser_view_layout.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
diff --git a/chrome/browser/ui/views/frame/contents_layout_manager.h b/chrome/browser/ui/views/frame/contents_layout_manager.h
index 7f9fcf73..621d6ab 100644
--- a/chrome/browser/ui/views/frame/contents_layout_manager.h
+++ b/chrome/browser/ui/views/frame/contents_layout_manager.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_FRAME_CONTENTS_LAYOUT_MANAGER_H_
 #define CHROME_BROWSER_UI_VIEWS_FRAME_CONTENTS_LAYOUT_MANAGER_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
 #include "ui/views/layout/layout_manager.h"
 
diff --git a/chrome/browser/ui/views/frame/contents_web_view.h b/chrome/browser/ui/views/frame/contents_web_view.h
index 60f989a..cab6e0fa 100644
--- a/chrome/browser/ui/views/frame/contents_web_view.h
+++ b/chrome/browser/ui/views/frame/contents_web_view.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/views/frame/web_contents_close_handler_delegate.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/skia/include/core/SkColor.h"
diff --git a/chrome/browser/ui/views/frame/dbus_appmenu.h b/chrome/browser/ui/views/frame/dbus_appmenu.h
index 3bb4b9d..4c9afde 100644
--- a/chrome/browser/ui/views/frame/dbus_appmenu.h
+++ b/chrome/browser/ui/views/frame/dbus_appmenu.h
@@ -8,7 +8,6 @@
 #include <map>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/containers/flat_set.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.h b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
index 9c9a4fd..0ca8681 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_FRAME_GLASS_BROWSER_FRAME_VIEW_H_
 #define CHROME_BROWSER_UI_VIEWS_FRAME_GLASS_BROWSER_FRAME_VIEW_H_
 
-#include "base/compiler_specific.h"
 #include "base/win/scoped_gdi_object.h"
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
 #include "chrome/browser/ui/views/frame/windows_10_caption_button.h"
diff --git a/chrome/browser/ui/views/frame/system_menu_insertion_delegate_win.h b/chrome/browser/ui/views/frame/system_menu_insertion_delegate_win.h
index 9b8122b..c4eda4e 100644
--- a/chrome/browser/ui/views/frame/system_menu_insertion_delegate_win.h
+++ b/chrome/browser/ui/views/frame/system_menu_insertion_delegate_win.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_FRAME_SYSTEM_MENU_INSERTION_DELEGATE_WIN_H_
 #define CHROME_BROWSER_UI_VIEWS_FRAME_SYSTEM_MENU_INSERTION_DELEGATE_WIN_H_
 
-#include "base/compiler_specific.h"
 #include "ui/views/controls/menu/menu_insertion_delegate_win.h"
 
 // SystemMenuInsertionDelegateWin is used to determine the index to insert menu
diff --git a/chrome/browser/ui/views/frame/system_menu_model_delegate.h b/chrome/browser/ui/views/frame/system_menu_model_delegate.h
index 083620a..d03cfa0 100644
--- a/chrome/browser/ui/views/frame/system_menu_model_delegate.h
+++ b/chrome/browser/ui/views/frame/system_menu_model_delegate.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_FRAME_SYSTEM_MENU_MODEL_DELEGATE_H_
 #define CHROME_BROWSER_UI_VIEWS_FRAME_SYSTEM_MENU_MODEL_DELEGATE_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/browser.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/models/simple_menu_model.h"
diff --git a/chrome/browser/ui/views/frame/toolbar_button_provider.h b/chrome/browser/ui/views/frame/toolbar_button_provider.h
index 976a337f..90e8a76 100644
--- a/chrome/browser/ui/views/frame/toolbar_button_provider.h
+++ b/chrome/browser/ui/views/frame/toolbar_button_provider.h
@@ -11,7 +11,7 @@
 class AvatarToolbarButton;
 class ExtensionsToolbarContainer;
 class PageActionIconView;
-class ReadLaterToolbarButton;
+class SidePanelToolbarButton;
 class ReloadButton;
 class ToolbarButton;
 
@@ -63,7 +63,7 @@
   virtual void ZoomChangedForActiveTab(bool can_show_bubble) = 0;
 
   // Returns the side panel button.
-  virtual ReadLaterToolbarButton* GetSidePanelButton() = 0;
+  virtual SidePanelToolbarButton* GetSidePanelButton() = 0;
 
   // Returns the avatar button.
   virtual AvatarToolbarButton* GetAvatarToolbarButton() = 0;
diff --git a/chrome/browser/ui/views/frame/top_container_view.h b/chrome/browser/ui/views/frame/top_container_view.h
index fda0d14..c5fc1802 100644
--- a/chrome/browser/ui/views/frame/top_container_view.h
+++ b/chrome/browser/ui/views/frame/top_container_view.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_FRAME_TOP_CONTAINER_VIEW_H_
 #define CHROME_BROWSER_UI_VIEWS_FRAME_TOP_CONTAINER_VIEW_H_
 
-#include "base/compiler_specific.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/view.h"
 
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
index b921f71eb..b425636 100644
--- a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
@@ -693,8 +693,8 @@
   EXPECT_FALSE(IsDialogVisible());
 }
 
-#if defined(OS_MAC) && defined(ARCH_CPU_ARM64)
-// https://crbug.com/1222873
+// TODO(crbug.com/1225531, crbug.com/1222873): Flaky.
+#if defined(OS_LINUX) || defined(OS_MAC)
 #define MAYBE_ShowsMetadataAndControlsMediaInRTL \
   DISABLED_ShowsMetadataAndControlsMediaInRTL
 #else
@@ -950,9 +950,8 @@
   EXPECT_TRUE(IsPlayingSessionDisplayedFirst());
 }
 
-#if (defined(OS_MAC) && defined(ARCH_CPU_ARM64)) || defined(OS_WIN)
-// https://crbug.com/1222873
-// https://crbug.com/1271131
+// TODO(crbug.com/1225531, crbug.com/1222873, crbug.com/1271131): Flaky.
+#if defined(OS_LINUX) || defined(OS_MAC) || defined(OS_WIN)
 #define MAYBE_LiveCaption DISABLED_LiveCaption
 #else
 #define MAYBE_LiveCaption LiveCaption
@@ -1057,8 +1056,8 @@
             base::UTF16ToUTF8(GetLiveCaptionTitleLabel()->GetText()));
 }
 
-#if defined(OS_MAC) && defined(ARCH_CPU_ARM64)
-// https://crbug.com/1222873
+// TODO(crbug.com/1225531, crbug.com/1222873): Flaky.
+#if defined(OS_LINUX) || defined(OS_MAC)
 #define MAYBE_LiveCaptionShowLanguage DISABLED_LiveCaptionShowLanguage
 #else
 #define MAYBE_LiveCaptionShowLanguage LiveCaptionShowLanguage
diff --git a/chrome/browser/ui/views/importer/import_lock_dialog_view.h b/chrome/browser/ui/views/importer/import_lock_dialog_view.h
index 735e209..2850a5e 100644
--- a/chrome/browser/ui/views/importer/import_lock_dialog_view.h
+++ b/chrome/browser/ui/views/importer/import_lock_dialog_view.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_UI_VIEWS_IMPORTER_IMPORT_LOCK_DIALOG_VIEW_H_
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/window/dialog_delegate.h"
 
diff --git a/chrome/browser/ui/views/infobars/confirm_infobar.h b/chrome/browser/ui/views/infobars/confirm_infobar.h
index a921b42..acad881 100644
--- a/chrome/browser/ui/views/infobars/confirm_infobar.h
+++ b/chrome/browser/ui/views/infobars/confirm_infobar.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_INFOBARS_CONFIRM_INFOBAR_H_
 #define CHROME_BROWSER_UI_VIEWS_INFOBARS_CONFIRM_INFOBAR_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/views/infobars/infobar_view.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
 
diff --git a/chrome/browser/ui/views/infobars/infobar_view.h b/chrome/browser/ui/views/infobars/infobar_view.h
index 522b3c9..b22e7111 100644
--- a/chrome/browser/ui/views/infobars/infobar_view.h
+++ b/chrome/browser/ui/views/infobars/infobar_view.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_INFOBARS_INFOBAR_VIEW_H_
 #define CHROME_BROWSER_UI_VIEWS_INFOBARS_INFOBAR_VIEW_H_
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "components/infobars/core/infobar.h"
 #include "components/infobars/core/infobar_container.h"
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc
index a710376..81afcf85 100644
--- a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc
+++ b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc
@@ -10,7 +10,6 @@
 #include "ash/components/arc/test/arc_util_test_support.h"
 #include "ash/components/arc/test/connection_holder_util.h"
 #include "ash/components/arc/test/fake_app_instance.h"
-#include "ash/components/arc/test/fake_intent_helper_instance.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
@@ -35,6 +34,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/session/arc_service_manager.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
 #include "components/services/app_service/public/cpp/icon_loader.h"
 #include "components/services/app_service/public/cpp/intent_filter_util.h"
 #include "components/services/app_service/public/cpp/intent_test_util.h"
diff --git a/chrome/browser/ui/views/lens/lens_side_panel_controller.cc b/chrome/browser/ui/views/lens/lens_side_panel_controller.cc
index d1873898..ca028a1 100644
--- a/chrome/browser/ui/views/lens/lens_side_panel_controller.cc
+++ b/chrome/browser/ui/views/lens/lens_side_panel_controller.cc
@@ -66,11 +66,11 @@
 void LensSidePanelController::OpenWithURL(
     const content::OpenURLParams& params) {
   // Hide Chrome side panel (Reading List/Bookmarks) if enabled and showing.
-  if (browser_view_->toolbar()->read_later_button() &&
+  if (browser_view_->toolbar()->side_panel_button() &&
       browser_view_->right_aligned_side_panel()->GetVisible()) {
     base::RecordAction(
         base::UserMetricsAction("LensSidePanel.HideChromeSidePanel"));
-    browser_view_->toolbar()->read_later_button()->HideSidePanel();
+    browser_view_->toolbar()->side_panel_button()->HideSidePanel();
   }
   side_panel_view_->GetWebContents()->GetController().LoadURLWithParams(
       content::NavigationController::LoadURLParams(params));
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
index 2d40766..efa86e5a 100644
--- a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
+++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
@@ -225,6 +225,13 @@
   return content_setting_image_model_->image_type();
 }
 
+views::Widget* ContentSettingImageView::GetBubbleWidgetForTesting() const {
+  if (!bubble_view_)
+    return nullptr;
+
+  return bubble_view_->GetWidget();
+}
+
 void ContentSettingImageView::OnWidgetDestroying(views::Widget* widget) {
   if (!bubble_view_ || bubble_view_->GetWidget() != widget)
     return;
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.h b/chrome/browser/ui/views/location_bar/content_setting_image_view.h
index 6f6acd9b..b8db8e5 100644
--- a/chrome/browser/ui/views/location_bar/content_setting_image_view.h
+++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.h
@@ -91,6 +91,7 @@
   void AnimationEnded(const gfx::Animation* animation) override;
 
   ContentSettingImageModel::ImageType GetTypeForTesting() const;
+  views::Widget* GetBubbleWidgetForTesting() const;
 
   void reset_animation_for_testing() {
     IconLabelBubbleView::ResetSlideAnimation(true);
diff --git a/chrome/browser/ui/views/location_bar/keyword_hint_view.h b/chrome/browser/ui/views/location_bar/keyword_hint_view.h
index bf0de2e..a193fc4139 100644
--- a/chrome/browser/ui/views/location_bar/keyword_hint_view.h
+++ b/chrome/browser/ui/views/location_bar/keyword_hint_view.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/gfx/geometry/size.h"
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index 9d5cbe44b..79241afe 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -11,7 +11,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view.h b/chrome/browser/ui/views/location_bar/selected_keyword_view.h
index 3d10627..1b7fda42 100644
--- a/chrome/browser/ui/views/location_bar/selected_keyword_view.h
+++ b/chrome/browser/ui/views/location_bar/selected_keyword_view.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/views/location_bar/icon_label_bubble_view.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/metadata/metadata_header_macros.h"
diff --git a/chrome/browser/ui/views/passwords/OWNERS b/chrome/browser/ui/views/passwords/OWNERS
index a10e9420..2affc5ad 100644
--- a/chrome/browser/ui/views/passwords/OWNERS
+++ b/chrome/browser/ui/views/passwords/OWNERS
@@ -1 +1,2 @@
+mamir@chromium.org
 vasilii@chromium.org
diff --git a/chrome/browser/ui/views/profiles/profile_indicator_icon.h b/chrome/browser/ui/views/profiles/profile_indicator_icon.h
index 5c6fa4b..705ae0e 100644
--- a/chrome/browser/ui/views/profiles/profile_indicator_icon.h
+++ b/chrome/browser/ui/views/profiles/profile_indicator_icon.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_PROFILES_PROFILE_INDICATOR_ICON_H_
 #define CHROME_BROWSER_UI_VIEWS_PROFILES_PROFILE_INDICATOR_ICON_H_
 
-#include "base/compiler_specific.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/gfx/image/image.h"
 #include "ui/views/view.h"
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl_browsertest.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl_browsertest.cc
index c01d31c6..7a03dfc 100644
--- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl_browsertest.cc
+++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "base/callback_helpers.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/send_tab_to_self_sync_service_factory.h"
 #include "chrome/browser/ui/browser.h"
@@ -75,7 +76,13 @@
   TestSendTabToSelfBubbleController controller_;
 };
 
-IN_PROC_BROWSER_TEST_P(SendTabToSelfBubbleTest, InvokeUi_default) {
+// crbug.com/1272360
+#if defined(OS_LINUX) || defined(OS_WIN)
+#define MAYBE_InvokeUi_default DISABLED_InvokeUi_default
+#else
+#define MAYBE_InvokeUi_default InvokeUi_default
+#endif
+IN_PROC_BROWSER_TEST_P(SendTabToSelfBubbleTest, MAYBE_InvokeUi_default) {
   ShowAndVerifyUi();
 }
 
diff --git a/chrome/browser/ui/views/side_panel/OWNERS b/chrome/browser/ui/views/side_panel/OWNERS
new file mode 100644
index 0000000..d8e574e
--- /dev/null
+++ b/chrome/browser/ui/views/side_panel/OWNERS
@@ -0,0 +1,3 @@
+corising@chromium.org
+pbos@chromium.org
+tluk@chromium.org
diff --git a/chrome/browser/ui/views/status_bubble_views.h b/chrome/browser/ui/views/status_bubble_views.h
index b40e8a7..1c23ff2 100644
--- a/chrome/browser/ui/views/status_bubble_views.h
+++ b/chrome/browser/ui/views/status_bubble_views.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/status_bubble.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/chrome/browser/ui/views/status_icons/status_icon_win.h b/chrome/browser/ui/views/status_icons/status_icon_win.h
index d3cbe47c..4caa5b7 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_win.h
+++ b/chrome/browser/ui/views/status_icons/status_icon_win.h
@@ -10,7 +10,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/win/scoped_gdi_object.h"
 #include "chrome/browser/status_icons/status_icon.h"
 
diff --git a/chrome/browser/ui/views/status_icons/status_tray_linux.h b/chrome/browser/ui/views/status_icons/status_tray_linux.h
index e1500b53..bd09933e 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_linux.h
+++ b/chrome/browser/ui/views/status_icons/status_tray_linux.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_LINUX_H_
 #define CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_LINUX_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/status_icons/status_tray.h"
 
 class StatusTrayLinux : public StatusTray {
diff --git a/chrome/browser/ui/views/status_icons/status_tray_win.h b/chrome/browser/ui/views/status_icons/status_tray_win.h
index 2113997..7b3041528 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_win.h
+++ b/chrome/browser/ui/views/status_icons/status_tray_win.h
@@ -9,7 +9,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "chrome/browser/status_icons/status_tray.h"
 
diff --git a/chrome/browser/ui/views/sync/one_click_signin_dialog_view.h b/chrome/browser/ui/views/sync/one_click_signin_dialog_view.h
index 5ca48c4..506ae2e5 100644
--- a/chrome/browser/ui/views/sync/one_click_signin_dialog_view.h
+++ b/chrome/browser/ui/views/sync/one_click_signin_dialog_view.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/sync/one_click_signin_links_delegate.h"
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
index 64f894e..2bed309 100644
--- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
+++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
@@ -42,11 +42,15 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/styled_label.h"
 #include "ui/views/layout/box_layout.h"
-#include "ui/views/layout/grid_layout.h"
+#include "ui/views/layout/box_layout_view.h"
 #include "ui/views/layout/layout_provider.h"
+#include "ui/views/view_class_properties.h"
 #include "ui/views/views_delegate.h"
 #include "ui/views/widget/widget.h"
 
+constexpr int kBusinessIconSize = 20;
+constexpr int kPreferredWidth = 440;
+
 ProfileSigninConfirmationDialogViews::ProfileSigninConfirmationDialogViews(
     Browser* browser,
     const std::string& username,
@@ -58,42 +62,6 @@
       prompt_for_new_profile_(prompt_for_new_profile),
       use_work_profile_wording_(base::FeatureList::IsEnabled(
           features::kSyncConfirmationUpdatedText)) {
-  if (use_work_profile_wording_) {
-    SetTitle(IDS_ENTERPRISE_SIGNIN_WORK_PROFILE_TITLE);
-    // Create business icon.
-    int business_icon_size = 20;
-    auto business_icon = std::make_unique<views::ImageView>();
-    SetIcon(gfx::CreateVectorIcon(
-        gfx::IconDescription(vector_icons::kBusinessIcon, business_icon_size,
-                             gfx::kChromeIconGrey)));
-    SetShowIcon(true);
-    SetDefaultButton(ui::DIALOG_BUTTON_OK);
-    SetButtonLabel(ui::DIALOG_BUTTON_OK,
-                   l10n_util::GetStringUTF16(
-                       prompt_for_new_profile_
-                           ? IDS_ENTERPRISE_SIGNIN_CREATE_NEW_WORK_PROFILE
-                           : IDS_ENTERPRISE_SIGNIN_CONTINUE));
-  } else {
-    SetShowCloseButton(false);
-    SetTitle(IDS_ENTERPRISE_SIGNIN_TITLE);
-    SetDefaultButton(ui::DIALOG_BUTTON_NONE);
-    SetButtonLabel(
-        ui::DIALOG_BUTTON_OK,
-        l10n_util::GetStringUTF16(prompt_for_new_profile_
-                                      ? IDS_ENTERPRISE_SIGNIN_CREATE_NEW_PROFILE
-                                      : IDS_ENTERPRISE_SIGNIN_CONTINUE));
-    if (prompt_for_new_profile) {
-      SetExtraView(std::make_unique<views::MdTextButton>(
-          base::BindRepeating(&ProfileSigninConfirmationDialogViews::
-                                  ContinueSigninButtonPressed,
-                              base::Unretained(this)),
-          l10n_util::GetStringUTF16(IDS_ENTERPRISE_SIGNIN_CONTINUE)));
-    }
-  }
-  SetButtonLabel(ui::DIALOG_BUTTON_CANCEL,
-                 l10n_util::GetStringUTF16(IDS_ENTERPRISE_SIGNIN_CANCEL));
-  SetModalType(ui::MODAL_TYPE_WINDOW);
-
   using Delegate = ui::ProfileSigninConfirmationDelegate;
   using DelegateNotifyFn = void (Delegate::*)();
   auto notify_delegate = [](ProfileSigninConfirmationDialogViews* dialog,
@@ -103,12 +71,56 @@
       dialog->delegate_.reset();
     }
   };
-  SetAcceptCallback(base::BindOnce(notify_delegate, base::Unretained(this),
-                                   prompt_for_new_profile_
-                                       ? &Delegate::OnSigninWithNewProfile
-                                       : &Delegate::OnContinueSignin));
-  SetCancelCallback(base::BindOnce(notify_delegate, base::Unretained(this),
-                                   &Delegate::OnCancelSignin));
+
+  auto builder =
+      views::Builder<ProfileSigninConfirmationDialogViews>(this)
+          .SetButtonLabel(
+              ui::DIALOG_BUTTON_CANCEL,
+              l10n_util::GetStringUTF16(IDS_ENTERPRISE_SIGNIN_CANCEL))
+          .SetModalType(ui::MODAL_TYPE_WINDOW)
+          .SetAcceptCallback(base::BindOnce(
+              notify_delegate, base::Unretained(this),
+              prompt_for_new_profile_ ? &Delegate::OnSigninWithNewProfile
+                                      : &Delegate::OnContinueSignin))
+          .SetCancelCallback(base::BindOnce(notify_delegate,
+                                            base::Unretained(this),
+                                            &Delegate::OnCancelSignin));
+
+  if (use_work_profile_wording_) {
+    builder
+        .SetTitle(IDS_ENTERPRISE_SIGNIN_WORK_PROFILE_TITLE)
+        // Create business icon.
+        .SetIcon(gfx::CreateVectorIcon(
+            gfx::IconDescription(vector_icons::kBusinessIcon, kBusinessIconSize,
+                                 gfx::kChromeIconGrey)))
+        .SetShowIcon(true)
+        .SetDefaultButton(ui::DIALOG_BUTTON_OK)
+        .SetButtonLabel(ui::DIALOG_BUTTON_OK,
+                        l10n_util::GetStringUTF16(
+                            prompt_for_new_profile_
+                                ? IDS_ENTERPRISE_SIGNIN_CREATE_NEW_WORK_PROFILE
+                                : IDS_ENTERPRISE_SIGNIN_CONTINUE));
+  } else {
+    builder.SetShowCloseButton(false)
+        .SetTitle(IDS_ENTERPRISE_SIGNIN_TITLE)
+        .SetDefaultButton(ui::DIALOG_BUTTON_NONE)
+        .SetButtonLabel(ui::DIALOG_BUTTON_OK,
+                        l10n_util::GetStringUTF16(
+                            prompt_for_new_profile_
+                                ? IDS_ENTERPRISE_SIGNIN_CREATE_NEW_PROFILE
+                                : IDS_ENTERPRISE_SIGNIN_CONTINUE));
+    if (prompt_for_new_profile) {
+      builder.SetExtraView(views::Builder<views::MdTextButton>()
+                               .SetCallback(base::BindRepeating(
+                                   &ProfileSigninConfirmationDialogViews::
+                                       ContinueSigninButtonPressed,
+                                   base::Unretained(this)))
+                               .SetText(l10n_util::GetStringUTF16(
+                                   IDS_ENTERPRISE_SIGNIN_CONTINUE)));
+    }
+  }
+
+  std::move(builder).BuildChildren();
 
   chrome::RecordDialogCreation(
       chrome::DialogIdentifier::PROFILE_SIGNIN_CONFIRMATION);
@@ -143,41 +155,16 @@
 
 void ProfileSigninConfirmationDialogViews::BuildDefaultView() {
   DCHECK(!use_work_profile_wording_);
-  const SkColor kPromptBarBackgroundColor =
-      ui::GetSigninConfirmationPromptBarColor(GetColorProvider(), 0x0A);
 
-  // Create business icon.
-  int business_icon_size = 20;
-  auto business_icon = std::make_unique<views::ImageView>();
-  business_icon->SetImage(gfx::CreateVectorIcon(gfx::IconDescription(
-      vector_icons::kBusinessIcon, business_icon_size, gfx::kChromeIconGrey)));
-
-  // Create the prompt label.
   size_t offset;
+  std::vector<size_t> offsets;
   const std::u16string domain =
       base::ASCIIToUTF16(gaia::ExtractDomainName(username_));
   const std::u16string username = base::ASCIIToUTF16(username_);
   const std::u16string prompt_text =
       l10n_util::GetStringFUTF16(IDS_ENTERPRISE_SIGNIN_ALERT, domain, &offset);
-  auto prompt_label = std::make_unique<views::StyledLabel>();
-  prompt_label->SetText(prompt_text);
-  prompt_label->SetDisplayedOnBackgroundColor(kPromptBarBackgroundColor);
-
   views::StyledLabel::RangeStyleInfo bold_style;
   bold_style.text_style = STYLE_EMPHASIZED;
-  prompt_label->AddStyleRange(
-      gfx::Range(offset, offset + domain.size()), bold_style);
-
-  // Create the prompt bar.
-  auto prompt_bar = std::make_unique<views::View>();
-  prompt_bar->SetBorder(views::CreateSolidSidedBorder(
-      1, 0, 1, 0,
-      ui::GetSigninConfirmationPromptBarColor(GetColorProvider(), 0x1F)));
-  prompt_bar->SetBackground(
-      views::CreateSolidBackground(kPromptBarBackgroundColor));
-
-  // Create the explanation label.
-  std::vector<size_t> offsets;
   const std::u16string learn_more_text =
       l10n_util::GetStringUTF16(IDS_LEARN_MORE);
   const std::u16string signin_explanation_text = l10n_util::GetStringFUTF16(
@@ -185,160 +172,108 @@
           ? IDS_ENTERPRISE_SIGNIN_EXPLANATION_WITH_PROFILE_CREATION
           : IDS_ENTERPRISE_SIGNIN_EXPLANATION_WITHOUT_PROFILE_CREATION,
       username, learn_more_text, &offsets);
-  auto explanation_label = std::make_unique<views::StyledLabel>();
-  explanation_label->SetText(signin_explanation_text);
-  explanation_label->AddStyleRange(
-      gfx::Range(offsets[1], offsets[1] + learn_more_text.size()),
-      views::StyledLabel::RangeStyleInfo::CreateForLink(base::BindRepeating(
-          &ProfileSigninConfirmationDialogViews::LearnMoreClicked,
-          base::Unretained(this))));
-
-  // Layout the components.
+  const SkColor kPromptBarBackgroundColor =
+      ui::GetSigninConfirmationPromptBarColor(GetColorProvider(), 0x0A);
   const gfx::Insets content_insets =
       views::LayoutProvider::Get()->GetDialogInsetsForContentType(
           views::DialogContentType::kControl, views::DialogContentType::kText);
-  // The prompt bar needs to go to the edge of the dialog, so remove horizontal
-  // insets.
-  SetBorder(views::CreateEmptyBorder(content_insets.top(), 0,
-                                     content_insets.bottom(), 0));
-  views::GridLayout* dialog_layout =
-      SetLayoutManager(std::make_unique<views::GridLayout>());
 
-  // Use GridLayout inside the prompt bar because StyledLabel requires it.
-  views::GridLayout* prompt_layout =
-      prompt_bar->SetLayoutManager(std::make_unique<views::GridLayout>());
-  prompt_bar->SetBorder(
-      views::CreateEmptyBorder(ChromeLayoutProvider::Get()->GetInsetsMetric(
-          views::INSETS_DIALOG_SUBSECTION)));
-  constexpr int kPromptBarColumnSetId = 0;
-  auto* prompt_columnset = prompt_layout->AddColumnSet(kPromptBarColumnSetId);
-  prompt_columnset->AddColumn(
-      views::GridLayout::FILL, views::GridLayout::CENTER,
-      views::GridLayout::kFixedSize,
-      views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
-  prompt_columnset->AddPaddingColumn(
-      views::GridLayout::kFixedSize,
-      ChromeLayoutProvider::Get()->GetDistanceMetric(
-          views::DISTANCE_TEXTFIELD_HORIZONTAL_TEXT_PADDING));
-  prompt_columnset->AddColumn(
-      views::GridLayout::FILL, views::GridLayout::CENTER, 1.0,
-      views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
-
-  prompt_layout->StartRow(views::GridLayout::kFixedSize, kPromptBarColumnSetId);
-  prompt_layout->AddView(std::move(business_icon));
-  prompt_layout->AddView(std::move(prompt_label));
-
-  // Use a column set with no padding.
-  dialog_layout->AddColumnSet(0)->AddColumn(
-      views::GridLayout::FILL, views::GridLayout::FILL, 1.0,
-      views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
-  dialog_layout->StartRow(views::GridLayout::kFixedSize, 0);
-  dialog_layout->AddView(std::move(prompt_bar), 1, 1, views::GridLayout::FILL,
-                         views::GridLayout::FILL, 0, 0);
-
-  // Use a new column set for the explanation label so we can add padding.
-  dialog_layout->AddPaddingRow(views::GridLayout::kFixedSize,
-                               content_insets.top());
-  constexpr int kExplanationColumnSetId = 1;
-  views::ColumnSet* explanation_columns =
-      dialog_layout->AddColumnSet(kExplanationColumnSetId);
-  explanation_columns->AddPaddingColumn(views::GridLayout::kFixedSize,
-                                        content_insets.left());
-  explanation_columns->AddColumn(
-      views::GridLayout::FILL, views::GridLayout::FILL, 1.0,
-      views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
-  explanation_columns->AddPaddingColumn(views::GridLayout::kFixedSize,
-                                        content_insets.right());
-  dialog_layout->StartRow(views::GridLayout::kFixedSize,
-                          kExplanationColumnSetId);
-  const int kPreferredWidth = 440;
-  int explanation_label_height =
-      explanation_label->GetHeightForWidth(kPreferredWidth);
-  dialog_layout->AddView(std::move(explanation_label), 1, 1,
-                         views::GridLayout::FILL, views::GridLayout::FILL,
-                         kPreferredWidth, explanation_label_height);
+  views::Builder<ProfileSigninConfirmationDialogViews>(this)
+      .SetBorder(views::CreateEmptyBorder(content_insets.top(), 0,
+                                          content_insets.bottom(), 0))
+      // Layout the components.
+      .SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kVertical, gfx::Insets(),
+          content_insets.top()))
+      .AddChildren(
+          views::Builder<views::BoxLayoutView>()
+              .SetOrientation(views::BoxLayout::Orientation::kHorizontal)
+              .SetBetweenChildSpacing(
+                  ChromeLayoutProvider::Get()->GetDistanceMetric(
+                      views::DISTANCE_TEXTFIELD_HORIZONTAL_TEXT_PADDING))
+              .SetBorder(views::CreateEmptyBorder(
+                  ChromeLayoutProvider::Get()->GetInsetsMetric(
+                      views::INSETS_DIALOG_SUBSECTION)))
+              .SetBackground(
+                  views::CreateSolidBackground(kPromptBarBackgroundColor))
+              .AddChildren(
+                  views::Builder<views::ImageView>().SetImage(
+                      gfx::CreateVectorIcon(gfx::IconDescription(
+                          vector_icons::kBusinessIcon, kBusinessIconSize,
+                          gfx::kChromeIconGrey))),
+                  views::Builder<views::StyledLabel>()
+                      .SetDisplayedOnBackgroundColor(kPromptBarBackgroundColor)
+                      .SetText(prompt_text)
+                      .AddStyleRange(gfx::Range(offset, offset + domain.size()),
+                                     bold_style)),
+          views::Builder<views::StyledLabel>()
+              .SetText(signin_explanation_text)
+              .AddStyleRange(
+                  gfx::Range(offsets[1], offsets[1] + learn_more_text.size()),
+                  views::StyledLabel::RangeStyleInfo::CreateForLink(
+                      base::BindRepeating(
+                          &ProfileSigninConfirmationDialogViews::
+                              LearnMoreClicked,
+                          base::Unretained(this))))
+              .SizeToFit(kPreferredWidth)
+              .SetProperty(views::kMarginsKey,
+                           gfx::Insets(0, content_insets.left(), 0,
+                                       content_insets.right())))
+      .BuildChildren();
 }
 
 void ProfileSigninConfirmationDialogViews::BuildWorkProfileView() {
   DCHECK(use_work_profile_wording_);
 
-  // Create the explanation label first row.
-  auto explanation_first_row = std::make_unique<views::Label>();
-  explanation_first_row->SetText(
-      l10n_util::GetStringUTF16(IDS_ENTERPRISE_SIGNIN_WORK_PROFILE_CREATION));
-  explanation_first_row->SetHorizontalAlignment(
-      gfx::HorizontalAlignment::ALIGN_LEFT);
-  explanation_first_row->SetMultiLine(true);
-
-  auto explanation_second_row = std::make_unique<views::Label>();
-  explanation_second_row->SetText(l10n_util::GetStringUTF16(
-      IDS_ENTERPRISE_SIGNIN_WORK_PROFILE_ISOLATION_NOTICE));
-  explanation_second_row->SetHorizontalAlignment(
-      gfx::HorizontalAlignment::ALIGN_LEFT);
-
-  // Create the explanation label.
+  // Define the explanation label text.
   size_t learn_more_offset;
   const std::u16string learn_more_text =
       l10n_util::GetStringUTF16(IDS_LEARN_MORE);
   const std::u16string signin_explanation_text =
       l10n_util::GetStringFUTF16(IDS_ENTERPRISE_SIGNIN_WORK_PROFILE_EXPLANATION,
                                  learn_more_text, &learn_more_offset);
-  auto explanation_label = std::make_unique<views::StyledLabel>();
-  explanation_label->SetText(signin_explanation_text);
-  explanation_label->AddStyleRange(
-      gfx::Range(learn_more_offset, learn_more_offset + learn_more_text.size()),
-      views::StyledLabel::RangeStyleInfo::CreateForLink(base::BindRepeating(
-          &ProfileSigninConfirmationDialogViews::LearnMoreClicked,
-          base::Unretained(this))));
-
-  // Layout the components.
   const gfx::Insets content_insets =
       views::LayoutProvider::Get()->GetDialogInsetsForContentType(
           views::DialogContentType::kControl, views::DialogContentType::kText);
-  // The prompt bar needs to go to the edge of the dialog, so remove horizontal
-  // insets.
-  SetBorder(views::CreateEmptyBorder(content_insets.top(), 0,
-                                     content_insets.bottom(), 0));
-  views::GridLayout* dialog_layout =
-      SetLayoutManager(std::make_unique<views::GridLayout>());
+  const gfx::Insets control_insets =
+      gfx::Insets(0, content_insets.left(), 0, content_insets.right());
 
-  // Use a new column set for the explanation label so we can add padding.
-  dialog_layout->AddPaddingRow(views::GridLayout::kFixedSize,
-                               content_insets.top());
-  constexpr int kExplanationColumnSetId = 1;
-  views::ColumnSet* explanation_columns =
-      dialog_layout->AddColumnSet(kExplanationColumnSetId);
-  explanation_columns->AddPaddingColumn(views::GridLayout::kFixedSize,
-                                        content_insets.left());
-  explanation_columns->AddColumn(
-      views::GridLayout::FILL, views::GridLayout::FILL, 1.0,
-      views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
-  explanation_columns->AddPaddingColumn(views::GridLayout::kFixedSize,
-                                        content_insets.right());
-  dialog_layout->StartRow(views::GridLayout::kFixedSize,
-                          kExplanationColumnSetId);
-  const int kPreferredWidth = 440;
-  int explanation_first_row_height =
-      explanation_first_row->GetHeightForWidth(kPreferredWidth);
-  int explanation_second_row_height =
-      explanation_second_row->GetHeightForWidth(kPreferredWidth);
-  int explanation_label_height =
-      explanation_label->GetHeightForWidth(kPreferredWidth);
-  dialog_layout->AddView(std::move(explanation_first_row), 1, 1,
-                         views::GridLayout::FILL, views::GridLayout::FILL,
-                         kPreferredWidth, explanation_first_row_height);
-  dialog_layout->StartRowWithPadding(views::GridLayout::kFixedSize,
-                                     kExplanationColumnSetId,
-                                     views::GridLayout::kFixedSize, 10);
-  dialog_layout->AddView(std::move(explanation_second_row), 1, 1,
-                         views::GridLayout::FILL, views::GridLayout::FILL,
-                         kPreferredWidth, explanation_second_row_height);
-  dialog_layout->StartRowWithPadding(views::GridLayout::kFixedSize,
-                                     kExplanationColumnSetId,
-                                     views::GridLayout::kFixedSize, 10);
-  dialog_layout->AddView(std::move(explanation_label), 1, 1,
-                         views::GridLayout::FILL, views::GridLayout::FILL,
-                         kPreferredWidth, explanation_label_height);
+  views::Builder<ProfileSigninConfirmationDialogViews>(this)
+      // The prompt bar needs to go to the edge of the dialog, so remove
+      // horizontal insets.
+      .SetBorder(views::CreateEmptyBorder(content_insets.top(), 0,
+                                          content_insets.bottom(), 0))
+      .SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kVertical,
+          gfx::Insets(content_insets.top(), 0, 0, 0), 10))
+      .AddChildren(
+          // Create the explanation label first row.
+          views::Builder<views::Label>()
+              .SetText(l10n_util::GetStringUTF16(
+                  IDS_ENTERPRISE_SIGNIN_WORK_PROFILE_CREATION))
+              .SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT)
+              .SetMultiLine(true)
+              .SizeToFit(kPreferredWidth)
+              .SetProperty(views::kMarginsKey, control_insets),
+          views::Builder<views::Label>()
+              .SetText(l10n_util::GetStringUTF16(
+                  IDS_ENTERPRISE_SIGNIN_WORK_PROFILE_ISOLATION_NOTICE))
+              .SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT)
+              .SetProperty(views::kMarginsKey, control_insets),
+          // Create the explanation label.
+          views::Builder<views::StyledLabel>()
+              .SetText(signin_explanation_text)
+              .AddStyleRange(
+                  gfx::Range(learn_more_offset,
+                             learn_more_offset + learn_more_text.size()),
+                  views::StyledLabel::RangeStyleInfo::CreateForLink(
+                      base::BindRepeating(
+                          &ProfileSigninConfirmationDialogViews::
+                              LearnMoreClicked,
+                          base::Unretained(this))))
+              .SizeToFit(kPreferredWidth)
+              .SetProperty(views::kMarginsKey, control_insets))
+      .BuildChildren();
 }
 
 void ProfileSigninConfirmationDialogViews::ContinueSigninButtonPressed() {
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
index dc97845..0057587 100644
--- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
+++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
@@ -7,9 +7,9 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h"
 #include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/views/metadata/view_factory.h"
 #include "ui/views/window/dialog_delegate.h"
 
 class Browser;
@@ -70,4 +70,11 @@
   const bool use_work_profile_wording_;
 };
 
+BEGIN_VIEW_BUILDER(,
+                   ProfileSigninConfirmationDialogViews,
+                   views::DialogDelegateView)
+END_VIEW_BUILDER
+
+DEFINE_VIEW_BUILDER(, ProfileSigninConfirmationDialogViews)
+
 #endif  // CHROME_BROWSER_UI_VIEWS_SYNC_PROFILE_SIGNIN_CONFIRMATION_DIALOG_VIEWS_H_
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc
index 19b9c756..03fbe3b 100644
--- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc
+++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -13,6 +14,7 @@
 #include "chrome/browser/ui/tab_dialogs.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "content/public/test/browser_test.h"
 
@@ -54,7 +56,23 @@
   }
 };
 
-// Test that calls ShowUi("true").
+class WorkProfileSigninConfirmationDialogTest
+    : public ProfileSigninConfirmationDialogTest {
+ public:
+  WorkProfileSigninConfirmationDialogTest() {
+    features_.InitAndEnableFeature(features::kSyncConfirmationUpdatedText);
+  }
+
+ private:
+  base::test::ScopedFeatureList features_;
+};
+
+// Test that calls ShowUi("default").
 IN_PROC_BROWSER_TEST_F(ProfileSigninConfirmationDialogTest, InvokeUi_default) {
   ShowAndVerifyUi();
 }
+
+IN_PROC_BROWSER_TEST_F(WorkProfileSigninConfirmationDialogTest,
+                       InvokeUi_default) {
+  ShowAndVerifyUi();
+}
diff --git a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.h b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.h
index 0c7fedd..9b72fc7 100644
--- a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.h
+++ b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "components/renderer_context_menu/context_menu_delegate.h"
 #include "content/public/browser/web_contents_view_delegate.h"
 
diff --git a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.h b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.h
index 1c857744..5072b7a 100644
--- a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.h
+++ b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/views/window/dialog_delegate.h"
diff --git a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.cc b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.cc
index e523993..6f0fc51c 100644
--- a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.cc
+++ b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.cc
@@ -243,21 +243,17 @@
 }
 
 void TabSharingUIViews::StartSharing(infobars::InfoBar* infobar) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (source_callback_.is_null())
     return;
 
-  SetContentsBorderVisible(shared_tab_, false);
-
   WebContents* shared_tab =
       infobars::ContentInfoBarManager::WebContentsFromInfoBar(infobar);
   DCHECK(shared_tab);
   DCHECK_EQ(infobars_[shared_tab], infobar);
-  shared_tab_ = shared_tab;
-  shared_tab_name_ = GetTabName(shared_tab_);
 
   RenderFrameHost* main_frame = shared_tab->GetMainFrame();
   DCHECK(main_frame);
-  RemoveInfobarsForAllTabs();
   source_callback_.Run(content::DesktopMediaID(
       content::DesktopMediaID::TYPE_WEB_CONTENTS,
       content::DesktopMediaID::kNullId,
diff --git a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc
index f43515f..f04bbca 100644
--- a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc
+++ b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc
@@ -325,9 +325,9 @@
   CreateUiAndStartSharing(browser(), /*capturing_tab=*/0, /*captured_tab=*/1);
 
   // Share a different tab.
+  // When switching tabs, a new UI is created, and the old one destroyed.
   ActivateTab(browser(), 2);
-  tab_sharing_ui_views()->StartSharing(
-      GetInfoBarManager(browser(), 2)->infobar_at(0));
+  CreateUiAndStartSharing(browser(), /*capturing_tab=*/0, /*captured_tab=*/2);
 
   // Test that the UI has been updated.
   VerifyUi(browser(), /*capturing_tab=*/0, /*captured_tab=*/2);
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
index 1887d34a..60e5d75 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/tabs/hover_tab_selector.h"
 #include "chrome/browser/ui/tabs/tab_menu_model_factory.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
index 292312e..3106cac 100644
--- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_types.h"
 #include "components/tab_groups/tab_group_id.h"
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index 28ab5dd..4049255 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -10,7 +10,6 @@
 #include <utility>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
diff --git a/chrome/browser/ui/views/toolbar/home_button.h b/chrome/browser/ui/views/toolbar/home_button.h
index 7a604e71..4d062240 100644
--- a/chrome/browser/ui/views/toolbar/home_button.h
+++ b/chrome/browser/ui/views/toolbar/home_button.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_TOOLBAR_HOME_BUTTON_H_
 #define CHROME_BROWSER_UI_VIEWS_TOOLBAR_HOME_BUTTON_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/metadata/view_factory.h"
diff --git a/chrome/browser/ui/views/toolbar/read_later_toolbar_button.cc b/chrome/browser/ui/views/toolbar/side_panel_toolbar_button.cc
similarity index 92%
rename from chrome/browser/ui/views/toolbar/read_later_toolbar_button.cc
rename to chrome/browser/ui/views/toolbar/side_panel_toolbar_button.cc
index e1d2b7f..31bac5e5 100644
--- a/chrome/browser/ui/views/toolbar/read_later_toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/side_panel_toolbar_button.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/toolbar/read_later_toolbar_button.h"
+#include "chrome/browser/ui/views/toolbar/side_panel_toolbar_button.h"
 
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
@@ -166,8 +166,8 @@
 
 }  // namespace
 
-ReadLaterToolbarButton::ReadLaterToolbarButton(Browser* browser)
-    : ToolbarButton(base::BindRepeating(&ReadLaterToolbarButton::ButtonPressed,
+SidePanelToolbarButton::SidePanelToolbarButton(Browser* browser)
+    : ToolbarButton(base::BindRepeating(&SidePanelToolbarButton::ButtonPressed,
                                         base::Unretained(this))),
       browser_(browser),
       dot_indicator_(views::DotIndicator::Install(image())),
@@ -186,18 +186,18 @@
     reading_list_model_scoped_observation_.Observe(reading_list_model_);
 }
 
-ReadLaterToolbarButton::~ReadLaterToolbarButton() = default;
+SidePanelToolbarButton::~SidePanelToolbarButton() = default;
 
-ReadLaterToolbarButton::DotBoundsUpdater::DotBoundsUpdater(
+SidePanelToolbarButton::DotBoundsUpdater::DotBoundsUpdater(
     views::DotIndicator* dot_indicator,
     views::ImageView* image)
     : dot_indicator_(dot_indicator), image_(image) {
   observation_.Observe(image);
 }
 
-ReadLaterToolbarButton::DotBoundsUpdater::~DotBoundsUpdater() = default;
+SidePanelToolbarButton::DotBoundsUpdater::~DotBoundsUpdater() = default;
 
-void ReadLaterToolbarButton::DotBoundsUpdater::OnViewBoundsChanged(
+void SidePanelToolbarButton::DotBoundsUpdater::OnViewBoundsChanged(
     View* observed_view) {
   gfx::Rect dot_rect(8, 8);
   if (ui::TouchUiController::Get()->touch_ui()) {
@@ -209,13 +209,13 @@
   dot_indicator_->SetBoundsRect(dot_rect);
 }
 
-void ReadLaterToolbarButton::ReadingListModelLoaded(
+void SidePanelToolbarButton::ReadingListModelLoaded(
     const ReadingListModel* model) {
   if (model->unseen_size())
     dot_indicator_->Show();
 }
 
-void ReadLaterToolbarButton::ReadingListModelBeingDeleted(
+void SidePanelToolbarButton::ReadingListModelBeingDeleted(
     const ReadingListModel* model) {
   DCHECK(model == reading_list_model_);
   DCHECK(reading_list_model_scoped_observation_.IsObservingSource(
@@ -223,7 +223,7 @@
   reading_list_model_scoped_observation_.Reset();
 }
 
-void ReadLaterToolbarButton::ReadingListDidApplyChanges(
+void SidePanelToolbarButton::ReadingListDidApplyChanges(
     ReadingListModel* model) {
   if (!side_panel_webview_ && reading_list_model_->unseen_size() > 0) {
     dot_indicator_->Show();
@@ -232,7 +232,7 @@
   }
 }
 
-void ReadLaterToolbarButton::ButtonPressed() {
+void SidePanelToolbarButton::ButtonPressed() {
   BrowserView* const browser_view =
       BrowserView::GetBrowserViewForBrowser(browser_);
   DCHECK(browser_view->right_aligned_side_panel());
@@ -250,9 +250,9 @@
 
     // Using base::Unretained(this) is safe here because the side panel (and the
     // web view as its child) will be destroyed before the toolbar which will
-    // destroy the ReadLaterToolbarButton.
+    // destroy the SidePanelToolbarButton.
     auto webview = std::make_unique<ReadLaterSidePanelWebView>(
-        browser_, base::BindRepeating(&ReadLaterToolbarButton::ButtonPressed,
+        browser_, base::BindRepeating(&SidePanelToolbarButton::ButtonPressed,
                                       base::Unretained(this)));
     side_panel_webview_ =
         browser_view->right_aligned_side_panel()->AddChildView(
@@ -265,7 +265,7 @@
   }
 }
 
-void ReadLaterToolbarButton::HideSidePanel() {
+void SidePanelToolbarButton::HideSidePanel() {
   BrowserView* const browser_view =
       BrowserView::GetBrowserViewForBrowser(browser_);
   DCHECK(browser_view->right_aligned_side_panel());
@@ -277,6 +277,6 @@
   }
 }
 
-bool ReadLaterToolbarButton::ShouldShowInkdropAfterIphInteraction() {
+bool SidePanelToolbarButton::ShouldShowInkdropAfterIphInteraction() {
   return false;
 }
diff --git a/chrome/browser/ui/views/toolbar/read_later_toolbar_button.h b/chrome/browser/ui/views/toolbar/side_panel_toolbar_button.h
similarity index 84%
rename from chrome/browser/ui/views/toolbar/read_later_toolbar_button.h
rename to chrome/browser/ui/views/toolbar/side_panel_toolbar_button.h
index 0334303..83731f4 100644
--- a/chrome/browser/ui/views/toolbar/read_later_toolbar_button.h
+++ b/chrome/browser/ui/views/toolbar/side_panel_toolbar_button.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_VIEWS_TOOLBAR_READ_LATER_TOOLBAR_BUTTON_H_
-#define CHROME_BROWSER_UI_VIEWS_TOOLBAR_READ_LATER_TOOLBAR_BUTTON_H_
+#ifndef CHROME_BROWSER_UI_VIEWS_TOOLBAR_SIDE_PANEL_TOOLBAR_BUTTON_H_
+#define CHROME_BROWSER_UI_VIEWS_TOOLBAR_SIDE_PANEL_TOOLBAR_BUTTON_H_
 
 #include "base/scoped_observation.h"
 #include "chrome/browser/ui/views/bubble/bubble_contents_wrapper.h"
@@ -15,13 +15,13 @@
 
 class Browser;
 
-class ReadLaterToolbarButton : public ToolbarButton,
+class SidePanelToolbarButton : public ToolbarButton,
                                public ReadingListModelObserver {
  public:
-  explicit ReadLaterToolbarButton(Browser* browser);
-  ReadLaterToolbarButton(const ReadLaterToolbarButton&) = delete;
-  ReadLaterToolbarButton& operator=(const ReadLaterToolbarButton&) = delete;
-  ~ReadLaterToolbarButton() override;
+  explicit SidePanelToolbarButton(Browser* browser);
+  SidePanelToolbarButton(const SidePanelToolbarButton&) = delete;
+  SidePanelToolbarButton& operator=(const SidePanelToolbarButton&) = delete;
+  ~SidePanelToolbarButton() override;
 
   // ToolbarButton
   bool ShouldShowInkdropAfterIphInteraction() override;
@@ -75,4 +75,4 @@
   views::View* side_panel_webview_ = nullptr;
 };
 
-#endif  // CHROME_BROWSER_UI_VIEWS_TOOLBAR_READ_LATER_TOOLBAR_BUTTON_H_
+#endif  // CHROME_BROWSER_UI_VIEWS_TOOLBAR_SIDE_PANEL_TOOLBAR_BUTTON_H_
diff --git a/chrome/browser/ui/views/toolbar/read_later_toolbar_button_unittest.cc b/chrome/browser/ui/views/toolbar/side_panel_toolbar_button_unittest.cc
similarity index 86%
rename from chrome/browser/ui/views/toolbar/read_later_toolbar_button_unittest.cc
rename to chrome/browser/ui/views/toolbar/side_panel_toolbar_button_unittest.cc
index bc08104..071ef0b 100644
--- a/chrome/browser/ui/views/toolbar/read_later_toolbar_button_unittest.cc
+++ b/chrome/browser/ui/views/toolbar/side_panel_toolbar_button_unittest.cc
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/toolbar/read_later_toolbar_button.h"
+#include "chrome/browser/ui/views/toolbar/side_panel_toolbar_button.h"
+
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ui/read_later/read_later_test_utils.h"
 #include "chrome/browser/ui/read_later/reading_list_model_factory.h"
@@ -14,7 +15,7 @@
 #include "ui/events/event_utils.h"
 #include "ui/views/test/button_test_api.h"
 
-class ReadLaterToolbarButtonTest : public TestWithBrowserView {
+class SidePanelToolbarButtonTest : public TestWithBrowserView {
  public:
   void SetUp() override {
     scoped_feature_list_.InitAndEnableFeature(features::kSidePanel);
@@ -33,9 +34,8 @@
     return factories;
   }
 
-  ReadLaterToolbarButton* GetReadLaterToolbarButton() {
-    return browser_view()->toolbar()->read_later_button();
-    ;
+  SidePanelToolbarButton* GetSidePanelToolbarButton() {
+    return browser_view()->toolbar()->side_panel_button();
   }
 
   ReadingListModel* model() { return model_; }
@@ -45,11 +45,11 @@
   ReadingListModel* model_;
 };
 
-TEST_F(ReadLaterToolbarButtonTest, DotIndicatorVisibleWithUnreadItems) {
+TEST_F(SidePanelToolbarButtonTest, DotIndicatorVisibleWithUnreadItems) {
   // Verify the dot indicator is seen when there is an unseen entry.
   model()->AddEntry(GURL("http://foo/1"), "Tab 1",
                     reading_list::EntrySource::ADDED_VIA_CURRENT_APP);
-  ReadLaterToolbarButton* const side_panel_button = GetReadLaterToolbarButton();
+  SidePanelToolbarButton* const side_panel_button = GetSidePanelToolbarButton();
   ASSERT_TRUE(side_panel_button->GetDotIndicatorVisibilityForTesting());
 
   // Verify the dot indicator is hidden once the toolbar button is clicked.
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index fcfa920..5e0b824 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -62,8 +62,8 @@
 #include "chrome/browser/ui/views/toolbar/chrome_labs_button.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_utils.h"
 #include "chrome/browser/ui/views/toolbar/home_button.h"
-#include "chrome/browser/ui/views/toolbar/read_later_toolbar_button.h"
 #include "chrome/browser/ui/views/toolbar/reload_button.h"
+#include "chrome/browser/ui/views/toolbar/side_panel_toolbar_button.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_account_icon_container_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
@@ -293,10 +293,10 @@
         std::make_unique<ToolbarAccountIconContainerView>(browser_view_);
   }
 
-  std::unique_ptr<ReadLaterToolbarButton> read_later_button;
+  std::unique_ptr<SidePanelToolbarButton> side_panel_button;
   if (browser_view_->right_aligned_side_panel() &&
       reading_list::switches::IsReadingListEnabled()) {
-    read_later_button = std::make_unique<ReadLaterToolbarButton>(browser_);
+    side_panel_button = std::make_unique<SidePanelToolbarButton>(browser_);
   }
 
   // Always add children in order from left to right, for accessibility.
@@ -354,8 +354,8 @@
   if (send_tab_to_self_button)
     send_tab_to_self_button_ = AddChildView(std::move(send_tab_to_self_button));
 
-  if (read_later_button)
-    read_later_button_ = AddChildView(std::move(read_later_button));
+  if (side_panel_button)
+    side_panel_button_ = AddChildView(std::move(side_panel_button));
 
   if (toolbar_account_icon_container) {
     toolbar_account_icon_container_ =
@@ -885,8 +885,8 @@
       can_show_bubble);
 }
 
-ReadLaterToolbarButton* ToolbarView::GetSidePanelButton() {
-  return read_later_button_;
+SidePanelToolbarButton* ToolbarView::GetSidePanelButton() {
+  return side_panel_button_;
 }
 
 AvatarToolbarButton* ToolbarView::GetAvatarToolbarButton() {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h
index 1da8e4f4..2f32d3b 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -21,7 +21,7 @@
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/profiles/avatar_toolbar_button.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
-#include "chrome/browser/ui/views/toolbar/read_later_toolbar_button.h"
+#include "chrome/browser/ui/views/toolbar/side_panel_toolbar_button.h"
 #include "chrome/browser/upgrade_detector/upgrade_observer.h"
 #include "components/prefs/pref_member.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -152,8 +152,8 @@
   LocationBarView* location_bar() const { return location_bar_; }
   CustomTabBarView* custom_tab_bar() { return custom_tab_bar_; }
   media_router::CastToolbarButton* cast_button() const { return cast_; }
-  ReadLaterToolbarButton* read_later_button() const {
-    return read_later_button_;
+  SidePanelToolbarButton* side_panel_button() const {
+    return side_panel_button_;
   }
   MediaToolbarButtonView* media_button() const { return media_button_; }
   send_tab_to_self::SendTabToSelfToolbarIconView* send_tab_to_self_button()
@@ -236,7 +236,7 @@
   views::AccessiblePaneView* GetAsAccessiblePaneView() override;
   views::View* GetAnchorView(PageActionIconType type) override;
   void ZoomChangedForActiveTab(bool can_show_bubble) override;
-  ReadLaterToolbarButton* GetSidePanelButton() override;
+  SidePanelToolbarButton* GetSidePanelButton() override;
   AvatarToolbarButton* GetAvatarToolbarButton() override;
   ToolbarButton* GetBackButton() override;
   ReloadButton* GetReloadButton() override;
@@ -278,7 +278,7 @@
   ExtensionsToolbarContainer* extensions_container_ = nullptr;
   ChromeLabsButton* chrome_labs_button_ = nullptr;
   media_router::CastToolbarButton* cast_ = nullptr;
-  ReadLaterToolbarButton* read_later_button_ = nullptr;
+  SidePanelToolbarButton* side_panel_button_ = nullptr;
   ToolbarAccountIconContainerView* toolbar_account_icon_container_ = nullptr;
   AvatarToolbarButton* avatar_ = nullptr;
   MediaToolbarButtonView* media_button_ = nullptr;
diff --git a/chrome/browser/ui/views/uninstall_view.h b/chrome/browser/ui/views/uninstall_view.h
index 1079d05..fd40fc11 100644
--- a/chrome/browser/ui/views/uninstall_view.h
+++ b/chrome/browser/ui/views/uninstall_view.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/base/models/combobox_model.h"
 #include "ui/views/window/dialog_delegate.h"
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.cc b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.cc
index 84139156..b17578d 100644
--- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.cc
+++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.cc
@@ -235,7 +235,7 @@
       can_show_bubble);
 }
 
-ReadLaterToolbarButton* WebAppFrameToolbarView::GetSidePanelButton() {
+SidePanelToolbarButton* WebAppFrameToolbarView::GetSidePanelButton() {
   return nullptr;
 }
 
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.h b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.h
index 80a48cc..983c788 100644
--- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.h
+++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.h
@@ -74,7 +74,7 @@
   views::AccessiblePaneView* GetAsAccessiblePaneView() override;
   views::View* GetAnchorView(PageActionIconType type) override;
   void ZoomChangedForActiveTab(bool can_show_bubble) override;
-  ReadLaterToolbarButton* GetSidePanelButton() override;
+  SidePanelToolbarButton* GetSidePanelButton() override;
   AvatarToolbarButton* GetAvatarToolbarButton() override;
   ToolbarButton* GetBackButton() override;
   ReloadButton* GetReloadButton() override;
diff --git a/chrome/browser/ui/web_applications/web_app_browsertest.cc b/chrome/browser/ui/web_applications/web_app_browsertest.cc
index 19354e2e..ba8c06a 100644
--- a/chrome/browser/ui/web_applications/web_app_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_browsertest.cc
@@ -809,7 +809,13 @@
 }
 
 // Tests that PWA menus have an uninstall option.
-IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, UninstallMenuOption) {
+// TODO(crbug.com/1271118): Flaky on mac arm64.
+#if defined(OS_MAC) && defined(ARCH_CPU_ARM64)
+#define MAYBE_UninstallMenuOption DISABLED_UninstallMenuOption
+#else
+#define MAYBE_UninstallMenuOption UninstallMenuOption
+#endif
+IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, MAYBE_UninstallMenuOption) {
   const GURL app_url = GetSecureAppURL();
   const AppId app_id = InstallPWA(app_url);
   Browser* const app_browser = LaunchWebAppBrowserAndWait(app_id);
@@ -1801,7 +1807,13 @@
   base::test::ScopedFeatureList feature_list_;
 };
 
-IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_FileHandler, WebAppFileHandler) {
+// TODO(crbug.com/1270961): Flaky.
+#if defined(OS_WIN) || (defined(OS_MAC) && defined(ARCH_CPU_ARM64))
+#define MAYBE_WebAppFileHandler DISABLED_WebAppFileHandler
+#else
+#define MAYBE_WebAppFileHandler WebAppFileHandler
+#endif
+IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_FileHandler, MAYBE_WebAppFileHandler) {
   os_hooks_suppress_.reset();
   base::ScopedAllowBlockingForTesting allow_blocking;
 
diff --git a/chrome/browser/ui/web_applications/web_app_launch_process.cc b/chrome/browser/ui/web_applications/web_app_launch_process.cc
index 80a595c..f45a49e 100644
--- a/chrome/browser/ui/web_applications/web_app_launch_process.cc
+++ b/chrome/browser/ui/web_applications/web_app_launch_process.cc
@@ -125,9 +125,7 @@
 const apps::ShareTarget* WebAppLaunchProcess::MaybeGetShareTarget() const {
   DCHECK(web_app_);
   bool is_share_intent =
-      params_.intent &&
-      (params_.intent->action == apps_util::kIntentActionSend ||
-       params_.intent->action == apps_util::kIntentActionSendMultiple);
+      params_.intent && apps_util::IsShareIntent(params_.intent);
   return is_share_intent && web_app_->share_target().has_value()
              ? &web_app_->share_target().value()
              : nullptr;
diff --git a/chrome/browser/ui/webui/about_ui.h b/chrome/browser/ui/webui/about_ui.h
index a033545..07c8e64c 100644
--- a/chrome/browser/ui/webui/about_ui.h
+++ b/chrome/browser/ui/webui/about_ui.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_ui_controller.h"
 
diff --git a/chrome/browser/ui/webui/browser_switch/browser_switch_ui.cc b/chrome/browser/ui/webui/browser_switch/browser_switch_ui.cc
index 95f80ed..5cb271f 100644
--- a/chrome/browser/ui/webui/browser_switch/browser_switch_ui.cc
+++ b/chrome/browser/ui/webui/browser_switch/browser_switch_ui.cc
@@ -240,6 +240,10 @@
   // Immediately re-download and apply XML rules.
   void HandleRefreshXml(const base::ListValue* args);
 
+  // Resolves a promise with the boolean value describing whether the feature
+  // is enabled or not which is configured by BrowserSwitcherEnabled key
+  void HandleIsBrowserSwitchEnabled(const base::ListValue* args);
+
   base::CallbackListSubscription prefs_subscription_;
 
   base::CallbackListSubscription service_subscription_;
@@ -280,6 +284,10 @@
   web_ui()->RegisterDeprecatedMessageCallback(
       "refreshXml", base::BindRepeating(&BrowserSwitchHandler::HandleRefreshXml,
                                         base::Unretained(this)));
+  web_ui()->RegisterDeprecatedMessageCallback(
+      "isBrowserSwitcherEnabled",
+      base::BindRepeating(&BrowserSwitchHandler::HandleIsBrowserSwitchEnabled,
+                          base::Unretained(this)));
 }
 
 void BrowserSwitchHandler::OnJavascriptAllowed() {
@@ -482,6 +490,16 @@
   service->StartDownload(base::TimeDelta());
 }
 
+void BrowserSwitchHandler::HandleIsBrowserSwitchEnabled(
+    const base::ListValue* args) {
+  DCHECK(args);
+  AllowJavascript();
+
+  auto* service = GetBrowserSwitcherService(web_ui());
+  ResolveJavascriptCallback(args->GetList()[0],
+                            base::Value(service->prefs().IsEnabled()));
+}
+
 BrowserSwitchUI::BrowserSwitchUI(content::WebUI* web_ui)
     : WebUIController(web_ui) {
   web_ui->AddMessageHandler(std::make_unique<BrowserSwitchHandler>());
diff --git a/chrome/browser/ui/webui/certificate_viewer_webui.h b/chrome/browser/ui/webui/certificate_viewer_webui.h
index e25d5aa..70cc1c95 100644
--- a/chrome/browser/ui/webui/certificate_viewer_webui.h
+++ b/chrome/browser/ui/webui/certificate_viewer_webui.h
@@ -8,7 +8,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/values.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "net/cert/scoped_nss_types.h"
diff --git a/chrome/browser/ui/webui/certificates_handler.h b/chrome/browser/ui/webui/certificates_handler.h
index cb51090..3bdebe54 100644
--- a/chrome/browser/ui/webui/certificates_handler.h
+++ b/chrome/browser/ui/webui/certificates_handler.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/containers/id_map.h"
 #include "base/memory/weak_ptr.h"
 #include "base/task/cancelable_task_tracker.h"
diff --git a/chrome/browser/ui/webui/chrome_web_contents_handler.h b/chrome/browser/ui/webui/chrome_web_contents_handler.h
index 5928fd5..ffcb4289 100644
--- a/chrome/browser/ui/webui/chrome_web_contents_handler.h
+++ b/chrome/browser/ui/webui/chrome_web_contents_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_CHROME_WEB_CONTENTS_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_CHROME_WEB_CONTENTS_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "ui/web_dialogs/web_dialog_web_contents_delegate.h"
 
 class ChromeWebContentsHandler
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 6bcd8eb..da0de68 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
 
 #include <stddef.h>
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
@@ -198,6 +199,7 @@
 #include "chrome/browser/ash/scanning/chrome_scanning_app_delegate.h"
 #include "chrome/browser/ash/scanning/scan_service.h"
 #include "chrome/browser/ash/scanning/scan_service_factory.h"
+#include "chrome/browser/ash/shimless_rma/chrome_shimless_rma_delegate.h"
 #include "chrome/browser/ash/web_applications/camera_app/chrome_camera_app_ui_delegate.h"
 #include "chrome/browser/ash/web_applications/chrome_file_manager_ui_delegate.h"
 #include "chrome/browser/ash/web_applications/help_app/help_app_ui_delegate.h"
@@ -496,6 +498,13 @@
 }
 
 template <>
+WebUIController* NewWebUI<ash::ShimlessRMADialogUI>(WebUI* web_ui,
+                                                    const GURL& url) {
+  return new ash::ShimlessRMADialogUI(
+      web_ui, std::make_unique<ash::shimless_rma::ChromeShimlessRmaDelegate>());
+}
+
+template <>
 WebUIController* NewWebUI<ash::DiagnosticsDialogUI>(WebUI* web_ui,
                                                     const GURL& url) {
   ash::HoldingSpaceKeyedService* holding_space_keyed_service =
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.cc b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.cc
new file mode 100644
index 0000000..fe10869e
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.cc
@@ -0,0 +1,127 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "ash/public/cpp/network_config_service.h"
+#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "chrome/browser/ash/login/saml/in_session_password_sync_manager.h"
+#include "chrome/browser/ash/login/saml/in_session_password_sync_manager_factory.h"
+#include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/extensions/tab_helper.h"
+#include "chrome/browser/ui/webui/chromeos/internet_config_dialog.h"
+#include "chrome/browser/ui/webui/chromeos/internet_detail_dialog.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/grit/browser_resources.h"
+#include "chrome/grit/generated_resources.h"
+#include "chromeos/strings/grit/chromeos_strings.h"
+#include "components/user_manager/user_manager.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "content/public/browser/web_ui_message_handler.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/chromeos/devicetype_utils.h"
+#include "ui/chromeos/strings/network_element_localized_strings_provider.h"
+
+namespace chromeos {
+
+namespace {
+
+constexpr char kInitialize[] = "initialize";
+constexpr char kAddNetwork[] = "addNetwork";
+constexpr char kShowNetworkDetails[] = "showNetworkDetails";
+constexpr char kShowNetworkConfig[] = "showNetworkConfig";
+constexpr char kGetHostname[] = "getHostname";
+
+InSessionPasswordSyncManager* GetInSessionPasswordSyncManager() {
+  const user_manager::User* user =
+      user_manager::UserManager::Get()->GetActiveUser();
+  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+
+  return InSessionPasswordSyncManagerFactory::GetForProfile(profile);
+}
+
+}  // namespace
+
+NetworkConfigMessageHandler::NetworkConfigMessageHandler() {}
+
+NetworkConfigMessageHandler::~NetworkConfigMessageHandler() = default;
+
+void NetworkConfigMessageHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      kInitialize, base::BindRepeating(&NetworkConfigMessageHandler::Initialize,
+                                       weak_ptr_factory_.GetWeakPtr()));
+  web_ui()->RegisterMessageCallback(
+      kAddNetwork, base::BindRepeating(&NetworkConfigMessageHandler::AddNetwork,
+                                       weak_ptr_factory_.GetWeakPtr()));
+  web_ui()->RegisterMessageCallback(
+      kShowNetworkDetails,
+      base::BindRepeating(&NetworkConfigMessageHandler::ShowNetworkDetails,
+                          weak_ptr_factory_.GetWeakPtr()));
+  web_ui()->RegisterMessageCallback(
+      kShowNetworkConfig,
+      base::BindRepeating(&NetworkConfigMessageHandler::ShowNetworkConfig,
+                          weak_ptr_factory_.GetWeakPtr()));
+  web_ui()->RegisterMessageCallback(
+      kGetHostname,
+      base::BindRepeating(&NetworkConfigMessageHandler::GetHostname,
+                          weak_ptr_factory_.GetWeakPtr()));
+}
+
+void NetworkConfigMessageHandler::Initialize(base::Value::ConstListView args) {
+  AllowJavascript();
+
+  // Notify the main dialog that the network dialog has been loaded.
+  auto* password_sync_manager = GetInSessionPasswordSyncManager();
+  password_sync_manager->get_reauth_dialog_for_testing()
+      ->OnNetworkDialogReadyForTesting();
+}
+
+void NetworkConfigMessageHandler::ShowNetworkDetails(
+    base::Value::ConstListView args) {
+  CHECK_EQ(1u, args.size());
+  std::string guid = args[0].GetString();
+
+  InternetDetailDialog::ShowDialog(guid);
+}
+
+void NetworkConfigMessageHandler::ShowNetworkConfig(
+    base::Value::ConstListView args) {
+  CHECK_EQ(1u, args.size());
+  std::string guid = args[0].GetString();
+
+  InternetConfigDialog::ShowDialogForNetworkId(guid);
+}
+
+void NetworkConfigMessageHandler::AddNetwork(base::Value::ConstListView args) {
+  CHECK_EQ(1u, args.size());
+  std::string onc_type = args[0].GetString();
+
+  InternetConfigDialog::ShowDialogForNetworkType(onc_type);
+}
+
+void NetworkConfigMessageHandler::GetHostname(base::Value::ConstListView args) {
+  CHECK_EQ(1u, args.size());
+  std::string callback_id = args[0].GetString();
+  std::string hostname =
+      NetworkHandler::Get()->network_state_handler()->hostname();
+  Respond(callback_id, base::Value(hostname));
+}
+
+void NetworkConfigMessageHandler::Respond(const std::string& callback_id,
+                                          const base::Value& response) {
+  AllowJavascript();
+  ResolveJavascriptCallback(base::Value(callback_id), response);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.h b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.h
new file mode 100644
index 0000000..24606fc
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.h
@@ -0,0 +1,36 @@
+
+// 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_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_HANDLER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+namespace chromeos {
+
+class NetworkConfigMessageHandler : public content::WebUIMessageHandler {
+ public:
+  explicit NetworkConfigMessageHandler();
+  ~NetworkConfigMessageHandler() override;
+
+  // WebUIMessageHandler implementation.
+  void RegisterMessages() override;
+
+ private:
+  void Initialize(base::Value::ConstListView args);
+  void ShowNetworkDetails(base::Value::ConstListView args);
+  void ShowNetworkConfig(base::Value::ConstListView args);
+  void AddNetwork(base::Value::ConstListView args);
+  void GetHostname(base::Value::ConstListView args);
+  void Respond(const std::string& callback_id, const base::Value& response);
+
+  base::WeakPtrFactory<NetworkConfigMessageHandler> weak_ptr_factory_{this};
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.cc b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.cc
index 3b58d225..32d43b0 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/ash/login/saml/in_session_password_sync_manager_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/extensions/tab_helper.h"
+#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.h"
 #include "chrome/browser/ui/webui/chromeos/internet_config_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/internet_detail_dialog.h"
 #include "chrome/common/url_constants.h"
@@ -35,63 +36,6 @@
 
 namespace chromeos {
 
-namespace {
-
-constexpr char kAddNetwork[] = "addNetwork";
-constexpr char kShowNetworkDetails[] = "showNetworkDetails";
-constexpr char kShowNetworkConfig[] = "showNetworkConfig";
-
-class NetworkConfigMessageHandler : public content::WebUIMessageHandler {
- public:
-  NetworkConfigMessageHandler() {}
-  NetworkConfigMessageHandler(NetworkConfigMessageHandler const&) = delete;
-  NetworkConfigMessageHandler& operator=(const NetworkConfigMessageHandler&) =
-      delete;
-  ~NetworkConfigMessageHandler() override {}
-
-  // WebUIMessageHandler implementation.
-  void RegisterMessages() override {
-    web_ui()->RegisterDeprecatedMessageCallback(
-        kAddNetwork,
-        base::BindRepeating(&NetworkConfigMessageHandler::AddNetwork,
-                            base::Unretained(this)));
-    web_ui()->RegisterDeprecatedMessageCallback(
-        kShowNetworkDetails,
-        base::BindRepeating(&NetworkConfigMessageHandler::ShowNetworkDetails,
-                            base::Unretained(this)));
-    web_ui()->RegisterDeprecatedMessageCallback(
-        kShowNetworkConfig,
-        base::BindRepeating(&NetworkConfigMessageHandler::ShowNetworkConfig,
-                            base::Unretained(this)));
-  }
-
- private:
-  void ShowNetworkDetails(const base::ListValue* arg_list) {
-    CHECK_EQ(1u, arg_list->GetList().size());
-    std::string guid = arg_list->GetList()[0].GetString();
-
-    InternetDetailDialog::ShowDialog(guid);
-  }
-
-  void ShowNetworkConfig(const base::ListValue* arg_list) {
-    CHECK_EQ(1u, arg_list->GetList().size());
-    std::string guid = arg_list->GetList()[0].GetString();
-
-    InternetConfigDialog::ShowDialogForNetworkId(guid);
-  }
-
-  void AddNetwork(const base::ListValue* args) {
-    CHECK_EQ(1u, args->GetList().size());
-    std::string onc_type = args->GetList()[0].GetString();
-
-    InternetConfigDialog::ShowDialogForNetworkType(onc_type);
-  }
-
-  base::WeakPtrFactory<NetworkConfigMessageHandler> weak_ptr_factory_{this};
-};
-
-}  // namespace
-
 // static
 void LockScreenNetworkUI::GetLocalizedStrings(
     base::DictionaryValue* localized_strings) {
@@ -111,7 +55,9 @@
 
 LockScreenNetworkUI::LockScreenNetworkUI(content::WebUI* web_ui)
     : ui::MojoWebDialogUI(web_ui) {
-  web_ui->AddMessageHandler(std::make_unique<NetworkConfigMessageHandler>());
+  auto main_handler = std::make_unique<NetworkConfigMessageHandler>();
+  main_handler_ = main_handler.get();
+  web_ui->AddMessageHandler(std::move(main_handler));
 
   base::DictionaryValue localized_strings;
   GetLocalizedStrings(&localized_strings);
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h
index f86344f..12c8573d 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h
+++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h
@@ -5,7 +5,9 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_UI_H_
 #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_UI_H_
 
+#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h"
+
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "ui/web_dialogs/web_dialog_ui.h"
 #include "ui/webui/mojo_web_ui_controller.h"
@@ -20,8 +22,6 @@
 class LockScreenNetworkUI : public ui::MojoWebDialogUI {
  public:
   explicit LockScreenNetworkUI(content::WebUI* web_ui);
-  LockScreenNetworkUI(LockScreenNetworkUI const&) = delete;
-  LockScreenNetworkUI& operator=(const LockScreenNetworkUI&) = delete;
   ~LockScreenNetworkUI() override;
 
   void GetLocalizedStrings(base::DictionaryValue* localized_strings);
@@ -31,7 +31,14 @@
   void BindInterface(
       mojo::PendingReceiver<network_config::mojom::CrosNetworkConfig> receiver);
 
+  NetworkConfigMessageHandler* GetMainHandlerForTests() {
+    return main_handler_;
+  }
+
  private:
+  // The main message handler owned by the corresponding WebUI.
+  NetworkConfigMessageHandler* main_handler_;
+
   WEB_UI_CONTROLLER_TYPE_DECL();
 };
 
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.cc b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.cc
index a93cad87..f211a7f 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.cc
+++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.cc
@@ -69,7 +69,8 @@
     g_dialog->ShowSystemDialogForBrowserContext(
         profile->GetPrimaryOTRProfile(/*create_if_needed=*/true));
     // Show network screen if needed.
-    if (!network_state_helper_->IsConnected()) {
+    // TODO(mslus): Handle other states in NetworkStateInformer properly.
+    if (network_state_informer_->state() == NetworkStateInformer::OFFLINE) {
       ShowLockScreenNetworkDialog();
     }
   } else if (status != Profile::CREATE_STATUS_CREATED) {
@@ -105,55 +106,77 @@
   return ret.width();
 }
 
-void LockScreenStartReauthDialog::CloseLockScreenNetworkDialog() {
+void LockScreenStartReauthDialog::DeleteLockScreenNetworkDialog() {
+  is_network_dialog_visible_ = false;
   if (!lock_screen_network_dialog_)
     return;
   lock_screen_network_dialog_.reset();
 }
 
+void LockScreenStartReauthDialog::DismissLockScreenNetworkDialog() {
+  if (lock_screen_network_dialog_)
+    lock_screen_network_dialog_->Dismiss();
+}
+
 void LockScreenStartReauthDialog::ShowLockScreenNetworkDialog() {
   if (lock_screen_network_dialog_)
     return;
   DCHECK(profile_);
+  is_network_dialog_visible_ = true;
   lock_screen_network_dialog_ =
       std::make_unique<chromeos::LockScreenNetworkDialog>(base::BindOnce(
-          &LockScreenStartReauthDialog::CloseLockScreenNetworkDialog,
+          &LockScreenStartReauthDialog::DeleteLockScreenNetworkDialog,
           base::Unretained(this)));
   lock_screen_network_dialog_->Show(profile_);
 }
 
+bool LockScreenStartReauthDialog::IsNetworkDialogLoadedForTesting(
+    base::OnceClosure callback) {
+  if (is_network_dialog_loaded_for_testing_)
+    return true;
+  DCHECK(!on_network_dialog_loaded_callback_for_testing_);
+  on_network_dialog_loaded_callback_for_testing_ = std::move(callback);
+  return false;
+}
+
+void LockScreenStartReauthDialog::OnNetworkDialogReadyForTesting() {
+  if (is_network_dialog_loaded_for_testing_)
+    return;
+  is_network_dialog_loaded_for_testing_ = true;
+  if (on_network_dialog_loaded_callback_for_testing_) {
+    std::move(on_network_dialog_loaded_callback_for_testing_).Run();
+  }
+}
+
 LockScreenStartReauthDialog::LockScreenStartReauthDialog()
     : BaseLockDialog(GURL(chrome::kChromeUILockScreenStartReauthURL),
                      CalculateLockScreenReauthDialogSize(
                          features::IsNewLockScreenReauthLayoutEnabled())),
-      network_state_helper_(std::make_unique<login::NetworkStateHelper>()) {
-  NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE);
+      network_state_informer_(
+          base::MakeRefCounted<chromeos::NetworkStateInformer>()) {
+  network_state_informer_->Init();
+  scoped_observation_.Observe(network_state_informer_.get());
 }
 
 LockScreenStartReauthDialog::~LockScreenStartReauthDialog() {
   DCHECK_EQ(this, g_dialog);
-  NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
-                                                                 FROM_HERE);
-  CloseLockScreenNetworkDialog();
+  scoped_observation_.Reset();
+  DeleteLockScreenNetworkDialog();
   g_dialog = nullptr;
 }
 
-void LockScreenStartReauthDialog::NetworkConnectionStateChanged(
-    const NetworkState* network) {
-  if (!profile_)
-    return;
-  if (network_state_helper_->IsConnected()) {
-    if (lock_screen_network_dialog_) {
+void LockScreenStartReauthDialog::UpdateState(
+    NetworkError::ErrorReason reason) {
+  const bool is_offline =
+      NetworkStateInformer::OFFLINE == network_state_informer_->state();
+  if (is_offline) {
+    ShowLockScreenNetworkDialog();
+  } else {
+    if (is_network_dialog_visible_ && lock_screen_network_dialog_) {
+      is_network_dialog_visible_ = false;
       lock_screen_network_dialog_->Close();
     }
-    return;
   }
-  ShowLockScreenNetworkDialog();
-}
-
-void LockScreenStartReauthDialog::DefaultNetworkChanged(
-    const NetworkState* network) {
-  NOTIMPLEMENTED();
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h
index ea94485..0083151 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h
+++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h
@@ -9,6 +9,7 @@
 #include "chrome/browser/ash/login/helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/chromeos/in_session_password_change/base_lock_dialog.h"
+#include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h"
 #include "chromeos/network/network_state_handler.h"
 #include "chromeos/network/network_state_handler_observer.h"
 #include "ui/web_dialogs/web_dialog_ui.h"
@@ -17,8 +18,9 @@
 
 class LockScreenNetworkDialog;
 
-class LockScreenStartReauthDialog : public BaseLockDialog,
-                                    public NetworkStateHandlerObserver {
+class LockScreenStartReauthDialog
+    : public BaseLockDialog,
+      public NetworkStateInformer::NetworkStateInformerObserver {
  public:
   LockScreenStartReauthDialog();
   LockScreenStartReauthDialog(LockScreenStartReauthDialog const&) = delete;
@@ -29,24 +31,45 @@
   bool IsRunning();
   int GetDialogWidth();
 
-  void CloseLockScreenNetworkDialog();
+  void DismissLockScreenNetworkDialog();
   void ShowLockScreenNetworkDialog();
   static gfx::Size CalculateLockScreenReauthDialogSize(
       bool is_new_layout_enabled);
 
+  // Used for waiting for the network dialog in tests.
+  // Similar methods exist for the main dialog in InSessionPasswordSyncManager.
+  bool IsNetworkDialogLoadedForTesting(base::OnceClosure callback);
+  void OnNetworkDialogReadyForTesting();
+
+  LockScreenNetworkDialog* get_network_dialog_for_testing() {
+    return lock_screen_network_dialog_.get();
+  }
+
+  bool is_network_dialog_visible_for_testing() {
+    return is_network_dialog_visible_;
+  }
+
  private:
   void OnProfileCreated(Profile* profile, Profile::CreateStatus status);
   void OnDialogClosed(const std::string& json_retval) override;
+  void DeleteLockScreenNetworkDialog();
 
-  // NetworkStateHandlerObserver:
-  void NetworkConnectionStateChanged(const NetworkState* network) override;
-  void DefaultNetworkChanged(const NetworkState* network) override;
+  // NetworkStateInformer::NetworkStateInformerObserver:
+  void UpdateState(NetworkError::ErrorReason reason) override;
 
-  std::unique_ptr<login::NetworkStateHelper> network_state_helper_;
+  scoped_refptr<chromeos::NetworkStateInformer> network_state_informer_;
+  bool is_network_dialog_visible_ = false;
+
+  base::ScopedObservation<NetworkStateInformer, NetworkStateInformerObserver>
+      scoped_observation_{this};
 
   std::unique_ptr<LockScreenNetworkDialog> lock_screen_network_dialog_;
   Profile* profile_ = nullptr;
 
+  // A callback that is used to notify tests that the network dialog is loaded.
+  base::OnceClosure on_network_dialog_loaded_callback_for_testing_;
+  bool is_network_dialog_loaded_for_testing_ = false;
+
   base::WeakPtrFactory<LockScreenStartReauthDialog> weak_factory_{this};
 };
 
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h
index 9e0f9db..9fc77d8 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h
+++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h
@@ -31,7 +31,6 @@
   void HandleUpdateUserPassword(base::Value::ConstListView);
 
   bool IsAuthenticatorLoaded(base::OnceClosure callback);
-  bool IsJsReadyForTesting(base::OnceClosure js_ready_callback);
 
   void force_saml_redirect_for_testing() {
     force_saml_redirect_for_testing_ = true;
diff --git a/chrome/browser/ui/webui/chromeos/launcher_internals/launcher_internals_handler.cc b/chrome/browser/ui/webui/chromeos/launcher_internals/launcher_internals_handler.cc
index 6716e5c1..ea8b0eb5 100644
--- a/chrome/browser/ui/webui/chromeos/launcher_internals/launcher_internals_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/launcher_internals/launcher_internals_handler.cc
@@ -25,13 +25,16 @@
     const std::vector<const ChromeSearchResult*>& results) {
   std::vector<launcher_internals::mojom::ResultPtr> internals_results;
   for (auto* result : results) {
+    auto ranker_scores = result->ranker_scores();
+    ranker_scores["Relevance"] = result->relevance();
+
     internals_results.emplace_back(launcher_internals::mojom::Result::New(
         result->id(), base::UTF16ToUTF8(result->title()),
         base::UTF16ToUTF8(result->details()),
         app_list::ResultTypeToString(result->result_type()),
         app_list::MetricsTypeToString(result->metrics_type()),
         app_list::DisplayTypeToString(result->display_type()),
-        result->relevance(), result->ranker_scores()));
+        result->display_score(), ranker_scores));
   }
   page_->UpdateResults(base::UTF16ToUTF8(query), std::move(internals_results));
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h
index ad6eccf..5a2fbb9 100644
--- a/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_AUTO_ENROLLMENT_CHECK_SCREEN_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_AUTO_ENROLLMENT_CHECK_SCREEN_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/login/enrollment/auto_enrollment_check_screen_view.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 
diff --git a/chrome/browser/ui/webui/chromeos/login/enable_adb_sideloading_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enable_adb_sideloading_screen_handler.h
index fa7944013..217f9a44 100644
--- a/chrome/browser/ui/webui/chromeos/login/enable_adb_sideloading_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/enable_adb_sideloading_screen_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_ENABLE_ADB_SIDELOADING_SCREEN_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_ENABLE_ADB_SIDELOADING_SCREEN_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 
 namespace ash {
diff --git a/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h
index e0e00b04..98b8611 100644
--- a/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_ENABLE_DEBUGGING_SCREEN_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_ENABLE_DEBUGGING_SCREEN_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 
diff --git a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
index fde8cddd..ae7281d 100644
--- a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_EULA_SCREEN_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_EULA_SCREEN_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 // TODO(https://crbug.com/1164001): move to forward declaration.
 #include "chrome/browser/ash/login/help_app_launcher.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/fake_update_required_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/fake_update_required_screen_handler.h
index 3f886593..8fb9ec2 100644
--- a/chrome/browser/ui/webui/chromeos/login/fake_update_required_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/fake_update_required_screen_handler.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h"
 
diff --git a/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h
index f63bbab..bdeb8f23 100644
--- a/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 
 namespace ash {
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h
index d0455bc..3129ec0 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_KIOSK_AUTOLAUNCH_SCREEN_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_KIOSK_AUTOLAUNCH_SCREEN_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager_observer.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h
index f838c737..3634fb6 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_KIOSK_ENABLE_SCREEN_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_KIOSK_ENABLE_SCREEN_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/l10n_util_test_util.h b/chrome/browser/ui/webui/chromeos/login/l10n_util_test_util.h
index 3f61e250..06db747 100644
--- a/chrome/browser/ui/webui/chromeos/login/l10n_util_test_util.h
+++ b/chrome/browser/ui/webui/chromeos/login/l10n_util_test_util.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/input_method/mock_input_method_manager_impl.h"
 #include "ui/base/ime/ash/input_method_descriptor.h"
 
diff --git a/chrome/browser/ui/webui/chromeos/login/network_state_informer.h b/chrome/browser/ui/webui/chromeos/login/network_state_informer.h
index 61e2a0ef..411481d 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_state_informer.h
+++ b/chrome/browser/ui/webui/chromeos/login/network_state_informer.h
@@ -10,7 +10,6 @@
 #include <string>
 
 #include "base/cancelable_callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
index 39f9cd3..17d36748 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
@@ -10,7 +10,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
 #include "chrome/browser/ash/login/oobe_screen.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h
index 2515920..9e7fe7c 100644
--- a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_RESET_SCREEN_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_RESET_SCREEN_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/tpm_firmware_update.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
index 5d8a444b..62291a7 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -11,7 +11,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 // TODO(https://crbug.com/1164001): move to forward declaration.
diff --git a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h
index a743dad9..d8029cd 100644
--- a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/base/locale_util.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 
diff --git a/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h
index 7696bcf7..4729b9c 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 
 namespace ash {
diff --git a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
index c39c8f8..80eaa886 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ash/accessibility/accessibility_manager.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 
diff --git a/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h
index cc3395e..6221019a 100644
--- a/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_WRONG_HWID_SCREEN_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_WRONG_HWID_SCREEN_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 
 namespace ash {
diff --git a/chrome/browser/ui/webui/chromeos/slow_trace_ui.h b/chrome/browser/ui/webui/chromeos/slow_trace_ui.h
index d3e213c..7749d46 100644
--- a/chrome/browser/ui/webui/chromeos/slow_trace_ui.h
+++ b/chrome/browser/ui/webui/chromeos/slow_trace_ui.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "ui/base/layout.h"
diff --git a/chrome/browser/ui/webui/chromeos/user_image_source.h b/chrome/browser/ui/webui/chromeos/user_image_source.h
index a5a3ac1..63ddfcc6 100644
--- a/chrome/browser/ui/webui/chromeos/user_image_source.h
+++ b/chrome/browser/ui/webui/chromeos/user_image_source.h
@@ -8,7 +8,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "content/public/browser/url_data_source.h"
 #include "ui/base/layout.h"
diff --git a/chrome/browser/ui/webui/constrained_web_dialog_ui.h b/chrome/browser/ui/webui/constrained_web_dialog_ui.h
index 1773a75..73fa3c02 100644
--- a/chrome/browser/ui/webui/constrained_web_dialog_ui.h
+++ b/chrome/browser/ui/webui/constrained_web_dialog_ui.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "ui/gfx/native_widget_types.h"
 
diff --git a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h b/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h
index 225dbd4..d9fcb64d 100644
--- a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h
+++ b/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager_observer.h"
diff --git a/chrome/browser/ui/webui/help/version_updater_basic.h b/chrome/browser/ui/webui/help/version_updater_basic.h
index 9aec389..7bd71ef 100644
--- a/chrome/browser/ui/webui/help/version_updater_basic.h
+++ b/chrome/browser/ui/webui/help/version_updater_basic.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_HELP_VERSION_UPDATER_BASIC_H_
 #define CHROME_BROWSER_UI_WEBUI_HELP_VERSION_UPDATER_BASIC_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/ui/webui/help/version_updater.h"
 
 // Bare bones implementation just checks if a new version is ready.
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.h b/chrome/browser/ui/webui/help/version_updater_chromeos.h
index 9e8ade6..846cdb3 100644
--- a/chrome/browser/ui/webui/help/version_updater_chromeos.h
+++ b/chrome/browser/ui/webui/help/version_updater_chromeos.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_HELP_VERSION_UPDATER_CHROMEOS_H_
 #define CHROME_BROWSER_UI_WEBUI_HELP_VERSION_UPDATER_CHROMEOS_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/webui/help/version_updater.h"
 
diff --git a/chrome/browser/ui/webui/help/version_updater_mac.h b/chrome/browser/ui/webui/help/version_updater_mac.h
index 554f81a9..3c32311 100644
--- a/chrome/browser/ui/webui/help/version_updater_mac.h
+++ b/chrome/browser/ui/webui/help/version_updater_mac.h
@@ -7,7 +7,6 @@
 
 #import <AppKit/AppKit.h>
 
-#include "base/compiler_specific.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_refptr.h"
 #include "chrome/browser/buildflags.h"
diff --git a/chrome/browser/ui/webui/history/navigation_handler.h b/chrome/browser/ui/webui/history/navigation_handler.h
index 70ec515b8..a1cd828 100644
--- a/chrome/browser/ui/webui/history/navigation_handler.h
+++ b/chrome/browser/ui/webui/history/navigation_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_HISTORY_NAVIGATION_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_HISTORY_NAVIGATION_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
 namespace base {
diff --git a/chrome/browser/ui/webui/invalidations/invalidations_message_handler.h b/chrome/browser/ui/webui/invalidations/invalidations_message_handler.h
index b64ae91..592c50c 100644
--- a/chrome/browser/ui/webui/invalidations/invalidations_message_handler.h
+++ b/chrome/browser/ui/webui/invalidations/invalidations_message_handler.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
 #include "components/invalidation/impl/invalidation_logger_observer.h"
diff --git a/chrome/browser/ui/webui/metrics_handler.h b/chrome/browser/ui/webui/metrics_handler.h
index 718070d..6f515e7a 100644
--- a/chrome/browser/ui/webui/metrics_handler.h
+++ b/chrome/browser/ui/webui/metrics_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_METRICS_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_METRICS_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/webui/ntp/core_app_launcher_handler.h b/chrome/browser/ui/webui/ntp/core_app_launcher_handler.h
index 4e19b12..ce113c6 100644
--- a/chrome/browser/ui/webui/ntp/core_app_launcher_handler.h
+++ b/chrome/browser/ui/webui/ntp/core_app_launcher_handler.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/values.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "content/public/browser/web_ui_message_handler.h"
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.h b/chrome/browser/ui/webui/ntp/ntp_resource_cache.h
index 58883d07..d3dacd8e 100644
--- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.h
+++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/scoped_observation.h"
diff --git a/chrome/browser/ui/webui/omnibox/omnibox_page_handler.h b/chrome/browser/ui/webui/omnibox/omnibox_page_handler.h
index 777fde9..6c64971 100644
--- a/chrome/browser/ui/webui/omnibox/omnibox_page_handler.h
+++ b/chrome/browser/ui/webui/omnibox/omnibox_page_handler.h
@@ -9,7 +9,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/ui/webui/predictors/predictors_handler.h b/chrome/browser/ui/webui/predictors/predictors_handler.h
index 11c4ebc57..9672262 100644
--- a/chrome/browser/ui/webui/predictors/predictors_handler.h
+++ b/chrome/browser/ui/webui/predictors/predictors_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_PREDICTORS_PREDICTORS_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_PREDICTORS_PREDICTORS_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
diff --git a/chrome/browser/ui/webui/settings/about_handler.h b/chrome/browser/ui/webui/settings/about_handler.h
index 7ad6f8d..54fedf10 100644
--- a/chrome/browser/ui/webui/settings/about_handler.h
+++ b/chrome/browser/ui/webui/settings/about_handler.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/about_section.cc b/chrome/browser/ui/webui/settings/chromeos/about_section.cc
index 722dcce..f676a04f 100644
--- a/chrome/browser/ui/webui/settings/chromeos/about_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/about_section.cc
@@ -13,6 +13,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
 #include "chrome/browser/ash/arc/arc_util.h"
+#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/obsolete_system/obsolete_system.h"
 #include "chrome/browser/ui/webui/management/management_ui.h"
 #include "chrome/browser/ui/webui/settings/about_handler.h"
@@ -181,6 +184,13 @@
   return std::string();
 }
 
+std::string GetDeviceManager() {
+  policy::BrowserPolicyConnectorAsh* connector =
+      g_browser_process->platform_part()->browser_policy_connector_ash();
+  DCHECK(connector);
+  return connector->GetEnterpriseDomainManager();
+}
+
 }  // namespace
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
@@ -343,6 +353,8 @@
   html_source->AddString("managementPage",
                          ManagementUI::GetManagementPageSubtitle(profile()));
 
+  html_source->AddString("deviceManager", GetDeviceManager());
+
   if (user_manager::UserManager::IsInitialized()) {
     user_manager::UserManager* user_manager = user_manager::UserManager::Get();
     if (!webui::IsEnterpriseManaged() && !user_manager->IsCurrentUserOwner()) {
diff --git a/chrome/browser/ui/webui/settings/chromeos/languages_section.cc b/chrome/browser/ui/webui/settings/chromeos/languages_section.cc
index 73ef93c36..3714ad1 100644
--- a/chrome/browser/ui/webui/settings/chromeos/languages_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/languages_section.cc
@@ -6,7 +6,6 @@
 
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
-#include "ash/public/cpp/quick_answers/quick_answers_state.h"
 #include "base/feature_list.h"
 #include "base/no_destructor.h"
 #include "base/strings/utf_string_conversions.h"
@@ -17,6 +16,7 @@
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
+#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h"
 #include "components/prefs/pref_service.h"
 #include "components/spellcheck/browser/pref_names.h"
 #include "content/public/browser/web_ui_data_source.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc b/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc
index 6e5d99c..0b11c10 100644
--- a/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/ui/webui/settings/chromeos/multidevice_section.h"
 
 #include "ash/components/phonehub/phone_hub_manager.h"
+#include "ash/components/phonehub/pref_names.h"
+#include "ash/components/phonehub/screen_lock_manager.h"
 #include "ash/components/phonehub/url_constants.h"
 #include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
@@ -354,8 +356,6 @@
        IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_CONNECTING_TITLE},
       {"multideviceNotificationAccessSetupScreenLockTitle",
        IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_TITLE},
-      {"multideviceNotificationAccessSetupScreenLockSubtitle",
-       IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_SUBTITLE},
       {"multideviceNotificationAccessSetupScreenLockInstruction",
        IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_INSTRUCTION},
       {"multideviceNotificationAccessSetupAwaitingResponseTitle",
@@ -412,6 +412,10 @@
       ui::SubstituteChromeOSDeviceType(
           IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_COMPLETED_SUMMARY));
   html_source->AddString(
+      "multideviceNotificationAccessSetupScreenLockSubtitle",
+      ui::SubstituteChromeOSDeviceType(
+          IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_SCREEN_LOCK_SUBTITLE));
+  html_source->AddString(
       "multideviceForgetDeviceSummary",
       ui::SubstituteChromeOSDeviceType(
           IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE_EXPLANATION));
@@ -526,8 +530,12 @@
           base::FeatureList::IsEnabled(
               ::features::kNearbySharingBackgroundScanning));
   html_source->AddBoolean("isEcheAppEnabled", features::IsEcheSWAEnabled());
-  // TODO(crbug.com/1256644): Query the real value from pref.
-  html_source->AddBoolean("isPhoneScreenLockEnabled", false);
+  bool is_phone_screen_lock_enabled =
+      static_cast<phonehub::ScreenLockManager::LockStatus>(
+          pref_service_->GetInteger(phonehub::prefs::kScreenLockStatus)) ==
+      phonehub::ScreenLockManager::LockStatus::kLockedOn;
+  html_source->AddBoolean("isPhoneScreenLockEnabled",
+                          is_phone_screen_lock_enabled);
   const bool is_screen_lock_enabled =
       SessionControllerClientImpl::CanLockScreen() &&
       SessionControllerClientImpl::ShouldLockScreenAutomatically();
diff --git a/chrome/browser/ui/webui/settings/chromeos/search_section.h b/chrome/browser/ui/webui/settings/chromeos/search_section.h
index dd68b30a..b42ec8b 100644
--- a/chrome/browser/ui/webui/settings/chromeos/search_section.h
+++ b/chrome/browser/ui/webui/settings/chromeos/search_section.h
@@ -6,9 +6,9 @@
 #define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SEARCH_SECTION_H_
 
 #include "ash/public/cpp/assistant/assistant_state_base.h"
-#include "ash/public/cpp/quick_answers/quick_answers_state.h"
 #include "base/values.h"
 #include "chrome/browser/ui/webui/settings/chromeos/os_settings_section.h"
+#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h"
 
 namespace content {
 class WebUIDataSource;
diff --git a/chrome/browser/ui/webui/settings/custom_home_pages_table_model.h b/chrome/browser/ui/webui/settings/custom_home_pages_table_model.h
index a81897f..59fed37 100644
--- a/chrome/browser/ui/webui/settings/custom_home_pages_table_model.h
+++ b/chrome/browser/ui/webui/settings/custom_home_pages_table_model.h
@@ -8,7 +8,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "components/history/core/browser/history_types.h"
 #include "ui/base/models/table_model.h"
diff --git a/chrome/browser/ui/webui/settings/import_data_handler.h b/chrome/browser/ui/webui/settings/import_data_handler.h
index de82de00..02bbef74 100644
--- a/chrome/browser/ui/webui/settings/import_data_handler.h
+++ b/chrome/browser/ui/webui/settings/import_data_handler.h
@@ -9,7 +9,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/importer/importer_progress_observer.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "chrome/common/importer/importer_data_types.h"
diff --git a/chrome/browser/ui/webui/settings/reset_settings_handler.h b/chrome/browser/ui/webui/settings/reset_settings_handler.h
index e227bed..1f2b5764 100644
--- a/chrome/browser/ui/webui/settings/reset_settings_handler.h
+++ b/chrome/browser/ui/webui/settings/reset_settings_handler.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
diff --git a/chrome/browser/ui/webui/settings/settings_cookies_view_handler.h b/chrome/browser/ui/webui/settings/settings_cookies_view_handler.h
index 7e6843e..fa6c6de 100644
--- a/chrome/browser/ui/webui/settings/settings_cookies_view_handler.h
+++ b/chrome/browser/ui/webui/settings/settings_cookies_view_handler.h
@@ -10,7 +10,6 @@
 #include <utility>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "chrome/browser/browsing_data/cookies_tree_model.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
diff --git a/chrome/browser/ui/webui/settings/settings_utils_linux.cc b/chrome/browser/ui/webui/settings/settings_utils_linux.cc
index 1f52839..236c2a7 100644
--- a/chrome/browser/ui/webui/settings/settings_utils_linux.cc
+++ b/chrome/browser/ui/webui/settings/settings_utils_linux.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/environment.h"
 #include "base/files/file_util.h"
+#include "base/memory/weak_ptr.h"
 #include "base/nix/xdg_util.h"
 #include "base/process/launch.h"
 #include "base/task/thread_pool.h"
@@ -48,8 +49,11 @@
 constexpr char kLinuxProxyConfigUrl[] = "chrome://linux-proxy-config";
 
 // Show the proxy config URL in the given tab.
-void ShowLinuxProxyConfigUrl(int render_process_id, int render_view_id) {
+void ShowLinuxProxyConfigUrl(base::WeakPtr<content::WebContents> web_contents,
+                             bool launched) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (launched)
+    return;
   std::unique_ptr<base::Environment> env(base::Environment::Create());
   const char* name = base::nix::GetDesktopEnvironmentName(env.get());
   if (name)
@@ -58,8 +62,6 @@
                        WindowOpenDisposition::NEW_FOREGROUND_TAB,
                        ui::PAGE_TRANSITION_LINK, false);
 
-  content::WebContents* web_contents =
-      tab_util::GetWebContentsByID(render_process_id, render_view_id);
   if (web_contents)
     web_contents->OpenURL(params);
 }
@@ -91,7 +93,7 @@
 
 // Detect, and if possible, start the appropriate proxy config utility. On
 // failure to do so, show the Linux proxy config URL in a new tab instead.
-void DetectAndStartProxyConfigUtil(int render_process_id, int render_view_id) {
+bool DetectAndStartProxyConfigUtil() {
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::MAY_BLOCK);
   std::unique_ptr<base::Environment> env(base::Environment::Create());
@@ -134,11 +136,7 @@
       break;
   }
 
-  if (launched)
-    return;
-  content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(&ShowLinuxProxyConfigUrl, render_process_id,
-                                render_view_id));
+  return launched;
 }
 
 }  // namespace
@@ -146,15 +144,10 @@
 namespace settings_utils {
 
 void ShowNetworkProxySettings(content::WebContents* web_contents) {
-  base::ThreadPool::PostTask(
+  base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
-      base::BindOnce(
-          &DetectAndStartProxyConfigUtil,
-          web_contents->GetMainFrame()
-              ->GetRenderViewHost()
-              ->GetProcess()
-              ->GetID(),
-          web_contents->GetMainFrame()->GetRenderViewHost()->GetRoutingID()));
+      base::BindOnce(&DetectAndStartProxyConfigUtil),
+      base::BindOnce(&ShowLinuxProxyConfigUrl, web_contents->GetWeakPtr()));
 }
 
 }  // namespace settings_utils
diff --git a/chrome/browser/ui/webui/signin_internals_ui.h b/chrome/browser/ui/webui/signin_internals_ui.h
index 37f9ef7..16e4193 100644
--- a/chrome/browser/ui/webui/signin_internals_ui.h
+++ b/chrome/browser/ui/webui/signin_internals_ui.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_SIGNIN_INTERNALS_UI_H_
 #define CHROME_BROWSER_UI_WEBUI_SIGNIN_INTERNALS_UI_H_
 
-#include "base/compiler_specific.h"
 #include "base/values.h"
 #include "components/signin/core/browser/about_signin_internals.h"
 #include "content/public/browser/web_ui_controller.h"
diff --git a/chrome/browser/ui/webui/sync_file_system_internals/dump_database_handler.h b/chrome/browser/ui/webui/sync_file_system_internals/dump_database_handler.h
index e72caf2..395b37c 100644
--- a/chrome/browser/ui/webui/sync_file_system_internals/dump_database_handler.h
+++ b/chrome/browser/ui/webui/sync_file_system_internals/dump_database_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_SYNC_FILE_SYSTEM_INTERNALS_DUMP_DATABASE_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_SYNC_FILE_SYSTEM_INTERNALS_DUMP_DATABASE_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
 class Profile;
diff --git a/chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.h b/chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.h
index 10737d9f..c793510 100644
--- a/chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.h
+++ b/chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_SYNC_FILE_SYSTEM_INTERNALS_EXTENSION_STATUSES_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_SYNC_FILE_SYSTEM_INTERNALS_EXTENSION_STATUSES_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
diff --git a/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.h b/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.h
index 56b8bcb..5ed1402 100644
--- a/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.h
+++ b/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/sync_file_system/remote_file_sync_service.h"
 #include "chrome/browser/sync_file_system/sync_status_code.h"
diff --git a/chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_handler.h b/chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_handler.h
index c4b0a7a..4c97b996 100644
--- a/chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_handler.h
+++ b/chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_handler.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/browser/sync_file_system/sync_event_observer.h"
 #include "chrome/browser/sync_file_system/task_logger.h"
 #include "content/public/browser/web_ui_message_handler.h"
diff --git a/chrome/browser/ui/webui/sync_internals/sync_internals_ui.h b/chrome/browser/ui/webui/sync_internals/sync_internals_ui.h
index 75bb219..416b2ba 100644
--- a/chrome/browser/ui/webui/sync_internals/sync_internals_ui.h
+++ b/chrome/browser/ui/webui/sync_internals/sync_internals_ui.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_SYNC_INTERNALS_UI_H_
 #define CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_SYNC_INTERNALS_UI_H_
 
-#include "base/compiler_specific.h"
 #include "content/public/browser/web_ui_controller.h"
 
 // The implementation for the chrome://sync-internals page.
diff --git a/chrome/browser/ui/webui/theme_source.h b/chrome/browser/ui/webui/theme_source.h
index 622ca8a..ea66c98 100644
--- a/chrome/browser/ui/webui/theme_source.h
+++ b/chrome/browser/ui/webui/theme_source.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/task/single_thread_task_runner.h"
 #include "content/public/browser/url_data_source.h"
diff --git a/chrome/browser/ui/webui/web_ui_test_handler.h b/chrome/browser/ui/webui/web_ui_test_handler.h
index 893d938e..685f2f1 100644
--- a/chrome/browser/ui/webui/web_ui_test_handler.h
+++ b/chrome/browser/ui/webui/web_ui_test_handler.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/data/webui/web_ui_test.mojom-forward.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chrome/browser/upgrade_detector/upgrade_detector_chromeos.h b/chrome/browser/upgrade_detector/upgrade_detector_chromeos.h
index e16c2613..c083b5e3 100644
--- a/chrome/browser/upgrade_detector/upgrade_detector_chromeos.h
+++ b/chrome/browser/upgrade_detector/upgrade_detector_chromeos.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UPGRADE_DETECTOR_UPGRADE_DETECTOR_CHROMEOS_H_
 #define CHROME_BROWSER_UPGRADE_DETECTOR_UPGRADE_DETECTOR_CHROMEOS_H_
 
-#include "base/compiler_specific.h"
 #include "base/no_destructor.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index e0f06c5b..54524edc5 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -576,6 +576,7 @@
       "//ash/constants",
       "//chrome/browser/chromeos",
       "//components/arc:arc",
+      "//components/arc:arc_test_support",
       "//components/arc/mojom",
     ]
   }
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
index a92d56e..54fe188 100644
--- a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
+++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
@@ -40,6 +40,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "components/content_settings/core/common/content_settings.h"
+#include "components/services/app_service/public/cpp/intent_util.h"
 #include "components/services/app_service/public/cpp/publisher_base.h"
 #include "content/public/browser/clear_site_data_utils.h"
 #include "third_party/blink/public/mojom/manifest/capture_links.mojom.h"
@@ -59,7 +60,9 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/ash/arc/arc_web_contents_data.h"
+#include "chrome/browser/ash/crostini/crostini_terminal.h"
 #include "chrome/browser/ash/crostini/crostini_util.h"
 #include "chrome/browser/ash/login/demo_mode/demo_session.h"
 #include "chrome/browser/web_applications/system_web_apps/system_web_app_manager.h"
@@ -282,7 +285,8 @@
 bool WebAppPublisherHelper::Accepts(const std::string& app_id) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Crostini Terminal System App is handled by Crostini Apps.
-  return app_id != crostini::kCrostiniTerminalSystemAppId;
+  return app_id != crostini::kCrostiniTerminalSystemAppId ||
+         base::FeatureList::IsEnabled(chromeos::features::kTerminalSSH);
 #else
   return true;
 #endif
@@ -622,6 +626,16 @@
     return nullptr;
   }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  if (app_id == crostini::kCrostiniTerminalSystemAppId) {
+    DCHECK(base::FeatureList::IsEnabled(chromeos::features::kTerminalSSH));
+    crostini::LaunchTerminal(profile_, window_info
+                                           ? window_info->display_id
+                                           : display::kInvalidDisplayId);
+    return nullptr;
+  }
+#endif
+
   const WebApp* web_app = GetWebApp(app_id);
   if (!web_app) {
     return nullptr;
@@ -685,7 +699,7 @@
   return LaunchAppWithParams(std::move(params));
 }
 
-content::WebContents* WebAppPublisherHelper::LaunchAppWithFiles(
+void WebAppPublisherHelper::LaunchAppWithFiles(
     const std::string& app_id,
     int32_t event_flags,
     apps::mojom::LaunchSource launch_source,
@@ -703,12 +717,13 @@
 
   if (base::FeatureList::IsEnabled(
           features::kDesktopPWAsFileHandlingSettingsGated)) {
-    NOTIMPLEMENTED();
-    return nullptr;
+    LaunchAppWithFilesCheckingUserPermission(app_id, std::move(params),
+                                             base::DoNothing());
+    return;
   }
 
   // The app will be launched for the currently active profile.
-  return LaunchAppWithParams(std::move(params));
+  LaunchAppWithParams(std::move(params));
 }
 
 void WebAppPublisherHelper::LaunchAppWithIntent(
@@ -719,6 +734,21 @@
     apps::mojom::WindowInfoPtr window_info,
     apps::mojom::Publisher::LaunchAppWithIntentCallback callback) {
   CHECK(intent);
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // TODO(crbug.com/1028898): Implement LaunchTerminalWithIntent() and call it.
+  // It must include support for sharing any open-with directory before terminal
+  // starts.
+  if (app_id == crostini::kCrostiniTerminalSystemAppId) {
+    DCHECK(base::FeatureList::IsEnabled(chromeos::features::kTerminalSSH));
+    crostini::LaunchTerminal(profile_, window_info
+                                           ? window_info->display_id
+                                           : display::kInvalidDisplayId);
+    std::move(callback).Run(true);
+    return;
+  }
+#endif
+
   LaunchAppWithIntentImpl(
       app_id, event_flags, std::move(intent), launch_source,
       window_info ? window_info->display_id : display::kInvalidDisplayId,
@@ -1295,20 +1325,22 @@
     return;
   }
 
+  bool is_file_handling_launch = intent->files && !intent->files->empty() &&
+                                 !apps_util::IsShareIntent(intent);
   auto params = apps::CreateAppLaunchParamsForIntent(
       app_id, event_flags, launch_source, display_id,
       ConvertDisplayModeToAppLaunchContainer(
           registrar().GetAppEffectiveDisplayMode(app_id)),
       std::move(intent), profile_);
-  if (params.launch_files.empty() ||
-      !base::FeatureList::IsEnabled(
+  if (is_file_handling_launch &&
+      base::FeatureList::IsEnabled(
           features::kDesktopPWAsFileHandlingSettingsGated)) {
-    std::move(callback).Run(LaunchAppWithParams(std::move(params)));
+    LaunchAppWithFilesCheckingUserPermission(app_id, std::move(params),
+                                             std::move(callback));
     return;
   }
 
-  LaunchAppWithFilesCheckingUserPermission(app_id, std::move(params),
-                                           std::move(callback));
+  std::move(callback).Run(LaunchAppWithParams(std::move(params)));
 }
 
 #if defined(OS_CHROMEOS)
@@ -1412,16 +1444,11 @@
     const std::string& app_id,
     apps::AppLaunchParams params,
     base::OnceCallback<void(content::WebContents*)> callback) {
-  absl::optional<GURL> file_handler_url =
-      provider_->os_integration_manager().GetMatchingFileHandlerURL(
-          app_id, params.launch_files);
-  if (!file_handler_url) {
-    NOTREACHED() << "App " << app_id
-                 << " was asked to launch with files it can't handle.";
-    std::move(callback).Run(nullptr);
-    return;
-  }
+  DCHECK(
+      provider_->os_integration_manager().IsFileHandlingAPIAvailable(app_id));
 
+  // TODO(estade): move the system app check into
+  // WebAppRegistrar::GetFileHandlerApprovalState().
   const WebApp* web_app = provider_->registrar().GetAppById(app_id);
   DCHECK(web_app);
   if (web_app->IsSystemApp()) {
@@ -1430,7 +1457,6 @@
   }
 
   std::vector<base::FilePath> file_paths = params.launch_files;
-
   auto launch_callback =
       base::BindOnce(&WebAppPublisherHelper::OnFileHandlerDialogCompleted,
                      weak_ptr_factory_.GetWeakPtr(), app_id, std::move(params),
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper.h b/chrome/browser/web_applications/app_service/web_app_publisher_helper.h
index fe2b16f..5a41cc1 100644
--- a/chrome/browser/web_applications/app_service/web_app_publisher_helper.h
+++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper.h
@@ -170,11 +170,10 @@
                                apps::mojom::LaunchSource launch_source,
                                apps::mojom::WindowInfoPtr window_info);
 
-  content::WebContents* LaunchAppWithFiles(
-      const std::string& app_id,
-      int32_t event_flags,
-      apps::mojom::LaunchSource launch_source,
-      apps::mojom::FilePathsPtr file_paths);
+  void LaunchAppWithFiles(const std::string& app_id,
+                          int32_t event_flags,
+                          apps::mojom::LaunchSource launch_source,
+                          apps::mojom::FilePathsPtr file_paths);
 
   content::WebContents* MaybeNavigateExistingWindow(const std::string& app_id,
                                                     absl::optional<GURL> url);
diff --git a/chrome/browser/web_applications/app_service/web_apps.cc b/chrome/browser/web_applications/app_service/web_apps.cc
index 4bc26104..449fe047 100644
--- a/chrome/browser/web_applications/app_service/web_apps.cc
+++ b/chrome/browser/web_applications/app_service/web_apps.cc
@@ -30,6 +30,7 @@
 #include "components/webapps/browser/installable/installable_metrics.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_menu_constants.h"
 #include "ash/webui/projector_app/public/cpp/projector_app_constants.h"  // nogncheck
 #include "base/bind.h"
@@ -37,6 +38,8 @@
 #include "chrome/browser/apps/app_service/menu_item_constants.h"
 #include "chrome/browser/apps/app_service/menu_util.h"
 #include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/browser/ash/crostini/crostini_terminal.h"
+#include "chrome/browser/ash/crostini/crostini_util.h"
 #include "chrome/browser/web_applications/web_app_icon_manager.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/services/app_service/public/cpp/app_registry_cache.h"
@@ -381,6 +384,11 @@
                                &menu_items);
   }
 
+  if (app_id == crostini::kCrostiniTerminalSystemAppId) {
+    DCHECK(base::FeatureList::IsEnabled(chromeos::features::kTerminalSSH));
+    crostini::AddTerminalMenuItems(profile_, &menu_items);
+  }
+
   if (menu_type == apps::mojom::MenuType::kShelf &&
       instance_registry_->ContainsAppId(app_id)) {
     apps::AddCommandItem(ash::MENU_CLOSE, IDS_SHELF_CONTEXT_MENU_CLOSE,
@@ -480,6 +488,13 @@
     ++menu_item_index;
   }
 
+  if (app_id == crostini::kCrostiniTerminalSystemAppId) {
+    DCHECK(base::FeatureList::IsEnabled(chromeos::features::kTerminalSSH));
+    crostini::AddTerminalMenuShortcuts(
+        profile_, &menu_items,
+        ash::LAUNCH_APP_SHORTCUT_FIRST + menu_item_index);
+  }
+
   std::move(callback).Run(std::move(menu_items));
 }
 
@@ -487,6 +502,13 @@
                                         int command_id,
                                         const std::string& shortcut_id,
                                         int64_t display_id) {
+  if (app_id == crostini::kCrostiniTerminalSystemAppId) {
+    DCHECK(base::FeatureList::IsEnabled(chromeos::features::kTerminalSSH));
+    if (crostini::ExecuteTerminalMenuShortcutCommand(profile_, shortcut_id,
+                                                     display_id)) {
+      return;
+    }
+  }
   publisher_helper().ExecuteContextMenuCommand(app_id, shortcut_id, display_id);
 }
 
diff --git a/chrome/browser/web_applications/web_app_install_manager.cc b/chrome/browser/web_applications/web_app_install_manager.cc
index c933f49..ef85590 100644
--- a/chrome/browser/web_applications/web_app_install_manager.cc
+++ b/chrome/browser/web_applications/web_app_install_manager.cc
@@ -89,7 +89,8 @@
     const GURL& web_app_url,
     webapps::WebappInstallSource install_source,
     WebAppManifestCheckCallback callback) {
-  DCHECK(started_);
+  if (!started_)
+    return;
 
   auto task = std::make_unique<WebAppInstallTask>(
       profile_, os_integration_manager_, finalizer_,
@@ -110,7 +111,8 @@
     webapps::WebappInstallSource install_source,
     WebAppInstallDialogCallback dialog_callback,
     OnceInstallCallback callback) {
-  DCHECK(started_);
+  if (!started_)
+    return;
 
   auto task = std::make_unique<WebAppInstallTask>(
       profile_, os_integration_manager_, finalizer_,
@@ -130,7 +132,8 @@
     webapps::WebappInstallSource install_source,
     WebAppInstallDialogCallback dialog_callback,
     OnceInstallCallback callback) {
-  DCHECK(started_);
+  if (!started_)
+    return;
 
   auto task = std::make_unique<WebAppInstallTask>(
       profile_, os_integration_manager_, finalizer_,
@@ -146,7 +149,8 @@
 void WebAppInstallManager::InstallSubApp(const AppId& parent_app_id,
                                          const GURL& install_url,
                                          OnceInstallCallback callback) {
-  DCHECK(started_);
+  if (!started_)
+    return;
 
   // Enqueue full background installation flow. Since app_id isn't available
   // yet, duplicate installation check will be performed down the line once
@@ -195,7 +199,8 @@
     const absl::optional<WebAppInstallParams>& install_params,
     webapps::WebappInstallSource install_source,
     OnceInstallCallback callback) {
-  DCHECK(started_);
+  if (!started_)
+    return;
 
   auto task = std::make_unique<WebAppInstallTask>(
       profile_, os_integration_manager_, finalizer_,
@@ -217,7 +222,8 @@
     const WebAppInstallParams& install_params,
     webapps::WebappInstallSource install_source,
     OnceInstallCallback callback) {
-  DCHECK(started_);
+  if (!started_)
+    return;
 
   auto task = std::make_unique<WebAppInstallTask>(
       profile_, os_integration_manager_, finalizer_,
@@ -321,7 +327,8 @@
 void WebAppInstallManager::InstallWebAppsAfterSync(
     std::vector<WebApp*> web_apps,
     RepeatingInstallCallback callback) {
-  DCHECK(started_);
+  if (!started_)
+    return;
 
   if (disable_web_app_sync_install_for_testing_)
     return;
@@ -349,14 +356,18 @@
 void WebAppInstallManager::UninstallWithoutRegistryUpdateFromSync(
     const std::vector<AppId>& web_apps,
     RepeatingUninstallCallback callback) {
-  DCHECK(started_);
+  if (!started_)
+    return;
+
   finalizer_->UninstallWithoutRegistryUpdateFromSync(std::move(web_apps),
                                                      std::move(callback));
 }
 
 void WebAppInstallManager::RetryIncompleteUninstalls(
     const std::vector<AppId>& apps_to_uninstall) {
-  DCHECK(started_);
+  if (!started_)
+    return;
+
   finalizer_->RetryIncompleteUninstalls(apps_to_uninstall);
 }
 
diff --git a/chrome/browser/web_applications/web_app_install_task_unittest.cc b/chrome/browser/web_applications/web_app_install_task_unittest.cc
index 7cc0221d..d0e69a5 100644
--- a/chrome/browser/web_applications/web_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_task_unittest.cc
@@ -67,12 +67,12 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/components/arc/test/connection_holder_util.h"
 #include "ash/components/arc/test/fake_app_instance.h"
-#include "ash/components/arc/test/fake_intent_helper_instance.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_test.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/mojom/intent_helper.mojom.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/session/arc_service_manager.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
 #endif
 
 namespace web_app {
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index d65b64b..f2b40a07 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1637301475-5fb92fe23de7d8e9b112c64f8e326e5af300f973.profdata
+chrome-linux-main-1637582157-6d0aca8725f5f30f6f064a070e4e9c9598832cfd.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index bd680cf..d2e35a1 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1637301475-39c5c472b39f86e08721c05cb8183243567e2c8a.profdata
+chrome-mac-main-1637582157-9e01b98de0eefd02bfda0fdfe631c48c81b16a28.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 9e99a6e..1369ca2 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1637311015-10c2928f05c3e4baadc4f1b6e106635d8062ebf0.profdata
+chrome-win32-main-1637571331-86b6691f1ff23ba7ccc4426cb2c9a93cf4e28072.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 7ddf04c..b0c1abc3 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1637311015-79168f43234d0f02bb9630c7eb8b144cd3ddc436.profdata
+chrome-win64-main-1637571331-b503cba1ca483d9373f61ddff038ef924d953abc.profdata
diff --git a/chrome/common/chrome_content_client.h b/chrome/common/chrome_content_client.h
index 1c23715..3ab707c 100644
--- a/chrome/common/chrome_content_client.h
+++ b/chrome/common/chrome_content_client.h
@@ -10,7 +10,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/synchronization/lock.h"
 #include "build/branding_buildflags.h"
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 784a601..8bb3afa8 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -284,13 +284,7 @@
 // Use settings instead of permissions to control access to the PWA File
 // Handling API.
 const base::Feature kDesktopPWAsFileHandlingSettingsGated{
-  "DesktopPWAsFileHandlingSettingsGated",
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MAC)
-      base::FEATURE_ENABLED_BY_DEFAULT
-#else
-      base::FEATURE_DISABLED_BY_DEFAULT
-#endif
-};
+    "DesktopPWAsFileHandlingSettingsGated", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Replaces the origin text flash in web app titlebars with the name of
 // the app.
diff --git a/chrome/common/extensions/chrome_extensions_client.h b/chrome/common/extensions/chrome_extensions_client.h
index 72edb7d..e483d36 100644
--- a/chrome/common/extensions/chrome_extensions_client.h
+++ b/chrome/common/extensions/chrome_extensions_client.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
 #include "extensions/common/extensions_client.h"
 #include "url/gurl.h"
diff --git a/chrome/installer/util/delete_reg_key_work_item.h b/chrome/installer/util/delete_reg_key_work_item.h
index da146e37e..6b56a9b1 100644
--- a/chrome/installer/util/delete_reg_key_work_item.h
+++ b/chrome/installer/util/delete_reg_key_work_item.h
@@ -9,7 +9,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/installer/util/registry_key_backup.h"
 #include "chrome/installer/util/work_item.h"
 
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h
index 8204d4d..108aabd 100644
--- a/chrome/renderer/chrome_content_renderer_client.h
+++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -13,7 +13,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "build/build_config.h"
diff --git a/chrome/renderer/chrome_render_thread_observer.h b/chrome/renderer/chrome_render_thread_observer.h
index 1e11916..da21aacb 100644
--- a/chrome/renderer/chrome_render_thread_observer.h
+++ b/chrome/renderer/chrome_render_thread_observer.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/common/renderer_configuration.mojom.h"
 #include "components/content_settings/common/content_settings_manager.mojom.h"
diff --git a/chrome/renderer/extensions/file_browser_handler_custom_bindings.h b/chrome/renderer/extensions/file_browser_handler_custom_bindings.h
index cb9298a..3816334 100644
--- a/chrome/renderer/extensions/file_browser_handler_custom_bindings.h
+++ b/chrome/renderer/extensions/file_browser_handler_custom_bindings.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_RENDERER_EXTENSIONS_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_H_
 #define CHROME_RENDERER_EXTENSIONS_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_H_
 
-#include "base/compiler_specific.h"
 #include "extensions/renderer/object_backed_native_handler.h"
 
 namespace extensions {
diff --git a/chrome/renderer/extensions/file_manager_private_custom_bindings.h b/chrome/renderer/extensions/file_manager_private_custom_bindings.h
index 1177bdf..942ad49 100644
--- a/chrome/renderer/extensions/file_manager_private_custom_bindings.h
+++ b/chrome/renderer/extensions/file_manager_private_custom_bindings.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_RENDERER_EXTENSIONS_FILE_MANAGER_PRIVATE_CUSTOM_BINDINGS_H_
 #define CHROME_RENDERER_EXTENSIONS_FILE_MANAGER_PRIVATE_CUSTOM_BINDINGS_H_
 
-#include "base/compiler_specific.h"
 #include "extensions/renderer/object_backed_native_handler.h"
 
 namespace extensions {
diff --git a/chrome/renderer/extensions/notifications_native_handler.h b/chrome/renderer/extensions/notifications_native_handler.h
index 1a953910..ed7b7587 100644
--- a/chrome/renderer/extensions/notifications_native_handler.h
+++ b/chrome/renderer/extensions/notifications_native_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_RENDERER_EXTENSIONS_NOTIFICATIONS_NATIVE_HANDLER_H_
 #define CHROME_RENDERER_EXTENSIONS_NOTIFICATIONS_NATIVE_HANDLER_H_
 
-#include "base/compiler_specific.h"
 #include "extensions/renderer/object_backed_native_handler.h"
 
 namespace base {
diff --git a/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h b/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h
index 38a2a504..059ebafc 100644
--- a/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h
+++ b/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_RENDERER_PEPPER_CHROME_RENDERER_PEPPER_HOST_FACTORY_H_
 #define CHROME_RENDERER_PEPPER_CHROME_RENDERER_PEPPER_HOST_FACTORY_H_
 
-#include "base/compiler_specific.h"
 #include "ppapi/host/host_factory.h"
 
 namespace content {
diff --git a/chrome/renderer/pepper/pepper_flash_font_file_host.h b/chrome/renderer/pepper/pepper_flash_font_file_host.h
index 3513036..31bf85b 100644
--- a/chrome/renderer/pepper/pepper_flash_font_file_host.h
+++ b/chrome/renderer/pepper/pepper_flash_font_file_host.h
@@ -8,7 +8,6 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "ppapi/c/private/pp_private_font_charset.h"
 #include "ppapi/host/resource_host.h"
diff --git a/chrome/renderer/pepper/pepper_flash_fullscreen_host.h b/chrome/renderer/pepper/pepper_flash_fullscreen_host.h
index be91a31d..18b5fa8 100644
--- a/chrome/renderer/pepper/pepper_flash_fullscreen_host.h
+++ b/chrome/renderer/pepper/pepper_flash_fullscreen_host.h
@@ -7,7 +7,6 @@
 
 #include <stdint.h>
 
-#include "base/compiler_specific.h"
 #include "ppapi/host/resource_host.h"
 
 namespace content {
diff --git a/chrome/renderer/pepper/pepper_helper.h b/chrome/renderer/pepper/pepper_helper.h
index 7572241..5794ac8 100644
--- a/chrome/renderer/pepper/pepper_helper.h
+++ b/chrome/renderer/pepper/pepper_helper.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_RENDERER_PEPPER_PEPPER_HELPER_H_
 #define CHROME_RENDERER_PEPPER_PEPPER_HELPER_H_
 
-#include "base/compiler_specific.h"
 #include "content/public/renderer/render_frame_observer.h"
 
 // This class listens for Pepper creation events from the RenderFrame and
diff --git a/chrome/renderer/pepper/pepper_shared_memory_message_filter.h b/chrome/renderer/pepper/pepper_shared_memory_message_filter.h
index fa98aae..09e694b 100644
--- a/chrome/renderer/pepper/pepper_shared_memory_message_filter.h
+++ b/chrome/renderer/pepper/pepper_shared_memory_message_filter.h
@@ -7,7 +7,6 @@
 
 #include <stdint.h>
 
-#include "base/compiler_specific.h"
 #include "ppapi/c/pp_instance.h"
 #include "ppapi/host/instance_message_filter.h"
 
diff --git a/chrome/renderer/resources/default_100_percent/common/error_network_generic.png b/chrome/renderer/resources/default_100_percent/common/error_network_generic.png
deleted file mode 100644
index 7f753d0b..0000000
--- a/chrome/renderer/resources/default_100_percent/common/error_network_generic.png
+++ /dev/null
Binary files differ
diff --git a/chrome/renderer/resources/default_200_percent/common/error_network_generic.png b/chrome/renderer/resources/default_200_percent/common/error_network_generic.png
deleted file mode 100644
index b1cb2cd5c..0000000
--- a/chrome/renderer/resources/default_200_percent/common/error_network_generic.png
+++ /dev/null
Binary files differ
diff --git a/chrome/renderer/resources/extensions/browser_action_custom_bindings.js b/chrome/renderer/resources/extensions/browser_action_custom_bindings.js
index b4b6043c..64855934 100644
--- a/chrome/renderer/resources/extensions/browser_action_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/browser_action_custom_bindings.js
@@ -21,7 +21,7 @@
   });
 
   apiFunctions.setCustomCallback('openPopup',
-      function(name, callback, response) {
+      function(callback, response) {
     if (!callback)
       return;
 
diff --git a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js
index 70a05543d..123f33a 100644
--- a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js
@@ -29,7 +29,7 @@
   var apiFunctions = bindingsAPI.apiFunctions;
 
   apiFunctions.setCustomCallback('searchDrive',
-      function(name, callback, response) {
+      function(callback, response) {
     if (response && !response.error && response.entries) {
       response.entries = response.entries.map(function(entry) {
         return GetExternalFileEntry(entry);
@@ -45,7 +45,7 @@
   });
 
   apiFunctions.setCustomCallback('searchDriveMetadata',
-      function(name, callback, response) {
+      function(callback, response) {
     if (response && !response.error) {
       for (var i = 0; i < response.length; i++) {
         response[i].entry =
@@ -313,7 +313,7 @@
   });
 
   apiFunctions.setCustomCallback('searchFiles',
-      function(name, callback, response) {
+      function(callback, response) {
     if (response && !response.error && response.entries) {
       response.entries = response.entries.map(function(entry) {
         return GetExternalFileEntry(entry);
diff --git a/chrome/renderer/resources/extensions/input.ime_custom_bindings.js b/chrome/renderer/resources/extensions/input.ime_custom_bindings.js
index 0a64b8c..c5d870a 100644
--- a/chrome/renderer/resources/extensions/input.ime_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/input.ime_custom_bindings.js
@@ -41,7 +41,7 @@
   };
 
   api.apiFunctions.setCustomCallback('createWindow',
-      function(name, callback, windowParams) {
+      function(callback, windowParams) {
     if (!callback) {
       return;
     }
diff --git a/chrome/renderer/resources/extensions/media_galleries_custom_bindings.js b/chrome/renderer/resources/extensions/media_galleries_custom_bindings.js
index 53be944..157e81c7 100644
--- a/chrome/renderer/resources/extensions/media_galleries_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/media_galleries_custom_bindings.js
@@ -32,14 +32,14 @@
   // getMediaFileSystems and addUserSelectedFolder use a custom callback so that
   // they can instantiate and return an array of file system objects.
   apiFunctions.setCustomCallback('getMediaFileSystems',
-                                 function(name, callback, response) {
+                                 function(callback, response) {
     var result = createFileSystemObjectsAndUpdateMetadata(response);
     if (callback)
       callback(result);
   });
 
   apiFunctions.setCustomCallback('addUserSelectedFolder',
-      function(name, callback, response) {
+      function(callback, response) {
     var fileSystems = [];
     var selectedFileSystemName = "";
     if (response && 'mediaFileSystems' in response &&
@@ -70,7 +70,7 @@
     };
   });
 
-  function getMetadataCallback(uuid, name, callback, response) {
+  function getMetadataCallback(uuid, callback, response) {
     if (response && response.attachedImagesBlobInfo) {
       for (var i = 0; i < response.attachedImagesBlobInfo.length; i++) {
         var blobInfo = response.attachedImagesBlobInfo[i];
diff --git a/chrome/renderer/resources/extensions/page_capture_custom_bindings.js b/chrome/renderer/resources/extensions/page_capture_custom_bindings.js
index a669fec..dce5d91 100644
--- a/chrome/renderer/resources/extensions/page_capture_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/page_capture_custom_bindings.js
@@ -13,7 +13,7 @@
   var apiFunctions = bindingsAPI.apiFunctions;
 
   apiFunctions.setCustomCallback('saveAsMHTML',
-      function(name,  callback, response) {
+      function(callback, response) {
     var requestId;
     if (response) {
       requestId = response.requestId;
diff --git a/chrome/renderer/resources/extensions/sync_file_system_custom_bindings.js b/chrome/renderer/resources/extensions/sync_file_system_custom_bindings.js
index c55c850..582f83a 100644
--- a/chrome/renderer/resources/extensions/sync_file_system_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/sync_file_system_custom_bindings.js
@@ -45,7 +45,7 @@
 
   // Functions which return an [instanceOf=DOMFileSystem].
   apiFunctions.setCustomCallback('requestFileSystem',
-      function(name, callback, response) {
+      function(callback, response) {
     var result = null;
     if (response) {
       result = syncFileSystemNatives.GetSyncFileSystemObject(
@@ -58,7 +58,7 @@
   // Functions which return an array of FileStatusInfo object
   // which has [instanceOf=FileEntry].
   apiFunctions.setCustomCallback('getFileStatuses',
-      function(name, callback, response) {
+      function(callback, response) {
     var results = [];
     if (response) {
       for (var i = 0; i < response.length; i++) {
diff --git a/chrome/renderer/resources/extensions/tab_capture_custom_bindings.js b/chrome/renderer/resources/extensions/tab_capture_custom_bindings.js
index b380a18f..f6594be 100644
--- a/chrome/renderer/resources/extensions/tab_capture_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/tab_capture_custom_bindings.js
@@ -7,7 +7,7 @@
 apiBridge.registerCustomHook(function(bindingsAPI, extensionId) {
   var apiFunctions = bindingsAPI.apiFunctions;
 
-  function proxyToGetUserMedia(name, callback, response) {
+  function proxyToGetUserMedia(callback, response) {
     if (!callback)
       return;
 
@@ -24,7 +24,7 @@
       if (!error || (typeof error.message !== 'string'))
         return fallbackMessage;
       return error.message.replace(/(navigator\.)?(webkit)?GetUserMedia/gi,
-                                   name);
+                                   'tabCapture.capture');
     }
 
     var options = {};
diff --git a/chrome/renderer/resources/plugins/play.png b/chrome/renderer/resources/plugins/play.png
deleted file mode 100644
index fa19179..0000000
--- a/chrome/renderer/resources/plugins/play.png
+++ /dev/null
Binary files differ
diff --git a/chrome/renderer/resources/plugins/youtube.png b/chrome/renderer/resources/plugins/youtube.png
deleted file mode 100644
index f2c28eb..0000000
--- a/chrome/renderer/resources/plugins/youtube.png
+++ /dev/null
Binary files differ
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 643b74db..d8463fa3 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1600,7 +1600,6 @@
       "../browser/media/webrtc/media_stream_devices_controller_browsertest.cc",
       "../browser/media/webrtc/test_stats_dictionary_unittest.cc",
       "../browser/media/webrtc/webrtc_apprtc_browsertest.cc",
-      "../browser/media/webrtc/webrtc_browsertest.cc",
       "../browser/media/webrtc/webrtc_browsertest_perf.cc",
       "../browser/media/webrtc/webrtc_browsertest_perf.h",
       "../browser/media/webrtc/webrtc_browsertest_perf_unittest.cc",
@@ -2208,7 +2207,10 @@
         "//chrome/browser/web_applications/app_service",
         "//chromeos/ui/frame",
       ]
-      sources += [ "../browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc" ]
+      sources += [
+        "../browser/download/notification/download_notification_browsertest.cc",
+        "../browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc",
+      ]
     }
 
     if (is_linux && !is_chromeos_lacros) {
@@ -3368,7 +3370,6 @@
         "../browser/chromeos/policy/dlp/mock_dlp_rules_manager.cc",
         "../browser/chromeos/policy/dlp/mock_dlp_rules_manager.h",
         "../browser/device_api/device_attribute_api_browsertest.cc",
-        "../browser/download/notification/download_notification_browsertest.cc",
         "../browser/drive/drive_notification_manager_factory_browsertest.cc",
         "../browser/extensions/api/certificate_provider/certificate_provider_apitest.cc",
         "../browser/extensions/api/file_manager/file_browser_handler_api_ash_test.cc",
@@ -3603,6 +3604,8 @@
         "//ash/app_list:test_support",
         "//ash/app_list/model:app_list_model",
         "//ash/components/arc:arc_test_support",
+        "//ash/components/attestation",
+        "//ash/components/attestation:test_support",
         "//ash/components/audio",
         "//ash/components/drivefs",
         "//ash/components/drivefs:test_support",
@@ -3654,8 +3657,7 @@
         "//chrome/services/wilco_dtc_supportd/public/mojom",
         "//chromeos:test_support",
         "//chromeos/assistant:buildflags",
-        "//chromeos/attestation",
-        "//chromeos/attestation:test_support",
+        "//chromeos/components/quick_answers/public/cpp:cpp",
         "//chromeos/cryptohome",
         "//chromeos/dbus:test_support",
         "//chromeos/dbus/attestation",
@@ -3696,6 +3698,7 @@
         "//chromeos/ui/frame:test_support",
         "//chromeos/ui/wm",
         "//components/app_restore",
+        "//components/arc:arc_test_support",
         "//components/arc/enterprise",
         "//components/crash/content/browser/error_reporting:mock_crash_endpoint",
         "//components/device_event_log",
@@ -5010,6 +5013,7 @@
   if (is_chromeos) {
     sources += [
       "../browser/apps/intent_helper/metrics/intent_handling_metrics_unittest.cc",
+      "../browser/download/notification/download_item_notification_unittest.cc",
       "../browser/policy/system_features_disable_list_policy_handler_unittest.cc",
       "chromeos/printing/fake_local_printer_chromeos.cc",
       "chromeos/printing/fake_local_printer_chromeos.h",
@@ -5615,6 +5619,7 @@
       "../browser/signin/dice_signed_in_profile_creator_unittest.cc",
       "../browser/signin/dice_tab_helper_unittest.cc",
       "../browser/signin/dice_web_signin_interceptor_unittest.cc",
+      "../browser/signin/logout_tab_helper_unittest.cc",
       "../browser/signin/process_dice_header_delegate_impl_unittest.cc",
       "../browser/signin/signin_manager_unittest.cc",
       "../browser/ui/passwords/account_storage_auth_helper_unittest.cc",
@@ -6638,12 +6643,14 @@
       "//chrome/services/sharing/nearby/platform:unit_tests",
       "//chromeos/assistant:buildflags",
       "//chromeos/components/quick_answers:quick_answers",
+      "//chromeos/components/quick_answers/public/cpp:cpp",
       "//chromeos/constants",
       "//chromeos/dbus/image_loader",
       "//chromeos/dbus/u2f",
       "//chromeos/services/nearby/public/cpp:test_support",
       "//chromeos/ui/wm",
       "//components/app_restore:unit_tests",
+      "//components/arc:arc_test_support",
       "//components/soda:soda",
     ]
   }
@@ -7353,6 +7360,7 @@
 
   if (is_linux || is_chromeos_ash || is_mac || is_win) {
     sources += [
+      "../browser/enterprise/connectors/device_trust/device_trust_connector_service_unittest.cc",
       "../browser/enterprise/connectors/device_trust/device_trust_service_unittest.cc",
       "../browser/enterprise/connectors/device_trust/navigation_throttle_unittest.cc",
       "../browser/enterprise/connectors/device_trust/signals/signals_service_impl_unittest.cc",
@@ -7781,8 +7789,8 @@
       "../browser/ui/views/toolbar/chrome_labs_bubble_view_model_unittest.cc",
       "../browser/ui/views/toolbar/chrome_labs_bubble_view_unittest.cc",
       "../browser/ui/views/toolbar/chrome_labs_button_unittest.cc",
-      "../browser/ui/views/toolbar/read_later_toolbar_button_unittest.cc",
       "../browser/ui/views/toolbar/reload_button_unittest.cc",
+      "../browser/ui/views/toolbar/side_panel_toolbar_button_unittest.cc",
       "../browser/ui/views/toolbar/toolbar_action_view_unittest.cc",
       "../browser/ui/views/toolbar/toolbar_actions_bar_bubble_views_unittest.cc",
       "../browser/ui/views/toolbar/toolbar_button_unittest.cc",
@@ -8307,6 +8315,7 @@
       "../browser/extensions/window_open_interactive_apitest.cc",
       "../browser/focus_ring_browsertest.cc",
       "../browser/media/webrtc/media_stream_permission_interactive_uitest.cc",
+      "../browser/media/webrtc/webrtc_interactive_uitest.cc",
       "../browser/media/webrtc/webrtc_mediadevices_interactive_uitest.cc",
       "../browser/mouse_events_interactive_uitest.cc",
       "../browser/notifications/platform_notification_service_interactive_uitest.cc",
@@ -8550,6 +8559,7 @@
         "../browser/ui/views/certificate_selector_browsertest.cc",
         "../browser/ui/views/commander_frontend_views_browsertest.cc",
         "../browser/ui/views/constrained_window_views_browsertest.cc",
+        "../browser/ui/views/content_setting_bubble_contents_interactive_uitest.cc",
         "../browser/ui/views/exclusive_access_bubble_views_interactive_uitest.cc",
         "../browser/ui/views/extensions/extension_dialog_interactive_uitest.cc",
         "../browser/ui/views/extensions/extensions_toolbar_container_interactive_uitest.cc",
diff --git a/chrome/test/base/chrome_render_view_host_test_harness.h b/chrome/test/base/chrome_render_view_host_test_harness.h
index 8d0c525..a50e8df 100644
--- a/chrome/test/base/chrome_render_view_host_test_harness.h
+++ b/chrome/test/base/chrome_render_view_host_test_harness.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <utility>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_renderer_host.h"
 
diff --git a/chrome/test/base/chrome_test_utils.h b/chrome/test/base/chrome_test_utils.h
index 1e05388..5b8c240 100644
--- a/chrome/test/base/chrome_test_utils.h
+++ b/chrome/test/base/chrome_test_utils.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_TEST_BASE_CHROME_TEST_UTILS_H_
 #define CHROME_TEST_BASE_CHROME_TEST_UTILS_H_
 
-#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "url/gurl.h"
 
diff --git a/chrome/test/base/chrome_unit_test_suite.h b/chrome/test/base/chrome_unit_test_suite.h
index 660d415..a1edcda 100644
--- a/chrome/test/base/chrome_unit_test_suite.h
+++ b/chrome/test/base/chrome_unit_test_suite.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_TEST_BASE_CHROME_UNIT_TEST_SUITE_H_
 #define CHROME_TEST_BASE_CHROME_UNIT_TEST_SUITE_H_
 
-#include "base/compiler_specific.h"
 #include "base/test/test_discardable_memory_allocator.h"
 #include "build/build_config.h"
 #include "chrome/test/base/chrome_test_suite.h"
diff --git a/chrome/test/chromedriver/chrome/adb_impl.h b/chrome/test/chromedriver/chrome/adb_impl.h
index fa53114..d39224b8 100644
--- a/chrome/test/chromedriver/chrome/adb_impl.h
+++ b/chrome/test/chromedriver/chrome/adb_impl.h
@@ -8,7 +8,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/test/chromedriver/chrome/adb.h"
 
diff --git a/chrome/test/chromedriver/chrome/chrome_android_impl.h b/chrome/test/chromedriver/chrome/chrome_android_impl.h
index e373c525..3621af23 100644
--- a/chrome/test/chromedriver/chrome/chrome_android_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_android_impl.h
@@ -9,7 +9,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/chrome_impl.h"
 
 class Device;
diff --git a/chrome/test/chromedriver/chrome/chrome_desktop_impl.h b/chrome/test/chromedriver/chrome/chrome_desktop_impl.h
index 5cea73b..e03f2070 100644
--- a/chrome/test/chromedriver/chrome/chrome_desktop_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_desktop_impl.h
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/command_line.h"
-#include "base/compiler_specific.h"
 #include "base/process/process.h"
 #include "chrome/test/chromedriver/chrome/chrome_impl.h"
 #include "chrome/test/chromedriver/chrome/scoped_temp_dir_with_retry.h"
diff --git a/chrome/test/chromedriver/chrome/chrome_impl.h b/chrome/test/chromedriver/chrome/chrome_impl.h
index e88037f6..2fd6624 100644
--- a/chrome/test/chromedriver/chrome/chrome_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_impl.h
@@ -10,7 +10,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/values.h"
 #include "chrome/test/chromedriver/chrome/chrome.h"
 
diff --git a/chrome/test/chromedriver/chrome/chrome_remote_impl.h b/chrome/test/chromedriver/chrome/chrome_remote_impl.h
index 88228b20..5abbe9d 100644
--- a/chrome/test/chromedriver/chrome/chrome_remote_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_remote_impl.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/chrome_impl.h"
 
 class DevToolsClient;
diff --git a/chrome/test/chromedriver/chrome/console_logger.h b/chrome/test/chromedriver/chrome/console_logger.h
index e0b7f6be..21c7dd06 100644
--- a/chrome/test/chromedriver/chrome/console_logger.h
+++ b/chrome/test/chromedriver/chrome/console_logger.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_TEST_CHROMEDRIVER_CHROME_CONSOLE_LOGGER_H_
 #define CHROME_TEST_CHROMEDRIVER_CHROME_CONSOLE_LOGGER_H_
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 
 class Log;
diff --git a/chrome/test/chromedriver/chrome/device_manager.h b/chrome/test/chromedriver/chrome/device_manager.h
index 39d62e8..3cea815 100644
--- a/chrome/test/chromedriver/chrome/device_manager.h
+++ b/chrome/test/chromedriver/chrome/device_manager.h
@@ -10,7 +10,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
 
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.h b/chrome/test/chromedriver/chrome/devtools_client_impl.h
index d79584d..5cec8af 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.h
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.h
@@ -11,7 +11,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
 #include "chrome/test/chromedriver/chrome/devtools_client.h"
diff --git a/chrome/test/chromedriver/chrome/dom_tracker.h b/chrome/test/chromedriver/chrome/dom_tracker.h
index c87ca422..5e24a5dd 100644
--- a/chrome/test/chromedriver/chrome/dom_tracker.h
+++ b/chrome/test/chromedriver/chrome/dom_tracker.h
@@ -8,7 +8,6 @@
 #include <map>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 
 namespace base {
diff --git a/chrome/test/chromedriver/chrome/download_directory_override_manager.h b/chrome/test/chromedriver/chrome/download_directory_override_manager.h
index dbcdfce..198c35a 100644
--- a/chrome/test/chromedriver/chrome/download_directory_override_manager.h
+++ b/chrome/test/chromedriver/chrome/download_directory_override_manager.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/browser_info.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 
diff --git a/chrome/test/chromedriver/chrome/frame_tracker.h b/chrome/test/chromedriver/chrome/frame_tracker.h
index 7cfe3cd..35d6b3de 100644
--- a/chrome/test/chromedriver/chrome/frame_tracker.h
+++ b/chrome/test/chromedriver/chrome/frame_tracker.h
@@ -9,7 +9,6 @@
 #include <string>
 #include <unordered_set>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 #include "chrome/test/chromedriver/chrome/web_view.h"
 
diff --git a/chrome/test/chromedriver/chrome/geolocation_override_manager.h b/chrome/test/chromedriver/chrome/geolocation_override_manager.h
index 543594c..ee13d8b1 100644
--- a/chrome/test/chromedriver/chrome/geolocation_override_manager.h
+++ b/chrome/test/chromedriver/chrome/geolocation_override_manager.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 
 namespace base {
diff --git a/chrome/test/chromedriver/chrome/heap_snapshot_taker.h b/chrome/test/chromedriver/chrome/heap_snapshot_taker.h
index 2d4ecd1..6105b382 100644
--- a/chrome/test/chromedriver/chrome/heap_snapshot_taker.h
+++ b/chrome/test/chromedriver/chrome/heap_snapshot_taker.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 
 namespace base {
diff --git a/chrome/test/chromedriver/chrome/javascript_dialog_manager.h b/chrome/test/chromedriver/chrome/javascript_dialog_manager.h
index c851023..ba41320 100644
--- a/chrome/test/chromedriver/chrome/javascript_dialog_manager.h
+++ b/chrome/test/chromedriver/chrome/javascript_dialog_manager.h
@@ -8,7 +8,6 @@
 #include <list>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 
 namespace base {
diff --git a/chrome/test/chromedriver/chrome/log.h b/chrome/test/chromedriver/chrome/log.h
index 10b7cb29..de7667e 100644
--- a/chrome/test/chromedriver/chrome/log.h
+++ b/chrome/test/chromedriver/chrome/log.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/time/time.h"
 
 namespace base {
diff --git a/chrome/test/chromedriver/chrome/mobile_emulation_override_manager.h b/chrome/test/chromedriver/chrome/mobile_emulation_override_manager.h
index 06d4523..bba82f4 100644
--- a/chrome/test/chromedriver/chrome/mobile_emulation_override_manager.h
+++ b/chrome/test/chromedriver/chrome/mobile_emulation_override_manager.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 
 namespace base {
diff --git a/chrome/test/chromedriver/chrome/navigation_tracker.h b/chrome/test/chromedriver/chrome/navigation_tracker.h
index 3b0b021..d502f92 100644
--- a/chrome/test/chromedriver/chrome/navigation_tracker.h
+++ b/chrome/test/chromedriver/chrome/navigation_tracker.h
@@ -9,7 +9,6 @@
 #include <string>
 #include <unordered_map>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 #include "chrome/test/chromedriver/chrome/page_load_strategy.h"
 #include "chrome/test/chromedriver/chrome/status.h"
diff --git a/chrome/test/chromedriver/chrome/network_conditions_override_manager.h b/chrome/test/chromedriver/chrome/network_conditions_override_manager.h
index bbf9629..49322fa 100644
--- a/chrome/test/chromedriver/chrome/network_conditions_override_manager.h
+++ b/chrome/test/chromedriver/chrome/network_conditions_override_manager.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 
 namespace base {
diff --git a/chrome/test/chromedriver/chrome/stub_chrome.h b/chrome/test/chromedriver/chrome/stub_chrome.h
index 7da93d7..fdf10b80 100644
--- a/chrome/test/chromedriver/chrome/stub_chrome.h
+++ b/chrome/test/chromedriver/chrome/stub_chrome.h
@@ -8,7 +8,6 @@
 #include <list>
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/browser_info.h"
 #include "chrome/test/chromedriver/chrome/chrome.h"
 
diff --git a/chrome/test/chromedriver/chrome/stub_devtools_client.h b/chrome/test/chromedriver/chrome/stub_devtools_client.h
index 30ac7a93..e6e79aa1 100644
--- a/chrome/test/chromedriver/chrome/stub_devtools_client.h
+++ b/chrome/test/chromedriver/chrome/stub_devtools_client.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/devtools_client.h"
 
 namespace base {
diff --git a/chrome/test/chromedriver/chrome/stub_web_view.h b/chrome/test/chromedriver/chrome/stub_web_view.h
index 17e1f7f05..b3649bae 100644
--- a/chrome/test/chromedriver/chrome/stub_web_view.h
+++ b/chrome/test/chromedriver/chrome/stub_web_view.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/web_view.h"
 
 class StubWebView : public WebView {
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.h b/chrome/test/chromedriver/chrome/web_view_impl.h
index b2af2a4..09853881 100644
--- a/chrome/test/chromedriver/chrome/web_view_impl.h
+++ b/chrome/test/chromedriver/chrome/web_view_impl.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/chrome/web_view.h"
 
 namespace base {
diff --git a/chrome/test/chromedriver/command_listener_proxy.h b/chrome/test/chromedriver/command_listener_proxy.h
index b247e84..3f02367 100644
--- a/chrome/test/chromedriver/command_listener_proxy.h
+++ b/chrome/test/chromedriver/command_listener_proxy.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/command_listener.h"
 
 class CommandListenerProxy : public CommandListener {
diff --git a/chrome/test/chromedriver/devtools_events_logger.h b/chrome/test/chromedriver/devtools_events_logger.h
index 2d4d121..b54daa9 100644
--- a/chrome/test/chromedriver/devtools_events_logger.h
+++ b/chrome/test/chromedriver/devtools_events_logger.h
@@ -8,7 +8,6 @@
 #include <string>
 #include <unordered_set>
 
-#include "base/compiler_specific.h"
 #include "base/values.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 #include "chrome/test/chromedriver/chrome/log.h"
diff --git a/chrome/test/chromedriver/net/pipe_handler.h b/chrome/test/chromedriver/net/pipe_handler.h
index b4bc8a8..fcfe618 100644
--- a/chrome/test/chromedriver/net/pipe_handler.h
+++ b/chrome/test/chromedriver/net/pipe_handler.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/test/chromedriver/net/websocket.h"
 
diff --git a/chrome/test/chromedriver/net/sync_websocket_impl.h b/chrome/test/chromedriver/net/sync_websocket_impl.h
index 01c363e..ad419408 100644
--- a/chrome/test/chromedriver/net/sync_websocket_impl.h
+++ b/chrome/test/chromedriver/net/sync_websocket_impl.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
diff --git a/chrome/test/chromedriver/net/test_http_server.h b/chrome/test/chromedriver/net/test_http_server.h
index a64bd3d..bc82055 100644
--- a/chrome/test/chromedriver/net/test_http_server.h
+++ b/chrome/test/chromedriver/net/test_http_server.h
@@ -7,7 +7,6 @@
 
 #include <set>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
diff --git a/chrome/test/chromedriver/net/url_request_context_getter.h b/chrome/test/chromedriver/net/url_request_context_getter.h
index ad1989d9..6c4edbf 100644
--- a/chrome/test/chromedriver/net/url_request_context_getter.h
+++ b/chrome/test/chromedriver/net/url_request_context_getter.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/compiler_specific.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/task/single_thread_task_runner.h"
 #include "net/url_request/url_request_context_getter.h"
diff --git a/chrome/test/chromedriver/net/websocket.h b/chrome/test/chromedriver/net/websocket.h
index eb774e2..58ed34d4 100644
--- a/chrome/test/chromedriver/net/websocket.h
+++ b/chrome/test/chromedriver/net/websocket.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_checker.h"
 #include "net/base/completion_once_callback.h"
diff --git a/chrome/test/chromedriver/performance_logger.h b/chrome/test/chromedriver/performance_logger.h
index 8526768..1e43298 100644
--- a/chrome/test/chromedriver/performance_logger.h
+++ b/chrome/test/chromedriver/performance_logger.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/chromedriver/capabilities.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 #include "chrome/test/chromedriver/command_listener.h"
diff --git a/chrome/test/chromedriver/server/http_handler.h b/chrome/test/chromedriver/server/http_handler.h
index b136670c..fa7aa05 100644
--- a/chrome/test/chromedriver/server/http_handler.h
+++ b/chrome/test/chromedriver/server/http_handler.h
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index 0a5ddd74..872a6bed 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -235,7 +235,6 @@
     caps->SetBoolKey("locationContextEnabled", true);
     caps->SetBoolKey("mobileEmulationEnabled",
                      session->chrome->IsMobileEmulationEnabled());
-    caps->SetBoolKey("applicationCacheEnabled", false);
     caps->SetBoolKey("browserConnectionEnabled", false);
     caps->SetBoolKey("cssSelectorsEnabled", true);
     caps->SetBoolKey("webStorageEnabled", true);
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/line_start_offsets.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/line_start_offsets.js
index 8fe7b7f..f58bbbf 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/line_start_offsets.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/line_start_offsets.js
@@ -10,7 +10,8 @@
     assertTrue(!!input);
     assertTrue('lineStartOffsets' in input);
     var lineStarts = input.lineStartOffsets;
-    assertEq(0, lineStarts.length);
+    assertEq(1, lineStarts.length);
+    assertEq(0, lineStarts[0]);
     chrome.test.succeed();
   },
 
@@ -21,9 +22,10 @@
     assertTrue(!!textarea);
     assertTrue('lineStartOffsets' in textarea);
     var lineStarts = textarea.lineStartOffsets;
-    assertEq(2, lineStarts.length);
-    assertEq(10, lineStarts[0]);
-    assertEq(20, lineStarts[1]);
+    assertEq(3, lineStarts.length);
+    assertEq(0, lineStarts[0]);
+    assertEq(10, lineStarts[1]);
+    assertEq(20, lineStarts[2]);
     chrome.test.succeed();
   }
 ];
diff --git a/chrome/test/data/fenced_frames/iframe.html b/chrome/test/data/fenced_frames/iframe.html
new file mode 100644
index 0000000..21ea436
--- /dev/null
+++ b/chrome/test/data/fenced_frames/iframe.html
@@ -0,0 +1,4 @@
+<html><head><title>iframe test</title></head>
+<body>
+<iframe src="title1.html" id="test"></iframe>
+</body></html>
\ No newline at end of file
diff --git a/chrome/test/data/fenced_frames/iframe.html.mock-http-headers b/chrome/test/data/fenced_frames/iframe.html.mock-http-headers
new file mode 100644
index 0000000..263e89c4
--- /dev/null
+++ b/chrome/test/data/fenced_frames/iframe.html.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Supports-Loading-Mode: fenced-frame
\ No newline at end of file
diff --git a/chrome/test/data/fenced_frames/title2.html b/chrome/test/data/fenced_frames/title2.html
new file mode 100644
index 0000000..13823c92
--- /dev/null
+++ b/chrome/test/data/fenced_frames/title2.html
@@ -0,0 +1,4 @@
+<html>
+<head><title>Title Of Awesomeness</title></head>
+<body>This page has a title.</body>
+</html>
diff --git a/chrome/test/data/fenced_frames/title2.html.mock-http-headers b/chrome/test/data/fenced_frames/title2.html.mock-http-headers
new file mode 100644
index 0000000..263e89c4
--- /dev/null
+++ b/chrome/test/data/fenced_frames/title2.html.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Supports-Loading-Mode: fenced-frame
\ No newline at end of file
diff --git a/chrome/test/data/navigation_predictor/fenced_frames/anchors_different_area.html b/chrome/test/data/navigation_predictor/fenced_frames/anchors_different_area.html
new file mode 100644
index 0000000..c0daddb
--- /dev/null
+++ b/chrome/test/data/navigation_predictor/fenced_frames/anchors_different_area.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <a id="small" href="https://example.com/2"><img height="2" width="2"></a>
+    <a id="xlarge" href="https://google.com"><img height="5" width="5"></a>
+    <a id="xmall" href="https://example.com/1"><img height="1" width="1"></a>
+    <a id="medium" href="https://example.com"><img height="3" width="3"></a>
+    <a id="large" href="https://dummy.com"><img height="4" width="4"></a>
+  </body>
+</html>
\ No newline at end of file
diff --git a/chrome/test/data/navigation_predictor/fenced_frames/anchors_different_area.html.mock-http-headers b/chrome/test/data/navigation_predictor/fenced_frames/anchors_different_area.html.mock-http-headers
new file mode 100644
index 0000000..27f34d2
--- /dev/null
+++ b/chrome/test/data/navigation_predictor/fenced_frames/anchors_different_area.html.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Supports-Loading-Mode: fenced-frame
diff --git a/chrome/test/data/navigation_predictor/fenced_frames/simple_page_with_anchors.html b/chrome/test/data/navigation_predictor/fenced_frames/simple_page_with_anchors.html
new file mode 100644
index 0000000..54c67b36
--- /dev/null
+++ b/chrome/test/data/navigation_predictor/fenced_frames/simple_page_with_anchors.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <a id="google" href="https://google.com">Google</a>
+    <a id="example" href="https://example.com">Example</a>
+    <a id="example" href="simple_page_with_anchors.html">Same page</a>
+    <a id="example" href="simple_page_with_anchors.html#">Same page</a>
+    <a id="example" href="simple_page_with_anchors.html#foobar">Same page</a>
+  </body>
+</html>
\ No newline at end of file
diff --git a/chrome/test/data/navigation_predictor/fenced_frames/simple_page_with_anchors.html.mock-http-headers b/chrome/test/data/navigation_predictor/fenced_frames/simple_page_with_anchors.html.mock-http-headers
new file mode 100644
index 0000000..27f34d2
--- /dev/null
+++ b/chrome/test/data/navigation_predictor/fenced_frames/simple_page_with_anchors.html.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Supports-Loading-Mode: fenced-frame
diff --git a/chrome/test/data/webui/print_preview/BUILD.gn b/chrome/test/data/webui/print_preview/BUILD.gn
index db9746fce..9b099d2 100644
--- a/chrome/test/data/webui/print_preview/BUILD.gn
+++ b/chrome/test/data/webui/print_preview/BUILD.gn
@@ -36,10 +36,6 @@
   "cloud_print_interface_stub.ts",
   "copies_settings_test.ts",
   "custom_margins_test.ts",
-  "destination_dialog_cros_interactive_test.js",
-  "destination_dialog_cros_test.js",
-  "destination_dialog_interactive_test.js",
-  "destination_dialog_test.js",
   "destination_item_test.js",
   "destination_list_test.js",
   "destination_search_test.js",
@@ -76,6 +72,8 @@
 
 if (is_chromeos) {
   non_preprocessed_tests += [
+    "destination_dialog_cros_interactive_test.ts",
+    "destination_dialog_cros_test.ts",
     "destination_dropdown_cros_test.js",
     "destination_item_test_cros.js",
     "destination_search_test_chromeos.js",
@@ -85,6 +83,11 @@
     "pin_settings_test.js",
     "print_server_store_test.js",
   ]
+} else {
+  non_preprocessed_tests += [
+    "destination_dialog_interactive_test.ts",
+    "destination_dialog_test.ts",
+  ]
 }
 
 generate_grd("build_grdp") {
diff --git a/chrome/test/data/webui/print_preview/destination_dialog_cros_interactive_test.js b/chrome/test/data/webui/print_preview/destination_dialog_cros_interactive_test.ts
similarity index 67%
rename from chrome/test/data/webui/print_preview/destination_dialog_cros_interactive_test.js
rename to chrome/test/data/webui/print_preview/destination_dialog_cros_interactive_test.ts
index 8d3c66f..33d729b 100644
--- a/chrome/test/data/webui/print_preview/destination_dialog_cros_interactive_test.js
+++ b/chrome/test/data/webui/print_preview/destination_dialog_cros_interactive_test.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {CloudPrintInterfaceImpl, Destination, makeRecentDestination, NativeLayerImpl, PrintPreviewDestinationDialogCrosElement, PrintPreviewSearchBoxElement, State} from 'chrome://print/print_preview.js';
+import {CloudPrintInterfaceImpl, NativeLayerImpl, PrintPreviewDestinationDialogCrosElement, State} from 'chrome://print/print_preview.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
 
@@ -12,32 +12,30 @@
 import {CloudPrintInterfaceStub} from './cloud_print_interface_stub.js';
 import {setNativeLayerCrosInstance} from './native_layer_cros_stub.js';
 import {NativeLayerStub} from './native_layer_stub.js';
-import {getDestinations, setupTestListenerElement} from './print_preview_test_utils.js';
+import {setupTestListenerElement} from './print_preview_test_utils.js';
 
-window.destination_dialog_cros_interactive_test = {};
-const destination_dialog_cros_interactive_test =
-    window.destination_dialog_cros_interactive_test;
-destination_dialog_cros_interactive_test.suiteName =
-    'DestinationDialogCrosInteractiveTest';
-/** @enum {string} */
-destination_dialog_cros_interactive_test.TestNames = {
-  FocusSearchBox: 'focus search box',
-  EscapeSearchBox: 'escape search box',
+const destination_dialog_cros_interactive_test = {
+  suiteName: 'DestinationDialogCrosInteractiveTest',
+  TestNames: {
+    FocusSearchBox: 'focus search box',
+    EscapeSearchBox: 'escape search box',
+  },
 };
 
+Object.assign(window, {
+  destination_dialog_cros_interactive_test:
+      destination_dialog_cros_interactive_test
+});
+
 suite(destination_dialog_cros_interactive_test.suiteName, function() {
-  /** @type {!PrintPreviewDestinationDialogCrosElement} */
-  let dialog;
+  let dialog: PrintPreviewDestinationDialogCrosElement;
 
-  /** @type {!NativeLayerStub} */
-  let nativeLayer;
+  let nativeLayer: NativeLayerStub;
 
-  /** @override */
   suiteSetup(function() {
     setupTestListenerElement();
   });
 
-  /** @override */
   setup(function() {
     document.body.innerHTML = '';
 
@@ -45,10 +43,6 @@
     nativeLayer = new NativeLayerStub();
     NativeLayerImpl.setInstance(nativeLayer);
     setNativeLayerCrosInstance();
-    const localDestinations = [];
-    const destinations = getDestinations(localDestinations);
-    const recentDestinations = [makeRecentDestination(destinations[4])];
-    nativeLayer.setLocalDestinations(localDestinations);
     const cloudPrintInterface = new CloudPrintInterfaceStub();
     CloudPrintInterfaceImpl.setInstance(cloudPrintInterface);
     cloudPrintInterface.configure();
@@ -66,17 +60,13 @@
     document.body.appendChild(destinationSettings);
 
     // Initialize
-    destinationSettings.cloudPrintInterface = cloudPrintInterface;
     destinationSettings.init(
         'FooDevice' /* printerName */, false /* pdfPrinterDisabled */,
         true /* isDriveMounted */,
-        '' /* serializedDefaultDestinationSelectionRulesStr */,
-        [] /* userAccounts */, true /* syncAvailable */);
+        '' /* serializedDefaultDestinationSelectionRulesStr */);
     return nativeLayer.whenCalled('getPrinterCapabilities').then(() => {
       // Retrieve a reference to dialog
-      dialog = /** @type {!PrintPreviewDestinationDialogCrosElement} */ (
-          destinationSettings.shadowRoot.querySelector('#destinationDialog')
-              .get());
+      dialog = destinationSettings.$.destinationDialog.get();
     });
   });
 
@@ -85,9 +75,7 @@
   test(
       assert(destination_dialog_cros_interactive_test.TestNames.FocusSearchBox),
       function() {
-        const searchInput = /** @type {!PrintPreviewSearchBoxElement} */ (
-                                dialog.shadowRoot.querySelector('#searchBox'))
-                                .getSearchInput();
+        const searchInput = dialog.$.searchBox.getSearchInput();
         assertTrue(!!searchInput);
         const whenFocusDone = eventToPromise('focus', searchInput);
         dialog.destinationStore.startLoadAllDestinations();
@@ -101,8 +89,7 @@
       assert(
           destination_dialog_cros_interactive_test.TestNames.EscapeSearchBox),
       function() {
-        const searchBox = /** @type {!PrintPreviewSearchBoxElement} */ (
-            dialog.shadowRoot.querySelector('#searchBox'));
+        const searchBox = dialog.$.searchBox;
         const searchInput = searchBox.getSearchInput();
         assertTrue(!!searchInput);
         const whenFocusDone = eventToPromise('focus', searchInput);
@@ -110,7 +97,7 @@
         dialog.show();
         return whenFocusDone
             .then(() => {
-              assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
+              assertTrue(dialog.$.dialog.open);
 
               // Put something in the search box.
               const whenSearchChanged =
@@ -128,7 +115,7 @@
             })
             .then(() => {
               // Dialog should still be open.
-              assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
+              assertTrue(dialog.$.dialog.open);
 
               // Clear the search box.
               const whenSearchChanged =
@@ -146,7 +133,7 @@
             })
             .then(() => {
               // Dialog is closed.
-              assertFalse(dialog.shadowRoot.querySelector('#dialog').open);
+              assertFalse(dialog.$.dialog.open);
             });
       });
 });
diff --git a/chrome/test/data/webui/print_preview/destination_dialog_cros_test.js b/chrome/test/data/webui/print_preview/destination_dialog_cros_test.ts
similarity index 71%
rename from chrome/test/data/webui/print_preview/destination_dialog_cros_test.js
rename to chrome/test/data/webui/print_preview/destination_dialog_cros_test.ts
index d4d41b9..a472f05 100644
--- a/chrome/test/data/webui/print_preview/destination_dialog_cros_test.js
+++ b/chrome/test/data/webui/print_preview/destination_dialog_cros_test.ts
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {Destination, DestinationConnectionStatus, DestinationOrigin, DestinationStore, DestinationStoreEventType, DestinationType, GooglePromotedDestinationId, makeRecentDestination, NativeLayerImpl, PrintPreviewDestinationDialogCrosElement, PrintPreviewSearchBoxElement} from 'chrome://print/print_preview.js';
+import {Destination, DestinationStore, DestinationStoreEventType, GooglePromotedDestinationId, LocalDestinationInfo, makeRecentDestination, NativeLayerImpl, PrintPreviewDestinationDialogCrosElement, PrintPreviewDestinationListItemElement, RecentDestination} from 'chrome://print/print_preview.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
-import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {keyEventOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -17,49 +16,41 @@
 import {NativeLayerStub} from './native_layer_stub.js';
 import {createDestinationStore, getCloudDestination, getDestinations, setupTestListenerElement} from './print_preview_test_utils.js';
 
-window.destination_dialog_cros_test = {};
-const destination_dialog_cros_test = window.destination_dialog_cros_test;
-destination_dialog_cros_test.suiteName = 'DestinationDialogCrosTest';
-/** @enum {string} */
-destination_dialog_cros_test.TestNames = {
-  PrinterList: 'PrinterList',
-  ShowProvisionalDialog: 'ShowProvisionalDialog',
-  UserAccounts: 'UserAccounts',
-  PrintServersChanged: 'PrintServersChanged',
-  PrintServerSelected: 'PrintServerSelected',
+const destination_dialog_cros_test = {
+  suiteName: 'DestinationDialogCrosTest',
+  TestNames: {
+    PrinterList: 'PrinterList',
+    ShowProvisionalDialog: 'ShowProvisionalDialog',
+    UserAccounts: 'UserAccounts',
+    PrintServersChanged: 'PrintServersChanged',
+    PrintServerSelected: 'PrintServerSelected',
+  },
 };
 
+Object.assign(
+    window, {destination_dialog_cros_test: destination_dialog_cros_test});
+
 suite(destination_dialog_cros_test.suiteName, function() {
-  /** @type {!PrintPreviewDestinationDialogCrosElement} */
-  let dialog;
+  let dialog: PrintPreviewDestinationDialogCrosElement;
 
-  /** @type {!DestinationStore} */
-  let destinationStore;
+  let destinationStore: DestinationStore;
 
-  /** @type {!NativeLayerStub} */
-  let nativeLayer;
+  let nativeLayer: NativeLayerStub;
 
-  /** @type {!NativeLayerCrosStub} */
-  let nativeLayerCros;
+  let nativeLayerCros: NativeLayerCrosStub;
 
-  /** @type {!CloudPrintInterfaceStub} */
-  let cloudPrintInterface;
+  let cloudPrintInterface: CloudPrintInterfaceStub;
 
-  /** @type {!Array<!Destination>} */
-  let destinations = [];
+  let destinations: Destination[] = [];
 
-  /** @type {!Array<!LocalDestinationInfo>} */
-  const localDestinations = [];
+  const localDestinations: LocalDestinationInfo[] = [];
 
-  /** @type {!Array<!RecentDestination>} */
-  let recentDestinations = [];
+  let recentDestinations: RecentDestination[] = [];
 
-  /** @override */
   suiteSetup(function() {
     setupTestListenerElement();
   });
 
-  /** @override */
   setup(function() {
     // Create data classes
     nativeLayer = new NativeLayerStub();
@@ -69,7 +60,7 @@
     destinationStore = createDestinationStore();
     destinationStore.setCloudPrintInterface(cloudPrintInterface);
     destinations = getDestinations(localDestinations);
-    recentDestinations = [makeRecentDestination(destinations[4])];
+    recentDestinations = [makeRecentDestination(destinations[4]!)];
     nativeLayer.setLocalDestinations(localDestinations);
     destinationStore.init(
         false /* pdfPrinterDisabled */, true /* isDriveMounted */,
@@ -78,8 +69,7 @@
         recentDestinations /* recentDestinations */);
 
     // Set up dialog
-    dialog = /** @type {!PrintPreviewDestinationDialogCrosElement} */ (
-        document.createElement('print-preview-destination-dialog-cros'));
+    dialog = document.createElement('print-preview-destination-dialog-cros');
     dialog.activeUser = '';
     dialog.users = [];
     dialog.destinationStore = destinationStore;
@@ -102,28 +92,29 @@
   test(assert(destination_dialog_cros_test.TestNames.PrinterList), async () => {
     await finishSetup();
     const list =
-        dialog.shadowRoot.querySelector('print-preview-destination-list');
+        dialog.shadowRoot!.querySelector('print-preview-destination-list')!;
 
-    const printerItems =
-        list.shadowRoot.querySelectorAll('print-preview-destination-list-item');
+    const printerItems = list.shadowRoot!.querySelectorAll(
+        'print-preview-destination-list-item');
 
-    const getDisplayedName = item =>
-        item.shadowRoot.querySelector('.name').textContent;
+    const getDisplayedName = (item: PrintPreviewDestinationListItemElement) =>
+        item.shadowRoot!.querySelector('.name')!.textContent;
     // 5 printers + Save as PDF
     assertEquals(6, printerItems.length);
     // Save as PDF shows up first.
     assertEquals(
         GooglePromotedDestinationId.SAVE_AS_PDF,
-        getDisplayedName(printerItems[0]));
+        getDisplayedName(printerItems[0]!));
     assertEquals(
         'rgb(32, 33, 36)',
         window
-            .getComputedStyle(printerItems[0].shadowRoot.querySelector('.name'))
+            .getComputedStyle(
+                printerItems[0]!.shadowRoot!.querySelector('.name')!)
             .color);
     Array.from(printerItems).slice(1, 5).forEach((item, index) => {
-      assertEquals(destinations[index].displayName, getDisplayedName(item));
+      assertEquals(destinations[index]!.displayName, getDisplayedName(item));
     });
-    assertEquals('FooName', getDisplayedName(printerItems[5]));
+    assertEquals('FooName', getDisplayedName(printerItems[5]!));
   });
 
   // Test that clicking a provisional destination shows the provisional
@@ -132,7 +123,6 @@
   test(
       assert(destination_dialog_cros_test.TestNames.ShowProvisionalDialog),
       async () => {
-        let provisionalDialog = null;
         const provisionalDestination = {
           extensionId: 'ABC123',
           extensionName: 'ABC Printing',
@@ -146,12 +136,12 @@
         nativeLayer.setExtensionDestinations([provisionalDestination]);
         await finishSetup();
         flush();
-        provisionalDialog = dialog.shadowRoot.querySelector(
-            'print-preview-provisional-destination-resolver');
-        assertFalse(provisionalDialog.shadowRoot.querySelector('#dialog').open);
+        const provisionalDialog = dialog.shadowRoot!.querySelector(
+            'print-preview-provisional-destination-resolver')!;
+        assertFalse(provisionalDialog.$.dialog.open);
         const list =
-            dialog.shadowRoot.querySelector('print-preview-destination-list');
-        const printerItems = list.shadowRoot.querySelectorAll(
+            dialog.shadowRoot!.querySelector('print-preview-destination-list')!;
+        const printerItems = list.shadowRoot!.querySelectorAll(
             'print-preview-destination-list-item');
 
         // Should have 5 local destinations, Save as PDF + extension
@@ -162,9 +152,9 @@
         });
 
         // Click the provisional destination to select it.
-        provisionalItem.click();
+        provisionalItem!.click();
         flush();
-        assertTrue(provisionalDialog.shadowRoot.querySelector('#dialog').open);
+        assertTrue(provisionalDialog.$.dialog.open);
 
         // Send escape key on provisionalDialog. Destinations dialog should
         // not close.
@@ -173,33 +163,36 @@
         flush();
         await whenClosed;
 
-        assertFalse(provisionalDialog.shadowRoot.querySelector('#dialog').open);
-        assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
+        assertFalse(provisionalDialog.$.dialog.open);
+        assertTrue(dialog.$.dialog.open);
       });
 
   /**
-   * @param {string} account The current active user account.
-   * @param {number} numUsers The total number of users that are signed in.
+   * @param account The current active user account.
+   * @param numUsers The total number of users that are signed in.
    */
-  function assertSignedInState(account, numUsers) {
+  function assertSignedInState(account: string, numUsers: number) {
     const signedIn = account !== '';
     assertEquals(
-        !signedIn, dialog.shadowRoot.querySelector('.user-info').hidden);
+        !signedIn,
+        dialog.shadowRoot!.querySelector<HTMLElement>('.user-info')!.hidden);
 
     if (numUsers > 0) {
-      const userSelect = dialog.shadowRoot.querySelector('.md-select');
-      const userSelectOptions = userSelect.querySelectorAll('option');
+      const userSelect =
+          dialog.shadowRoot!.querySelector<HTMLSelectElement>('.md-select')!;
+      const userSelectOptions =
+          userSelect.querySelectorAll<HTMLOptionElement>('option');
       assertEquals(numUsers + 1, userSelectOptions.length);
-      assertEquals('', userSelectOptions[numUsers].value);
+      assertEquals('', userSelectOptions[numUsers]!.value);
       assertEquals(account, userSelect.value);
     }
   }
 
-  /** @param {number} numPrinters The total number of available printers. */
-  function assertNumPrintersVisible(numPrinters) {
+  /** @param numPrinters The total number of available printers. */
+  function assertNumPrintersVisible(numPrinters: number) {
     const list =
-        dialog.shadowRoot.querySelector('print-preview-destination-list');
-    const printerItems = list.shadowRoot.querySelectorAll(
+        dialog.shadowRoot!.querySelector('print-preview-destination-list')!;
+    const printerItems = list.shadowRoot!.querySelectorAll(
         'print-preview-destination-list-item:not([hidden])');
     assertEquals(numPrinters, printerItems.length);
   }
@@ -219,13 +212,14 @@
             user2);
         cloudPrintInterface.setPrinter(driveDestination1);
         cloudPrintInterface.setPrinter(driveDestination2);
-        let userSelect = null;
 
         await finishSetup();
         // Check that the user dropdown is hidden when there are no active
         // users.
-        assertTrue(dialog.shadowRoot.querySelector('.user-info').hidden);
-        userSelect = dialog.shadowRoot.querySelector('.md-select');
+        assertTrue(dialog.shadowRoot!.querySelector<HTMLElement>(
+                                         '.user-info')!.hidden);
+        const userSelect =
+            dialog.shadowRoot!.querySelector<HTMLSelectElement>('.md-select')!;
 
         // Enable cloud print.
         assertSignedInState('', 0);
@@ -317,14 +311,17 @@
         });
         await waitAfterNextRender(dialog);
 
-        assertFalse(
-            dialog.shadowRoot.querySelector('.server-search-box-input').hidden);
+        assertFalse(dialog.shadowRoot!
+                        .querySelector<HTMLElement>(
+                            '.server-search-box-input')!.hidden);
         const serverSelector =
-            dialog.shadowRoot.querySelector('.server-search-box-input');
+            dialog.shadowRoot!.querySelector('.server-search-box-input')!;
         const serverSelections =
-            serverSelector.shadowRoot.querySelectorAll('.list-item');
-        assertEquals('Print Server 1', serverSelections[0].textContent.trim());
-        assertEquals('Print Server 2', serverSelections[1].textContent.trim());
+            serverSelector.shadowRoot!.querySelectorAll('.list-item');
+        assertEquals(
+            'Print Server 1', serverSelections[0]!.textContent!.trim());
+        assertEquals(
+            'Print Server 2', serverSelections[1]!.textContent!.trim());
       });
 
   // Tests that choosePrintServers is called when the print server searchable
@@ -349,7 +346,7 @@
 
         const pendingPrintServerId =
             nativeLayerCros.whenCalled('choosePrintServers');
-        dialog.shadowRoot.querySelector('cr-searchable-drop-down').value =
+        dialog.shadowRoot!.querySelector('cr-searchable-drop-down')!.value =
             'Print Server 2';
         await waitAfterNextRender(dialog);
 
diff --git a/chrome/test/data/webui/print_preview/destination_dialog_interactive_test.js b/chrome/test/data/webui/print_preview/destination_dialog_interactive_test.ts
similarity index 67%
rename from chrome/test/data/webui/print_preview/destination_dialog_interactive_test.js
rename to chrome/test/data/webui/print_preview/destination_dialog_interactive_test.ts
index c8432545..33556eb 100644
--- a/chrome/test/data/webui/print_preview/destination_dialog_interactive_test.js
+++ b/chrome/test/data/webui/print_preview/destination_dialog_interactive_test.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {CloudPrintInterfaceImpl, Destination, makeRecentDestination, NativeLayerImpl, PrintPreviewDestinationDialogElement, PrintPreviewSearchBoxElement, State} from 'chrome://print/print_preview.js';
+import {CloudPrintInterfaceImpl, NativeLayerImpl, PrintPreviewDestinationDialogElement, State} from 'chrome://print/print_preview.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
 
@@ -11,42 +11,35 @@
 
 import {CloudPrintInterfaceStub} from './cloud_print_interface_stub.js';
 import {NativeLayerStub} from './native_layer_stub.js';
-import {getDestinations, setupTestListenerElement} from './print_preview_test_utils.js';
+import {setupTestListenerElement} from './print_preview_test_utils.js';
 
-window.destination_dialog_interactive_test = {};
-const destination_dialog_interactive_test =
-    window.destination_dialog_interactive_test;
-destination_dialog_interactive_test.suiteName =
-    'DestinationDialogInteractiveTest';
-/** @enum {string} */
-destination_dialog_interactive_test.TestNames = {
-  FocusSearchBox: 'focus search box',
-  EscapeSearchBox: 'escape search box',
+const destination_dialog_interactive_test = {
+  suiteName: 'DestinationDialogInteractiveTest',
+  TestNames: {
+    FocusSearchBox: 'focus search box',
+    EscapeSearchBox: 'escape search box',
+  },
 };
 
+Object.assign(
+    window,
+    {destination_dialog_interactive_test: destination_dialog_interactive_test});
+
 suite(destination_dialog_interactive_test.suiteName, function() {
-  /** @type {!PrintPreviewDestinationDialogElement} */
-  let dialog;
+  let dialog: PrintPreviewDestinationDialogElement;
 
-  /** @type {!NativeLayerStub} */
-  let nativeLayer;
+  let nativeLayer: NativeLayerStub;
 
-  /** @override */
   suiteSetup(function() {
     setupTestListenerElement();
   });
 
-  /** @override */
   setup(function() {
     document.body.innerHTML = '';
 
     // Create destinations.
     nativeLayer = new NativeLayerStub();
     NativeLayerImpl.setInstance(nativeLayer);
-    const localDestinations = [];
-    const destinations = getDestinations(localDestinations);
-    const recentDestinations = [makeRecentDestination(destinations[4])];
-    nativeLayer.setLocalDestinations(localDestinations);
     const cloudPrintInterface = new CloudPrintInterfaceStub();
     CloudPrintInterfaceImpl.setInstance(cloudPrintInterface);
     cloudPrintInterface.configure();
@@ -64,17 +57,13 @@
     document.body.appendChild(destinationSettings);
 
     // Initialize
-    destinationSettings.cloudPrintInterface = cloudPrintInterface;
     destinationSettings.init(
         'FooDevice' /* printerName */, false /* pdfPrinterDisabled */,
         true /* isDriveMounted */,
-        '' /* serializedDefaultDestinationSelectionRulesStr */,
-        [] /* userAccounts */, true /* syncAvailable */);
+        '' /* serializedDefaultDestinationSelectionRulesStr */);
     return nativeLayer.whenCalled('getPrinterCapabilities').then(() => {
       // Retrieve a reference to dialog
-      dialog = /** @type {!PrintPreviewDestinationDialogElement} */ (
-          destinationSettings.shadowRoot.querySelector('#destinationDialog')
-              .get());
+      dialog = destinationSettings.$.destinationDialog.get();
     });
   });
 
@@ -83,9 +72,7 @@
   test(
       assert(destination_dialog_interactive_test.TestNames.FocusSearchBox),
       function() {
-        const searchInput = /** @type {!PrintPreviewSearchBoxElement} */ (
-                                dialog.shadowRoot.querySelector('#searchBox'))
-                                .getSearchInput();
+        const searchInput = dialog.$.searchBox.getSearchInput();
         assertTrue(!!searchInput);
         const whenFocusDone = eventToPromise('focus', searchInput);
         dialog.destinationStore.startLoadAllDestinations();
@@ -98,8 +85,7 @@
   test(
       assert(destination_dialog_interactive_test.TestNames.EscapeSearchBox),
       function() {
-        const searchBox = /** @type {!PrintPreviewSearchBoxElement} */ (
-            dialog.shadowRoot.querySelector('#searchBox'));
+        const searchBox = dialog.$.searchBox;
         const searchInput = searchBox.getSearchInput();
         assertTrue(!!searchInput);
         const whenFocusDone = eventToPromise('focus', searchInput);
@@ -107,7 +93,7 @@
         dialog.show();
         return whenFocusDone
             .then(() => {
-              assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
+              assertTrue(dialog.$.dialog.open);
 
               // Put something in the search box.
               const whenSearchChanged =
@@ -125,7 +111,7 @@
             })
             .then(() => {
               // Dialog should still be open.
-              assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
+              assertTrue(dialog.$.dialog.open);
 
               // Clear the search box.
               const whenSearchChanged =
@@ -143,7 +129,7 @@
             })
             .then(() => {
               // Dialog is closed.
-              assertFalse(dialog.shadowRoot.querySelector('#dialog').open);
+              assertFalse(dialog.$.dialog.open);
             });
       });
 });
diff --git a/chrome/test/data/webui/print_preview/destination_dialog_test.js b/chrome/test/data/webui/print_preview/destination_dialog_test.js
deleted file mode 100644
index f130fbb..0000000
--- a/chrome/test/data/webui/print_preview/destination_dialog_test.js
+++ /dev/null
@@ -1,299 +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.
-
-import {Destination, DestinationConnectionStatus, DestinationOrigin, DestinationStore, DestinationStoreEventType, DestinationType, GooglePromotedDestinationId, makeRecentDestination, NativeLayerImpl, PrintPreviewDestinationDialogElement} from 'chrome://print/print_preview.js';
-import {assert} from 'chrome://resources/js/assert.m.js';
-import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {keyEventOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
-import {eventToPromise} from 'chrome://webui-test/test_util.js';
-
-import {CloudPrintInterfaceStub} from './cloud_print_interface_stub.js';
-import {NativeLayerStub} from './native_layer_stub.js';
-import {createDestinationStore, getDestinations, getGoogleDriveDestination, setupTestListenerElement} from './print_preview_test_utils.js';
-
-window.destination_dialog_test = {};
-const destination_dialog_test = window.destination_dialog_test;
-destination_dialog_test.suiteName = 'DestinationDialogTest';
-/** @enum {string} */
-destination_dialog_test.TestNames = {
-  PrinterList: 'PrinterList',
-  ShowProvisionalDialog: 'ShowProvisionalDialog',
-  UserAccounts: 'UserAccounts',
-};
-
-suite(destination_dialog_test.suiteName, function() {
-  /** @type {!PrintPreviewDestinationDialogElement} */
-  let dialog;
-
-  /** @type {!DestinationStore} */
-  let destinationStore;
-
-  /** @type {!NativeLayerStub} */
-  let nativeLayer;
-
-  /** @type {!CloudPrintInterfaceStub} */
-  let cloudPrintInterface;
-
-  /** @type {!Array<!Destination>} */
-  let destinations = [];
-
-  /** @type {!Array<!LocalDestinationInfo>} */
-  const localDestinations = [];
-
-  /** @type {!Array<!RecentDestination>} */
-  let recentDestinations = [];
-
-  /** @override */
-  suiteSetup(function() {
-    setupTestListenerElement();
-  });
-
-  /** @override */
-  setup(function() {
-    // Create data classes
-    nativeLayer = new NativeLayerStub();
-    NativeLayerImpl.setInstance(nativeLayer);
-    cloudPrintInterface = new CloudPrintInterfaceStub();
-    destinationStore = createDestinationStore();
-    destinationStore.setCloudPrintInterface(cloudPrintInterface);
-    destinations = getDestinations(localDestinations);
-    recentDestinations = [makeRecentDestination(destinations[4])];
-    nativeLayer.setLocalDestinations(localDestinations);
-    destinationStore.init(
-        false /* pdfPrinterDisabled */, true /* isDriveMounted */,
-        'FooDevice' /* printerName */,
-        '' /* serializedDefaultDestinationSelectionRulesStr */,
-        recentDestinations /* recentDestinations */);
-
-    // Set up dialog
-    dialog = /** @type {!PrintPreviewDestinationDialogElement} */ (
-        document.createElement('print-preview-destination-dialog'));
-    dialog.activeUser = '';
-    dialog.users = [];
-    dialog.destinationStore = destinationStore;
-  });
-
-  function finishSetup() {
-    document.body.appendChild(dialog);
-    return nativeLayer.whenCalled('getPrinterCapabilities')
-        .then(function() {
-          destinationStore.startLoadAllDestinations();
-          dialog.show();
-          return nativeLayer.whenCalled('getPrinters');
-        })
-        .then(function() {
-          flush();
-        });
-  }
-
-  // Test that destinations are correctly displayed in the lists.
-  test(assert(destination_dialog_test.TestNames.PrinterList), async () => {
-    await finishSetup();
-    const list =
-        dialog.shadowRoot.querySelector('print-preview-destination-list');
-
-    const printerItems =
-        list.shadowRoot.querySelectorAll('print-preview-destination-list-item');
-
-    const getDisplayedName = item =>
-        item.shadowRoot.querySelector('.name').textContent;
-    // 5 printers + Save as PDF
-    assertEquals(6, printerItems.length);
-    // Save as PDF shows up first.
-    assertEquals(
-        GooglePromotedDestinationId.SAVE_AS_PDF,
-        getDisplayedName(printerItems[0]));
-    assertEquals(
-        'rgb(32, 33, 36)',
-        window
-            .getComputedStyle(printerItems[0].shadowRoot.querySelector('.name'))
-            .color);
-    Array.from(printerItems).slice(1, 5).forEach((item, index) => {
-      assertEquals(destinations[index].displayName, getDisplayedName(item));
-    });
-    assertEquals('FooName', getDisplayedName(printerItems[5]));
-  });
-
-  // Test that clicking a provisional destination shows the provisional
-  // destinations dialog, and that the escape key closes only the provisional
-  // dialog when it is open, not the destinations dialog.
-  test(
-      assert(destination_dialog_test.TestNames.ShowProvisionalDialog),
-      async () => {
-        let provisionalDialog = null;
-        const provisionalDestination = {
-          extensionId: 'ABC123',
-          extensionName: 'ABC Printing',
-          id: 'XYZDevice',
-          name: 'XYZ',
-          provisional: true,
-        };
-
-        // Set the extension destinations and force the destination store to
-        // reload printers.
-        nativeLayer.setExtensionDestinations([provisionalDestination]);
-        await finishSetup();
-        flush();
-        provisionalDialog = dialog.shadowRoot.querySelector(
-            'print-preview-provisional-destination-resolver');
-        assertFalse(provisionalDialog.shadowRoot.querySelector('#dialog').open);
-        const list =
-            dialog.shadowRoot.querySelector('print-preview-destination-list');
-        const printerItems = list.shadowRoot.querySelectorAll(
-            'print-preview-destination-list-item');
-
-        // Should have 5 local destinations, Save as PDF + extension
-        // destination.
-        assertEquals(7, printerItems.length);
-        const provisionalItem = Array.from(printerItems).find(printerItem => {
-          return printerItem.destination.id === provisionalDestination.id;
-        });
-
-        // Click the provisional destination to select it.
-        provisionalItem.click();
-        flush();
-        assertTrue(provisionalDialog.shadowRoot.querySelector('#dialog').open);
-
-        // Send escape key on provisionalDialog. Destinations dialog should
-        // not close.
-        const whenClosed = eventToPromise('close', provisionalDialog);
-        keyEventOn(provisionalDialog, 'keydown', 19, [], 'Escape');
-        flush();
-        await whenClosed;
-
-        assertFalse(provisionalDialog.shadowRoot.querySelector('#dialog').open);
-        assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
-      });
-
-  /**
-   * @param {string} account The current active user account.
-   * @param {number} numUsers The total number of users that are signed in.
-   */
-  function assertSignedInState(account, numUsers) {
-    const signedIn = account !== '';
-    assertEquals(
-        !signedIn, dialog.shadowRoot.querySelector('.user-info').hidden);
-
-    if (numUsers > 0) {
-      const userSelect = dialog.shadowRoot.querySelector('.md-select');
-      const userSelectOptions = userSelect.querySelectorAll('option');
-      assertEquals(numUsers + 1, userSelectOptions.length);
-      assertEquals('', userSelectOptions[numUsers].value);
-      assertEquals(account, userSelect.value);
-    }
-  }
-
-  /**
-   * @param {number} numPrinters The total number of available printers.
-   * @param {string} account The current active user account.
-   */
-  function assertNumPrintersWithDriveAccount(numPrinters, account) {
-    const list =
-        dialog.shadowRoot.querySelector('print-preview-destination-list');
-    const printerItems = list.shadowRoot.querySelectorAll(
-        'print-preview-destination-list-item:not([hidden])');
-    assertEquals(numPrinters, printerItems.length);
-
-    const drivePrinter = Array.from(printerItems).find(item => {
-      return item.destination.id === GooglePromotedDestinationId.DOCS;
-    });
-    assertEquals(!!drivePrinter, account !== '');
-    if (drivePrinter) {
-      assertEquals(account, drivePrinter.destination.account);
-    }
-  }
-
-  // Test that signing in and switching accounts works as expected.
-  test(assert(destination_dialog_test.TestNames.UserAccounts), async () => {
-    // Set up the cloud print interface with Google Drive printer for a couple
-    // different accounts.
-    const user1 = 'foo@chromium.org';
-    const user2 = 'bar@chromium.org';
-    cloudPrintInterface.setPrinter(getGoogleDriveDestination(user1));
-    cloudPrintInterface.setPrinter(getGoogleDriveDestination(user2));
-    let userSelect = null;
-
-    await finishSetup();
-    // Check that the user dropdown is hidden when there are no active users.
-    assertTrue(dialog.shadowRoot.querySelector('.user-info').hidden);
-    userSelect = dialog.shadowRoot.querySelector('.md-select');
-
-    // Enable cloud print.
-    assertSignedInState('', 0);
-    // Local, extension, and cloud (since
-    // startLoadAllDestinations() was called).
-    assertEquals(2, nativeLayer.getCallCount('getPrinters'));
-    assertEquals(1, cloudPrintInterface.getCallCount('search'));
-
-    // 6 printers, no Google drive (since not signed in).
-    assertNumPrintersWithDriveAccount(6, '');
-
-    // Set an active user.
-    destinationStore.setActiveUser(user1);
-    destinationStore.reloadUserCookieBasedDestinations(user1);
-    dialog.activeUser = user1;
-    dialog.users = [user1];
-    flush();
-
-    // Select shows the signed in user.
-    assertSignedInState(user1, 1);
-
-    // Now have 7 printers (Google Drive), with user1 signed in.
-    const expectedPrinters = 7;
-    assertNumPrintersWithDriveAccount(expectedPrinters, user1);
-    // Still 2 calls as extension and local printers don't get refreshed on
-    // sign in.
-    assertEquals(2, nativeLayer.getCallCount('getPrinters'));
-    // Cloud printers should have been re-fetched.
-    assertEquals(2, cloudPrintInterface.getCallCount('search'));
-
-    // Simulate signing into a second account.
-    userSelect.value = '';
-    userSelect.dispatchEvent(new CustomEvent('change'));
-
-    await nativeLayer.whenCalled('signIn');
-    // No new printer fetch until the user actually changes the active
-    // account.
-    assertEquals(2, nativeLayer.getCallCount('getPrinters'));
-    assertEquals(2, cloudPrintInterface.getCallCount('search'));
-    dialog.users = [user1, user2];
-    flush();
-
-    // Select shows the signed in user.
-    assertSignedInState(user1, 2);
-
-    // Still have 7 printers (Google Drive), with user1 signed in.
-    assertNumPrintersWithDriveAccount(expectedPrinters, user1);
-
-    // Select the second account.
-    const whenEventFired = eventToPromise('account-change', dialog);
-    userSelect.value = user2;
-    userSelect.dispatchEvent(new CustomEvent('change'));
-
-    await whenEventFired;
-    flush();
-
-    // This will all be done by app.js and user_manager.js in response
-    // to the account-change event.
-    destinationStore.setActiveUser(user2);
-    dialog.activeUser = user2;
-    const whenInserted = eventToPromise(
-        DestinationStoreEventType.DESTINATIONS_INSERTED, destinationStore);
-    destinationStore.reloadUserCookieBasedDestinations(user2);
-
-    await whenInserted;
-    flush();
-
-    assertSignedInState(user2, 2);
-
-    // 7 printers (Google Drive), with user2 signed in.
-    assertNumPrintersWithDriveAccount(expectedPrinters, user2);
-    assertEquals(2, nativeLayer.getCallCount('getPrinters'));
-    // Cloud print should have been queried again for the new account.
-    assertEquals(3, cloudPrintInterface.getCallCount('search'));
-  });
-});
diff --git a/chrome/test/data/webui/print_preview/destination_dialog_test.ts b/chrome/test/data/webui/print_preview/destination_dialog_test.ts
new file mode 100644
index 0000000..196dc449
--- /dev/null
+++ b/chrome/test/data/webui/print_preview/destination_dialog_test.ts
@@ -0,0 +1,245 @@
+// 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.
+
+import {Destination, DestinationStore, DestinationStoreEventType, GooglePromotedDestinationId, LocalDestinationInfo, makeRecentDestination, NativeLayerImpl, PrintPreviewDestinationDialogElement, PrintPreviewDestinationListItemElement, RecentDestination} from 'chrome://print/print_preview.js';
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {eventToPromise} from 'chrome://webui-test/test_util.js';
+
+import {CloudPrintInterfaceStub} from './cloud_print_interface_stub.js';
+import {NativeLayerStub} from './native_layer_stub.js';
+import {createDestinationStore, getDestinations, getGoogleDriveDestination, setupTestListenerElement} from './print_preview_test_utils.js';
+
+const destination_dialog_test = {
+  suiteName: 'DestinationDialogTest',
+  TestNames: {
+    PrinterList: 'PrinterList',
+    ShowProvisionalDialog: 'ShowProvisionalDialog',
+    UserAccounts: 'UserAccounts',
+  },
+};
+
+Object.assign(window, {destination_dialog_test: destination_dialog_test});
+
+suite(destination_dialog_test.suiteName, function() {
+  let dialog: PrintPreviewDestinationDialogElement;
+
+  let destinationStore: DestinationStore;
+
+  let nativeLayer: NativeLayerStub;
+
+  let cloudPrintInterface: CloudPrintInterfaceStub;
+
+  let destinations: Destination[] = [];
+
+  const localDestinations: LocalDestinationInfo[] = [];
+
+  let recentDestinations: RecentDestination[] = [];
+
+  suiteSetup(function() {
+    setupTestListenerElement();
+  });
+
+  setup(function() {
+    // Create data classes
+    nativeLayer = new NativeLayerStub();
+    NativeLayerImpl.setInstance(nativeLayer);
+    cloudPrintInterface = new CloudPrintInterfaceStub();
+    destinationStore = createDestinationStore();
+    destinationStore.setCloudPrintInterface(cloudPrintInterface);
+    destinations = getDestinations(localDestinations);
+    recentDestinations = [makeRecentDestination(destinations[4]!)];
+    nativeLayer.setLocalDestinations(localDestinations);
+    destinationStore.init(
+        false /* pdfPrinterDisabled */, true /* isDriveMounted */,
+        'FooDevice' /* printerName */,
+        '' /* serializedDefaultDestinationSelectionRulesStr */,
+        recentDestinations /* recentDestinations */);
+
+    // Set up dialog
+    dialog = document.createElement('print-preview-destination-dialog');
+    dialog.activeUser = '';
+    dialog.users = [];
+    dialog.destinationStore = destinationStore;
+  });
+
+  function finishSetup(): Promise<void> {
+    document.body.appendChild(dialog);
+    return nativeLayer.whenCalled('getPrinterCapabilities')
+        .then(function() {
+          destinationStore.startLoadAllDestinations();
+          dialog.show();
+          return nativeLayer.whenCalled('getPrinters');
+        })
+        .then(function() {
+          flush();
+        });
+  }
+
+  // Test that destinations are correctly displayed in the lists.
+  test(assert(destination_dialog_test.TestNames.PrinterList), async () => {
+    await finishSetup();
+    const list =
+        dialog.shadowRoot!.querySelector('print-preview-destination-list');
+
+    const printerItems = list!.shadowRoot!.querySelectorAll(
+        'print-preview-destination-list-item');
+
+    const getDisplayedName = (item: PrintPreviewDestinationListItemElement) =>
+        item.shadowRoot!.querySelector('.name')!.textContent;
+    // 5 printers + Save as PDF
+    assertEquals(6, printerItems.length);
+    // Save as PDF shows up first.
+    assertEquals(
+        GooglePromotedDestinationId.SAVE_AS_PDF,
+        getDisplayedName(printerItems[0]!));
+    assertEquals(
+        'rgb(32, 33, 36)',
+        window
+            .getComputedStyle(
+                printerItems[0]!.shadowRoot!.querySelector('.name')!)
+            .color);
+    Array.from(printerItems).slice(1, 5).forEach((item, index) => {
+      assertEquals(destinations[index]!.displayName, getDisplayedName(item));
+    });
+    assertEquals('FooName', getDisplayedName(printerItems[5]!));
+  });
+
+  /**
+   * @param account The current active user account.
+   * @param numUsers The total number of users that are signed in.
+   */
+  function assertSignedInState(account: string, numUsers: number) {
+    const signedIn = account !== '';
+    assertEquals(
+        !signedIn,
+        dialog.shadowRoot!.querySelector<HTMLElement>('.user-info')!.hidden);
+
+    if (numUsers > 0) {
+      const userSelect =
+          dialog.shadowRoot!.querySelector<HTMLSelectElement>('.md-select')!;
+      const userSelectOptions =
+          userSelect.querySelectorAll<HTMLOptionElement>('option');
+      assertEquals(numUsers + 1, userSelectOptions.length);
+      assertEquals('', userSelectOptions[numUsers]!.value);
+      assertEquals(account, userSelect.value);
+    }
+  }
+
+  /**
+   * @param numPrinters The total number of available printers.
+   * @param account The current active user account.
+   */
+  function assertNumPrintersWithDriveAccount(
+      numPrinters: number, account: string) {
+    const list =
+        dialog.shadowRoot!.querySelector('print-preview-destination-list')!;
+    const printerItems =
+        list.shadowRoot!
+            .querySelectorAll<PrintPreviewDestinationListItemElement>(
+                'print-preview-destination-list-item:not([hidden])');
+    assertEquals(numPrinters, printerItems.length);
+
+    const drivePrinter = Array.from(printerItems).find(item => {
+      return item.destination.id === GooglePromotedDestinationId.DOCS;
+    });
+    assertEquals(!!drivePrinter, account !== '');
+    if (drivePrinter) {
+      assertEquals(account, drivePrinter.destination.account);
+    }
+  }
+
+  // Test that signing in and switching accounts works as expected.
+  test(assert(destination_dialog_test.TestNames.UserAccounts), async () => {
+    // Set up the cloud print interface with Google Drive printer for a couple
+    // different accounts.
+    const user1 = 'foo@chromium.org';
+    const user2 = 'bar@chromium.org';
+    cloudPrintInterface.setPrinter(getGoogleDriveDestination(user1));
+    cloudPrintInterface.setPrinter(getGoogleDriveDestination(user2));
+
+    await finishSetup();
+    // Check that the user dropdown is hidden when there are no active users.
+    assertTrue(
+        dialog.shadowRoot!.querySelector<HTMLElement>('.user-info')!.hidden);
+    const userSelect =
+        dialog.shadowRoot!.querySelector<HTMLSelectElement>('.md-select')!;
+
+    // Enable cloud print.
+    assertSignedInState('', 0);
+    // Local, extension, and cloud (since
+    // startLoadAllDestinations() was called).
+    assertEquals(2, nativeLayer.getCallCount('getPrinters'));
+    assertEquals(1, cloudPrintInterface.getCallCount('search'));
+
+    // 6 printers, no Google drive (since not signed in).
+    assertNumPrintersWithDriveAccount(6, '');
+
+    // Set an active user.
+    destinationStore.setActiveUser(user1);
+    destinationStore.reloadUserCookieBasedDestinations(user1);
+    dialog.activeUser = user1;
+    dialog.users = [user1];
+    flush();
+
+    // Select shows the signed in user.
+    assertSignedInState(user1, 1);
+
+    // Now have 7 printers (Google Drive), with user1 signed in.
+    const expectedPrinters = 7;
+    assertNumPrintersWithDriveAccount(expectedPrinters, user1);
+    // Still 2 calls as extension and local printers don't get refreshed on
+    // sign in.
+    assertEquals(2, nativeLayer.getCallCount('getPrinters'));
+    // Cloud printers should have been re-fetched.
+    assertEquals(2, cloudPrintInterface.getCallCount('search'));
+
+    // Simulate signing into a second account.
+    userSelect.value = '';
+    userSelect.dispatchEvent(new CustomEvent('change'));
+
+    await nativeLayer.whenCalled('signIn');
+    // No new printer fetch until the user actually changes the active
+    // account.
+    assertEquals(2, nativeLayer.getCallCount('getPrinters'));
+    assertEquals(2, cloudPrintInterface.getCallCount('search'));
+    dialog.users = [user1, user2];
+    flush();
+
+    // Select shows the signed in user.
+    assertSignedInState(user1, 2);
+
+    // Still have 7 printers (Google Drive), with user1 signed in.
+    assertNumPrintersWithDriveAccount(expectedPrinters, user1);
+
+    // Select the second account.
+    const whenEventFired = eventToPromise('account-change', dialog);
+    userSelect.value = user2;
+    userSelect.dispatchEvent(new CustomEvent('change'));
+
+    await whenEventFired;
+    flush();
+
+    // This will all be done by app.js and user_manager.js in response
+    // to the account-change event.
+    destinationStore.setActiveUser(user2);
+    dialog.activeUser = user2;
+    const whenInserted = eventToPromise(
+        DestinationStoreEventType.DESTINATIONS_INSERTED, destinationStore);
+    destinationStore.reloadUserCookieBasedDestinations(user2);
+
+    await whenInserted;
+    flush();
+
+    assertSignedInState(user2, 2);
+
+    // 7 printers (Google Drive), with user2 signed in.
+    assertNumPrintersWithDriveAccount(expectedPrinters, user2);
+    assertEquals(2, nativeLayer.getCallCount('getPrinters'));
+    // Cloud print should have been queried again for the new account.
+    assertEquals(3, cloudPrintInterface.getCallCount('search'));
+  });
+});
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn
index 67192dd..c3a6eaf 100644
--- a/chrome/test/data/webui/settings/BUILD.gn
+++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -16,6 +16,7 @@
   "privacy_page_test.ts",
   "route_tests.js",
   "security_page_test.ts",
+  "settings_menu_test.ts",
   "settings_toggle_button_tests.ts",
   "site_list_entry_tests.ts",
   "test_about_page_browser_proxy.ts",
@@ -93,8 +94,7 @@
   "settings_animated_pages_test.js",
   "settings_category_default_radio_group_tests.js",
   "settings_main_test.js",
-  "settings_menu_interactive_ui_test.js",
-  "settings_menu_test.js",
+  "settings_menu_interactive_ui_test.ts",
   "settings_page_test_util.ts",
   "settings_slider_tests.ts",
   "settings_subpage_test.js",
diff --git a/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js b/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js
index f199b87..5e032c5 100644
--- a/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js
@@ -176,6 +176,34 @@
       return lifetimeBrowserProxy.whenCalled('relaunch');
     });
 
+    test('Rollback', async () => {
+      loadTimeData.overrideValues({
+        deviceManager: 'google.com',
+        isManaged: true,
+      });
+      await initNewPage();
+      const statusMessageEl = page.$$('#updateStatusMessage div');
+
+      const progress = 90;
+      fireStatusChanged(
+          UpdateStatus.UPDATING,
+          {progress: progress, powerwash: true, rollback: true});
+
+      assertEquals(
+          page.i18nAdvanced(
+              'aboutRollbackInProgress',
+              {substitutions: [page.deviceManager_, progress + '%']}),
+          statusMessageEl.innerHTML);
+
+      fireStatusChanged(
+          UpdateStatus.NEARLY_UPDATED, {powerwash: true, rollback: true});
+
+      assertEquals(
+          page.i18nAdvanced(
+              'aboutRollbackSuccess', {substitutions: [page.deviceManager_]}),
+          statusMessageEl.innerHTML);
+    });
+
     test('NoInternet', function() {
       assertTrue(page.$.updateStatusMessage.hidden);
       aboutBrowserProxy.sendStatusNoInternet();
diff --git a/chrome/test/data/webui/settings/settings_menu_interactive_ui_test.js b/chrome/test/data/webui/settings/settings_menu_interactive_ui_test.ts
similarity index 75%
rename from chrome/test/data/webui/settings/settings_menu_interactive_ui_test.js
rename to chrome/test/data/webui/settings/settings_menu_interactive_ui_test.ts
index 3bd03e9b..c333302 100644
--- a/chrome/test/data/webui/settings/settings_menu_interactive_ui_test.js
+++ b/chrome/test/data/webui/settings/settings_menu_interactive_ui_test.ts
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {pageVisibility} from 'chrome://settings/settings.js';
+import {pageVisibility, SettingsMenuElement} from 'chrome://settings/settings.js';
 import {assertEquals} from 'chrome://webui-test/chai_assert.js';
 
 suite('SettingsMenuInteractiveUITest', () => {
-  let settingsMenu;
+  let settingsMenu: SettingsMenuElement;
 
   setup(() => {
     document.body.innerHTML = '';
@@ -21,7 +21,7 @@
       autofill: true,
     });
     settingsMenu.focusFirstItem();
-    assertEquals(settingsMenu.$.people, settingsMenu.shadowRoot.activeElement);
+    assertEquals(settingsMenu.$.people, settingsMenu.shadowRoot!.activeElement);
 
     settingsMenu.pageVisibility = Object.assign({}, pageVisibility || {}, {
       people: false,
@@ -29,6 +29,6 @@
     });
     settingsMenu.focusFirstItem();
     assertEquals(
-        settingsMenu.$.autofill, settingsMenu.shadowRoot.activeElement);
+        settingsMenu.$.autofill, settingsMenu.shadowRoot!.activeElement);
   });
 });
diff --git a/chrome/test/data/webui/settings/settings_menu_test.js b/chrome/test/data/webui/settings/settings_menu_test.ts
similarity index 66%
rename from chrome/test/data/webui/settings/settings_menu_test.js
rename to chrome/test/data/webui/settings/settings_menu_test.ts
index 4f85bc57..824a2502 100644
--- a/chrome/test/data/webui/settings/settings_menu_test.js
+++ b/chrome/test/data/webui/settings/settings_menu_test.ts
@@ -5,17 +5,18 @@
 /** @fileoverview Runs tests for the settings menu. */
 
 // clang-format off
-import {isChromeOS, isLacros} from 'chrome://resources/js/cr.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {pageVisibility, Router, routes} from 'chrome://settings/settings.js';
+import {pageVisibility, Router, routes, SettingsMenuElement} from 'chrome://settings/settings.js';
+import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
+
 // clang-format on
 
 suite('SettingsMenu', function() {
-  let settingsMenu = null;
+  let settingsMenu: SettingsMenuElement;
 
   setup(function() {
-    PolymerTest.clearBody();
+    document.body.innerHTML = '';
     settingsMenu = document.createElement('settings-menu');
     settingsMenu.pageVisibility = pageVisibility;
     document.body.appendChild(settingsMenu);
@@ -39,8 +40,7 @@
   test('tapAdvanced', function() {
     assertFalse(settingsMenu.advancedOpened);
 
-    const advancedToggle =
-        settingsMenu.shadowRoot.querySelector('#advancedButton');
+    const advancedToggle = settingsMenu.$.advancedButton;
     assertTrue(!!advancedToggle);
 
     advancedToggle.click();
@@ -56,17 +56,17 @@
     // There should be different icons for a top level menu being open
     // vs. being closed. E.g. arrow-drop-up and arrow-drop-down.
     const ironIconElement =
-        settingsMenu.shadowRoot.querySelector('#advancedButton iron-icon');
+        settingsMenu.$.advancedButton.querySelector('iron-icon');
     assertTrue(!!ironIconElement);
 
     settingsMenu.advancedOpened = true;
     flush();
-    const openIcon = ironIconElement.icon;
+    const openIcon = ironIconElement!.icon;
     assertTrue(!!openIcon);
 
     settingsMenu.advancedOpened = false;
     flush();
-    assertNotEquals(openIcon, ironIconElement.icon);
+    assertNotEquals(openIcon, ironIconElement!.icon);
   });
 
   // Test that navigating via the paper menu always clears the current
@@ -74,7 +74,8 @@
   test('clearsUrlSearchParam', function() {
     // As of iron-selector 2.x, need to force iron-selector to update before
     // clicking items on it, or wait for 'iron-items-changed'
-    const ironSelector = settingsMenu.shadowRoot.querySelector('iron-selector');
+    const ironSelector =
+        settingsMenu.shadowRoot!.querySelector('iron-selector')!;
     ironSelector.forceSynchronousItemUpdate();
 
     const urlParams = new URLSearchParams('search=foo');
@@ -88,11 +89,11 @@
 });
 
 suite('SettingsMenuReset', function() {
-  let settingsMenu = null;
+  let settingsMenu: SettingsMenuElement;
 
   setup(function() {
-    PolymerTest.clearBody();
-    Router.getInstance().navigateTo(routes.RESET, '');
+    document.body.innerHTML = '';
+    Router.getInstance().navigateTo(routes.RESET, undefined);
     settingsMenu = document.createElement('settings-menu');
     document.body.appendChild(settingsMenu);
     flush();
@@ -104,28 +105,28 @@
 
   test('openResetSection', function() {
     const selector = settingsMenu.$.subMenu;
-    const path = new window.URL(selector.selected).pathname;
+    const path = new window.URL(selector.selected.toString()).pathname;
     assertEquals('/reset', path);
   });
 
   test('navigateToAnotherSection', function() {
     const selector = settingsMenu.$.subMenu;
-    let path = new window.URL(selector.selected).pathname;
+    let path = new window.URL(selector.selected.toString()).pathname;
     assertEquals('/reset', path);
 
-    Router.getInstance().navigateTo(routes.PEOPLE, '');
+    Router.getInstance().navigateTo(routes.PEOPLE, undefined);
     flush();
 
-    path = new window.URL(selector.selected).pathname;
+    path = new window.URL(selector.selected.toString()).pathname;
     assertEquals('/people', path);
   });
 
   test('navigateToBasic', function() {
     const selector = settingsMenu.$.subMenu;
-    const path = new window.URL(selector.selected).pathname;
+    const path = new window.URL(selector.selected.toString()).pathname;
     assertEquals('/reset', path);
 
-    Router.getInstance().navigateTo(routes.BASIC, '');
+    Router.getInstance().navigateTo(routes.BASIC, undefined);
     flush();
 
     // BASIC has no sub page selected.
@@ -133,37 +134,36 @@
   });
 
   test('pageVisibility', function() {
-    function assertPagesHidden(expectedHidden) {
+    function assertPagesHidden(expectedHidden: boolean) {
+      assertEquals(expectedHidden, settingsMenu.$.people.hidden);
       assertEquals(
           expectedHidden,
-          settingsMenu.shadowRoot.querySelector('#people').hidden);
+          settingsMenu.shadowRoot!.querySelector<HTMLElement>(
+                                      '#appearance')!.hidden);
       assertEquals(
           expectedHidden,
-          settingsMenu.shadowRoot.querySelector('#appearance').hidden);
+          settingsMenu.shadowRoot!.querySelector<HTMLElement>(
+                                      '#onStartup')!.hidden);
+      assertEquals(expectedHidden, settingsMenu.$.advancedButton.hidden);
+      assertEquals(expectedHidden, settingsMenu.$.advancedSubmenu.hidden);
       assertEquals(
           expectedHidden,
-          settingsMenu.shadowRoot.querySelector('#onStartup').hidden);
-      assertEquals(
-          expectedHidden,
-          settingsMenu.shadowRoot.querySelector('#advancedButton').hidden);
-      assertEquals(
-          expectedHidden,
-          settingsMenu.shadowRoot.querySelector('#advancedSubmenu').hidden);
-      assertEquals(
-          expectedHidden,
-          settingsMenu.shadowRoot.querySelector('#reset').hidden);
+          settingsMenu.shadowRoot!.querySelector<HTMLElement>(
+                                      '#reset')!.hidden);
 
       if (!loadTimeData.getBoolean('enableLandingPageRedesign')) {
         assertEquals(
             expectedHidden,
-            settingsMenu.shadowRoot.querySelector('#safetyCheck').hidden);
+            settingsMenu.shadowRoot!.querySelector<HTMLElement>(
+                                        '#safetyCheck')!.hidden);
       }
 
-      if (!isChromeOS && !isLacros) {
-        assertEquals(
-            expectedHidden,
-            settingsMenu.shadowRoot.querySelector('#defaultBrowser').hidden);
-      }
+      // <if expr="not chromeos and not lacros">
+      assertEquals(
+          expectedHidden,
+          settingsMenu.shadowRoot!
+              .querySelector<HTMLElement>('#defaultBrowser')!.hidden);
+      // </if>
     }
 
     // The default pageVisibility should not cause menu items to be hidden.
diff --git a/chrome/test/nacl/pnacl_header_test.h b/chrome/test/nacl/pnacl_header_test.h
index d848253..e45b5ee5 100644
--- a/chrome/test/nacl/pnacl_header_test.h
+++ b/chrome/test/nacl/pnacl_header_test.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "chrome/test/base/in_process_browser_test.h"
 
 namespace net {
diff --git a/chrome/test/ppapi/ppapi_test.h b/chrome/test/ppapi/ppapi_test.h
index b9fdd495..8f0bc4f 100644
--- a/chrome/test/ppapi/ppapi_test.h
+++ b/chrome/test/ppapi/ppapi_test.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/scoped_observation.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/updater/app/server/mac/service_delegate.mm b/chrome/updater/app/server/mac/service_delegate.mm
index 27d66834d..241b93b 100644
--- a/chrome/updater/app/server/mac/service_delegate.mm
+++ b/chrome/updater/app/server/mac/service_delegate.mm
@@ -141,6 +141,8 @@
 
 - (void)checkForUpdateWithAppID:(NSString* _Nonnull)appID
                        priority:(CRUPriorityWrapper* _Nonnull)priority
+        policySameVersionUpdate:
+            (CRUPolicySameVersionUpdateWrapper* _Nonnull)policySameVersionUpdate
                     updateState:(id<CRUUpdateStateObserving>)updateState
                           reply:(void (^_Nonnull)(int rc))reply {
   auto cb =
@@ -185,6 +187,7 @@
       FROM_HERE,
       base::BindOnce(&updater::UpdateService::Update, _service,
                      base::SysNSStringToUTF8(appID), [priority priority],
+                     [policySameVersionUpdate policySameVersionUpdate],
                      std::move(sccb), std::move(cb)));
 }
 
diff --git a/chrome/updater/app/server/mac/service_protocol.h b/chrome/updater/app/server/mac/service_protocol.h
index 85648f7..85aee5e2 100644
--- a/chrome/updater/app/server/mac/service_protocol.h
+++ b/chrome/updater/app/server/mac/service_protocol.h
@@ -13,6 +13,7 @@
 @class CRUUpdateStateObserver;
 @class CRUUpdateStateWrapper;
 @class CRUPriorityWrapper;
+@class CRUPolicySameVersionUpdateWrapper;
 
 // Protocol which observes the state of the XPC update checking service.
 @protocol CRUUpdateStateObserving <NSObject>
@@ -42,6 +43,8 @@
 // updates of progress and returns the result in the reply block.
 - (void)checkForUpdateWithAppID:(NSString* _Nonnull)appID
                        priority:(CRUPriorityWrapper* _Nonnull)priority
+        policySameVersionUpdate:
+            (CRUPolicySameVersionUpdateWrapper* _Nonnull)policySameVersionUpdate
                     updateState:(CRUUpdateStateObserver* _Nonnull)updateState
                           reply:(void (^_Nonnull)(int rc))reply;
 
diff --git a/chrome/updater/app/server/mac/service_protocol.mm b/chrome/updater/app/server/mac/service_protocol.mm
index fa47e8a0..d86549f 100644
--- a/chrome/updater/app/server/mac/service_protocol.mm
+++ b/chrome/updater/app/server/mac/service_protocol.mm
@@ -22,9 +22,10 @@
 
   [updateCheckingInterface
        setInterface:updateStateObservingInterface
-        forSelector:@selector(checkForUpdateWithAppID:
-                                             priority:updateState:reply:)
-      argumentIndex:2
+        forSelector:@selector
+        (checkForUpdateWithAppID:
+                        priority:policySameVersionUpdate:updateState:reply:)
+      argumentIndex:3
             ofReply:NO];
 
   return updateCheckingInterface;
diff --git a/chrome/updater/app/server/mac/update_service_wrappers.h b/chrome/updater/app/server/mac/update_service_wrappers.h
index 1ef4976..4a45b8dc 100644
--- a/chrome/updater/app/server/mac/update_service_wrappers.h
+++ b/chrome/updater/app/server/mac/update_service_wrappers.h
@@ -43,6 +43,16 @@
 
 @end
 
+@interface CRUPolicySameVersionUpdateWrapper : NSObject <NSSecureCoding>
+
+@property(readonly, nonatomic)
+    updater::UpdateService::PolicySameVersionUpdate policySameVersionUpdate;
+
+- (instancetype)initWithPolicySameVersionUpdate:
+    (updater::UpdateService::PolicySameVersionUpdate)policySameVersionUpdate;
+
+@end
+
 @interface CRUErrorCategoryWrapper : NSObject <NSSecureCoding>
 
 @property(readonly, nonatomic)
diff --git a/chrome/updater/app/server/mac/update_service_wrappers.mm b/chrome/updater/app/server/mac/update_service_wrappers.mm
index 1c61769a..5395616 100644
--- a/chrome/updater/app/server/mac/update_service_wrappers.mm
+++ b/chrome/updater/app/server/mac/update_service_wrappers.mm
@@ -26,6 +26,7 @@
 static NSString* const kCRUUpdateStateExtraCode = @"updateStateExtraCode";
 
 static NSString* const kCRUPriority = @"priority";
+static NSString* const kCRUPolicySameVersionUpdate = @"policySameVersionUpdate";
 static NSString* const kCRUErrorCategory = @"errorCategory";
 
 using StateChangeCallback =
@@ -314,7 +315,6 @@
   DCHECK([coder respondsToSelector:@selector(encodeInt:forKey:)]);
   [coder encodeInt:static_cast<NSInteger>(self.priority) forKey:kCRUPriority];
 }
-
 // Required for unit tests.
 - (BOOL)isEqual:(id)object {
   if (![object isMemberOfClass:[CRUPriorityWrapper class]]) {
@@ -331,6 +331,75 @@
 
 @end
 
+@implementation CRUPolicySameVersionUpdateWrapper
+
+@synthesize policySameVersionUpdate = _policySameVersionUpdate;
+
+// Wrapper for updater::UpdateService::PolicySameVersionUpdate.
+typedef NS_ENUM(NSInteger, CRUUpdatePolicySameVersionUpdateEnum) {
+  kCRUPolicySameVersionUpdateNotAllowed = static_cast<NSInteger>(
+      updater::UpdateService::PolicySameVersionUpdate::kNotAllowed),
+  kCRUPolicySameVersionUpdateAllowed = static_cast<NSInteger>(
+      updater::UpdateService::PolicySameVersionUpdate::kAllowed),
+};
+
+// Designated initializer.
+- (instancetype)initWithPolicySameVersionUpdate:
+    (updater::UpdateService::PolicySameVersionUpdate)policySameVersionUpdate {
+  if (self = [super init]) {
+    _policySameVersionUpdate = policySameVersionUpdate;
+  }
+  return self;
+}
+
++ (BOOL)supportsSecureCoding {
+  return YES;
+}
+
+- (instancetype)initWithCoder:(NSCoder*)aDecoder {
+  DCHECK([aDecoder allowsKeyedCoding]);
+  NSInteger enumValue =
+      [aDecoder decodeIntegerForKey:kCRUPolicySameVersionUpdate];
+
+  switch (enumValue) {
+    case kCRUPolicySameVersionUpdateNotAllowed:
+      return [self
+          initWithPolicySameVersionUpdate:
+              updater::UpdateService::PolicySameVersionUpdate::kNotAllowed];
+    case kCRUPolicySameVersionUpdateAllowed:
+      return
+          [self initWithPolicySameVersionUpdate:
+                    updater::UpdateService::PolicySameVersionUpdate::kAllowed];
+    default:
+      DLOG(ERROR)
+          << "Unexpected value for CRUUpdatePolicySameVersionUpdateEnum: "
+          << enumValue;
+      return nil;
+  }
+}
+- (void)encodeWithCoder:(NSCoder*)coder {
+  DCHECK([coder respondsToSelector:@selector(encodeInt:forKey:)]);
+  [coder encodeInt:static_cast<NSInteger>(self.policySameVersionUpdate)
+            forKey:kCRUPolicySameVersionUpdate];
+}
+// Required for unit tests.
+- (BOOL)isEqual:(id)object {
+  if (![object isMemberOfClass:[CRUPolicySameVersionUpdateWrapper class]]) {
+    return NO;
+  }
+  CRUPolicySameVersionUpdateWrapper* otherPolicySameVersionUpdateWrapper =
+      object;
+  return self.policySameVersionUpdate ==
+         otherPolicySameVersionUpdateWrapper.policySameVersionUpdate;
+}
+
+// Required because isEqual is overridden.
+- (NSUInteger)hash {
+  return static_cast<NSUInteger>(_policySameVersionUpdate);
+}
+
+@end
+
 @implementation CRUErrorCategoryWrapper
 
 @synthesize errorCategory = _errorCategory;
diff --git a/chrome/updater/app/server/win/com_classes.cc b/chrome/updater/app/server/win/com_classes.cc
index 8e5690a..7e17335 100644
--- a/chrome/updater/app/server/win/com_classes.cc
+++ b/chrome/updater/app/server/win/com_classes.cc
@@ -22,6 +22,7 @@
 #include "base/win/scoped_bstr.h"
 #include "chrome/updater/app/server/win/server.h"
 #include "chrome/updater/registration_data.h"
+#include "chrome/updater/update_service.h"
 #include "chrome/updater/updater_version.h"
 #include "chrome/updater/win/win_util.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -296,6 +297,7 @@
              const std::string& app_id, IUpdaterObserverPtr observer) {
             update_service->Update(
                 app_id, UpdateService::Priority::kForeground,
+                UpdateService::PolicySameVersionUpdate::kNotAllowed,
                 base::BindRepeating(&StateChangeCallbackFilter::OnStateChange,
                                     base::Owned(new StateChangeCallbackFilter(
                                         task_runner, observer))),
diff --git a/chrome/updater/app/server/win/com_classes_legacy.cc b/chrome/updater/app/server/win/com_classes_legacy.cc
index e611427..a959d36 100644
--- a/chrome/updater/app/server/win/com_classes_legacy.cc
+++ b/chrome/updater/app/server/win/com_classes_legacy.cc
@@ -19,6 +19,7 @@
 #include "base/win/scoped_process_information.h"
 #include "chrome/updater/app/server/win/server.h"
 #include "chrome/updater/constants.h"
+#include "chrome/updater/update_service.h"
 #include "chrome/updater/win/win_constants.h"
 #include "chrome/updater/win/win_util.h"
 
@@ -172,6 +173,7 @@
              LegacyOnDemandImplPtr obj) {
             update_service->Update(
                 obj->app_id(), UpdateService::Priority::kForeground,
+                UpdateService::PolicySameVersionUpdate::kNotAllowed,
                 base::BindRepeating(
                     [](LegacyOnDemandImplPtr obj,
                        const UpdateService::UpdateState& state_update) {
diff --git a/chrome/updater/installer.cc b/chrome/updater/installer.cc
index c3ee69f..63f199c 100644
--- a/chrome/updater/installer.cc
+++ b/chrome/updater/installer.cc
@@ -19,6 +19,7 @@
 #include "build/build_config.h"
 #include "chrome/updater/action_handler.h"
 #include "chrome/updater/constants.h"
+#include "chrome/updater/update_service.h"
 #include "chrome/updater/updater_scope.h"
 #include "chrome/updater/util.h"
 #include "components/crx_file/crx_verifier.h"
@@ -48,18 +49,21 @@
 
 }  // namespace
 
-Installer::Installer(const std::string& app_id,
-                     const std::string& target_channel,
-                     const std::string& target_version_prefix,
-                     bool rollback_allowed,
-                     bool update_disabled,
-                     scoped_refptr<PersistedData> persisted_data)
+Installer::Installer(
+    const std::string& app_id,
+    const std::string& target_channel,
+    const std::string& target_version_prefix,
+    bool rollback_allowed,
+    bool update_disabled,
+    UpdateService::PolicySameVersionUpdate policy_same_version_update,
+    scoped_refptr<PersistedData> persisted_data)
     : updater_scope_(GetUpdaterScope()),
       app_id_(app_id),
       rollback_allowed_(rollback_allowed),
       target_channel_(target_channel),
       target_version_prefix_(target_version_prefix),
       update_disabled_(update_disabled),
+      policy_same_version_update_(policy_same_version_update),
       persisted_data_(persisted_data) {}
 
 Installer::~Installer() {
@@ -97,6 +101,9 @@
   component.fingerprint = fingerprint_;
   component.channel = target_channel_;
   component.rollback_allowed = rollback_allowed_;
+  component.same_version_update_allowed =
+      policy_same_version_update_ ==
+      UpdateService::PolicySameVersionUpdate::kAllowed;
   component.target_version_prefix = target_version_prefix_;
   component.supports_group_policy_enable_component_updates = update_disabled_;
 
diff --git a/chrome/updater/installer.h b/chrome/updater/installer.h
index 32a0244..d74e6ac1 100644
--- a/chrome/updater/installer.h
+++ b/chrome/updater/installer.h
@@ -15,6 +15,7 @@
 #include "base/version.h"
 #include "build/build_config.h"
 #include "chrome/updater/persisted_data.h"
+#include "chrome/updater/update_service.h"
 #include "chrome/updater/updater_scope.h"
 #include "components/update_client/update_client.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -42,6 +43,7 @@
             const std::string& target_version_prefix,
             bool rollback_allowed,
             bool update_disabled,
+            UpdateService::PolicySameVersionUpdate policy_same_version_update,
             scoped_refptr<PersistedData> persisted_data);
   Installer(const Installer&) = delete;
   Installer& operator=(const Installer&) = delete;
@@ -110,6 +112,7 @@
   const std::string target_channel_;
   const std::string target_version_prefix_;
   const bool update_disabled_;
+  const UpdateService::PolicySameVersionUpdate policy_same_version_update_;
   scoped_refptr<PersistedData> persisted_data_;
 
   // These members are not updated when the installer succeeds.
diff --git a/chrome/updater/mac/keystone/ksadmin.mm b/chrome/updater/mac/keystone/ksadmin.mm
index 12317f5..df31351 100644
--- a/chrome/updater/mac/keystone/ksadmin.mm
+++ b/chrome/updater/mac/keystone/ksadmin.mm
@@ -216,6 +216,7 @@
       app_id,
       HasSwitch(kCommandUserInitiated) ? UpdateService::Priority::kForeground
                                        : UpdateService::Priority::kBackground,
+      UpdateService::PolicySameVersionUpdate::kNotAllowed,
       base::BindRepeating([](const UpdateService::UpdateState& update_state) {
         if (update_state.state == UpdateService::UpdateState::State::kUpdated) {
           printf("Finished updating (errors=%d reboot=%s)\n", 0, "YES");
diff --git a/chrome/updater/mac/update_service_proxy.h b/chrome/updater/mac/update_service_proxy.h
index bda3097..5eb0e0a5 100644
--- a/chrome/updater/mac/update_service_proxy.h
+++ b/chrome/updater/mac/update_service_proxy.h
@@ -45,6 +45,7 @@
   void UpdateAll(StateChangeCallback state_update, Callback callback) override;
   void Update(const std::string& app_id,
               Priority priority,
+              PolicySameVersionUpdate policy_same_version_update,
               StateChangeCallback state_update,
               Callback callback) override;
   void Uninitialize() override;
diff --git a/chrome/updater/mac/update_service_proxy.mm b/chrome/updater/mac/update_service_proxy.mm
index cf33ab30..fff3d81 100644
--- a/chrome/updater/mac/update_service_proxy.mm
+++ b/chrome/updater/mac/update_service_proxy.mm
@@ -138,6 +138,8 @@
 
 - (void)checkForUpdateWithAppID:(NSString* _Nonnull)appID
                        priority:(CRUPriorityWrapper* _Nonnull)priority
+        policySameVersionUpdate:
+            (CRUPolicySameVersionUpdateWrapper* _Nonnull)policySameVersionUpdate
                     updateState:
                         (id<CRUUpdateStateObserving> _Nonnull)updateState
                           reply:(void (^_Nonnull)(int rc))reply {
@@ -150,6 +152,7 @@
   [[_updateCheckXPCConnection remoteObjectProxyWithErrorHandler:errorHandler]
       checkForUpdateWithAppID:appID
                      priority:priority
+      policySameVersionUpdate:policySameVersionUpdate
                   updateState:updateState
                         reply:reply];
 }
@@ -236,10 +239,12 @@
   [client_ checkForUpdatesWithUpdateState:stateObserver.get() reply:reply];
 }
 
-void UpdateServiceProxy::Update(const std::string& app_id,
-                                UpdateService::Priority priority,
-                                StateChangeCallback state_update,
-                                Callback callback) {
+void UpdateServiceProxy::Update(
+    const std::string& app_id,
+    UpdateService::Priority priority,
+    PolicySameVersionUpdate policy_same_version_update,
+    StateChangeCallback state_update,
+    Callback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   __block base::OnceCallback<void(UpdateService::Result)> block_callback =
@@ -252,6 +257,9 @@
 
   base::scoped_nsobject<CRUPriorityWrapper> priorityWrapper(
       [[CRUPriorityWrapper alloc] initWithPriority:priority]);
+  base::scoped_nsobject<CRUPolicySameVersionUpdateWrapper>
+      policySameVersionUpdateWrapper([[CRUPolicySameVersionUpdateWrapper alloc]
+          initWithPolicySameVersionUpdate:policy_same_version_update]);
   base::scoped_nsprotocol<id<CRUUpdateStateObserving>> stateObserver(
       [[CRUUpdateStateObserver alloc]
           initWithRepeatingCallback:state_update
@@ -259,6 +267,7 @@
 
   [client_ checkForUpdateWithAppID:SysUTF8ToNSString(app_id)
                           priority:priorityWrapper.get()
+           policySameVersionUpdate:policySameVersionUpdateWrapper.get()
                        updateState:stateObserver.get()
                              reply:reply];
 }
diff --git a/chrome/updater/mac/update_service_proxy_test.mm b/chrome/updater/mac/update_service_proxy_test.mm
index 74a1f44..863dace 100644
--- a/chrome/updater/mac/update_service_proxy_test.mm
+++ b/chrome/updater/mac/update_service_proxy_test.mm
@@ -500,6 +500,10 @@
   base::scoped_nsobject<CRUPriorityWrapper> wrapped_priority(
       [[CRUPriorityWrapper alloc]
           initWithPriority:UpdateService::Priority::kForeground]);
+  base::scoped_nsobject<CRUPolicySameVersionUpdateWrapper>
+      wrapped_policySameVersionUpdate([[CRUPolicySameVersionUpdateWrapper alloc]
+          initWithPolicySameVersionUpdate:
+              UpdateService::PolicySameVersionUpdate::kNotAllowed]);
   StateChangeTestEngine state_change_engine(
       std::vector<StateChangeTestEngine::StatePair>{
           CheckingForUpdatesStates(test_app_id), UpdateFoundStates(test_app_id),
@@ -519,6 +523,7 @@
   OCMExpect([mock_remote_object
                 checkForUpdateWithAppID:base::SysUTF8ToNSString(test_app_id)
                                priority:wrapped_priority.get()
+                policySameVersionUpdate:wrapped_policySameVersionUpdate.get()
                             updateState:update_state_observer_capturer.Capture()
                                   reply:reply_block_capturer.Capture()])
       .andDo(^(NSInvocation*) {
@@ -533,6 +538,7 @@
   base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindLambdaForTesting([this, &state_change_engine]() {
         service_->Update("test_app_id", UpdateService::Priority::kForeground,
+                         UpdateService::PolicySameVersionUpdate::kNotAllowed,
                          state_change_engine.Watch(),
                          base::BindLambdaForTesting(
                              [this](UpdateService::Result actual_result) {
diff --git a/chrome/updater/test/integration_tests_impl.cc b/chrome/updater/test/integration_tests_impl.cc
index 77894bc..49db120 100644
--- a/chrome/updater/test/integration_tests_impl.cc
+++ b/chrome/updater/test/integration_tests_impl.cc
@@ -199,7 +199,8 @@
   scoped_refptr<UpdateService> update_service = CreateUpdateServiceProxy(scope);
   base::RunLoop loop;
   update_service->Update(
-      app_id, UpdateService::Priority::kForeground, base::DoNothing(),
+      app_id, UpdateService::Priority::kForeground,
+      UpdateService::PolicySameVersionUpdate::kNotAllowed, base::DoNothing(),
       base::BindOnce(base::BindLambdaForTesting(
           [&loop](UpdateService::Result result_unused) { loop.Quit(); })));
   loop.Run();
diff --git a/chrome/updater/update_service.h b/chrome/updater/update_service.h
index b38e044..a711cb6f 100644
--- a/chrome/updater/update_service.h
+++ b/chrome/updater/update_service.h
@@ -12,6 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/version.h"
 #include "chrome/updater/enum_traits.h"
+#include "components/update_client/update_client.h"
 
 namespace updater {
 
@@ -24,6 +25,22 @@
 // All functions and callbacks must be called on the same sequence.
 class UpdateService : public base::RefCountedThreadSafe<UpdateService> {
  public:
+  // Defines the behavior of the update stack for over-installs.
+  // Typically, same versions updates are not allowed, in which case, the update
+  // server replies with `update not available'. But there are cases, such as
+  // re-installing an application again, when the server may respond with an
+  // update.
+  enum class PolicySameVersionUpdate {
+    // The embedder does not allow over-installs with the same version. In this
+    // case, the server is expected to return `update not available` when it
+    // is queried for updates.
+    kNotAllowed = 0,
+
+    // The embedder is capable of handling updates with the same version, and
+    // the server may respond with such an update.
+    kAllowed = 1,
+  };
+
   // Values posted by the completion |callback| as a result of the
   // non-blocking invocation of the service functions. These values are not
   // present in the telemetry pings.
@@ -202,6 +219,7 @@
   //    Result: the final result from the update engine.
   virtual void Update(const std::string& app_id,
                       Priority priority,
+                      PolicySameVersionUpdate policy_same_version_update,
                       StateChangeCallback state_update,
                       Callback callback) = 0;
 
diff --git a/chrome/updater/update_service_impl.cc b/chrome/updater/update_service_impl.cc
index c3311b7d..036ee76 100644
--- a/chrome/updater/update_service_impl.cc
+++ b/chrome/updater/update_service_impl.cc
@@ -144,6 +144,7 @@
     scoped_refptr<PersistedData> persisted_data,
     bool foreground,
     bool update_blocked,
+    UpdateService::PolicySameVersionUpdate policy_same_version_update,
     const std::vector<std::string>& ids) {
   std::vector<absl::optional<update_client::CrxComponent>> components;
   for (const auto& id : ids) {
@@ -183,7 +184,7 @@
                       (!foreground && policy == kPolicyManualUpdatesOnly) ||
                       (foreground && policy == kPolicyAutomaticUpdatesOnly));
             }(),
-            persisted_data)
+            policy_same_version_update, persisted_data)
             ->MakeCrxComponent());
   }
   return components;
@@ -287,14 +288,16 @@
   ShouldBlockUpdateForMeteredNetwork(
       priority,
       base::BindOnce(&UpdateServiceImpl::OnShouldBlockUpdateForMeteredNetwork,
-                     this, state_update, std::move(callback), app_ids,
-                     priority));
+                     this, state_update, std::move(callback), app_ids, priority,
+                     UpdateService::PolicySameVersionUpdate::kNotAllowed));
 }
 
-void UpdateServiceImpl::Update(const std::string& app_id,
-                               Priority priority,
-                               StateChangeCallback state_update,
-                               Callback callback) {
+void UpdateServiceImpl::Update(
+    const std::string& app_id,
+    Priority priority,
+    PolicySameVersionUpdate /*policy_same_version_update*/,
+    StateChangeCallback state_update,
+    Callback callback) {
   VLOG(1) << __func__;
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -302,7 +305,8 @@
   ShouldBlockUpdateForMeteredNetwork(
       priority,
       base::BindOnce(&UpdateServiceImpl::OnShouldBlockUpdateForMeteredNetwork,
-                     this, state_update, std::move(callback), ids, priority));
+                     this, state_update, std::move(callback), ids, priority,
+                     UpdateService::PolicySameVersionUpdate::kNotAllowed));
 }
 
 void UpdateServiceImpl::OnShouldBlockUpdateForMeteredNetwork(
@@ -310,6 +314,7 @@
     Callback callback,
     const std::vector<std::string>& ids,
     Priority priority,
+    PolicySameVersionUpdate policy_same_version_update,
     bool update_blocked) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -318,7 +323,7 @@
       base::BindOnce(
           &update_client::UpdateClient::Update, update_client_, ids,
           base::BindOnce(&GetComponents, config_, persisted_data_, false,
-                         update_blocked),
+                         update_blocked, policy_same_version_update),
           MakeUpdateClientCrxStateChangeCallback(config_, state_update),
           priority == Priority::kForeground,
           MakeUpdateClientCallback(std::move(callback))));
diff --git a/chrome/updater/update_service_impl.h b/chrome/updater/update_service_impl.h
index 5bfea9b..f11a72a 100644
--- a/chrome/updater/update_service_impl.h
+++ b/chrome/updater/update_service_impl.h
@@ -45,6 +45,7 @@
   void UpdateAll(StateChangeCallback state_update, Callback callback) override;
   void Update(const std::string& app_id,
               Priority priority,
+              PolicySameVersionUpdate policy_same_version_update,
               StateChangeCallback state_update,
               Callback callback) override;
 
@@ -59,11 +60,13 @@
   // Run `callback`, pops `tasks_`, and calls TaskStart.
   void TaskDone(base::OnceClosure callback);
 
-  void OnShouldBlockUpdateForMeteredNetwork(StateChangeCallback state_update,
-                                            Callback callback,
-                                            const std::vector<std::string>& ids,
-                                            Priority priority,
-                                            bool update_blocked);
+  void OnShouldBlockUpdateForMeteredNetwork(
+      StateChangeCallback state_update,
+      Callback callback,
+      const std::vector<std::string>& ids,
+      Priority priority,
+      PolicySameVersionUpdate policy_same_version_update,
+      bool update_blocked);
 
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/chrome/updater/update_service_impl_inactive.cc b/chrome/updater/update_service_impl_inactive.cc
index 16b6fd2..2fd27ca 100644
--- a/chrome/updater/update_service_impl_inactive.cc
+++ b/chrome/updater/update_service_impl_inactive.cc
@@ -48,8 +48,9 @@
   }
 
   void Update(const std::string& app_id,
-              Priority priority,
-              StateChangeCallback state_update,
+              Priority /*priority*/,
+              PolicySameVersionUpdate /*policy_same_version_update*/,
+              StateChangeCallback /*state_update*/,
               Callback callback) override {
     base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
diff --git a/chrome/updater/update_service_internal_impl_qualifying.cc b/chrome/updater/update_service_internal_impl_qualifying.cc
index a4c14af6..375f3bd 100644
--- a/chrome/updater/update_service_internal_impl_qualifying.cc
+++ b/chrome/updater/update_service_internal_impl_qualifying.cc
@@ -78,7 +78,8 @@
             base::BindOnce(&UpdateServiceImpl::Update,
                            base::MakeRefCounted<UpdateServiceImpl>(config_),
                            kQualificationAppId,
-                           updater::UpdateService::Priority::kBackground,
+                           UpdateService::Priority::kBackground,
+                           UpdateService::PolicySameVersionUpdate::kNotAllowed,
                            base::DoNothing()),
             base::BindOnce(
                 &UpdateServiceInternalQualifyingImpl::QualificationDone, this,
diff --git a/chrome/updater/win/app_install_controller.cc b/chrome/updater/win/app_install_controller.cc
index 4590981..5d3e2a5 100644
--- a/chrome/updater/win/app_install_controller.cc
+++ b/chrome/updater/win/app_install_controller.cc
@@ -485,6 +485,7 @@
 
   update_service_->Update(
       app_id_, UpdateService::Priority::kForeground,
+      UpdateService::PolicySameVersionUpdate::kNotAllowed,
       base::BindRepeating(&AppInstallControllerImpl::StateChange, this),
       base::BindOnce(&AppInstallControllerImpl::InstallComplete, this));
 }
diff --git a/chrome/updater/win/update_service_proxy.cc b/chrome/updater/win/update_service_proxy.cc
index 00ca229..5a9e80ee 100644
--- a/chrome/updater/win/update_service_proxy.cc
+++ b/chrome/updater/win/update_service_proxy.cc
@@ -394,10 +394,12 @@
           base::BindPostTask(main_task_runner_, std::move(callback))));
 }
 
-void UpdateServiceProxy::Update(const std::string& app_id,
-                                UpdateService::Priority /*priority*/,
-                                StateChangeCallback state_update,
-                                Callback callback) {
+void UpdateServiceProxy::Update(
+    const std::string& app_id,
+    UpdateService::Priority /*priority*/,
+    PolicySameVersionUpdate /*policy_same_version_update*/,
+    StateChangeCallback state_update,
+    Callback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_main_);
 
   // Reposts the call to the COM task runner. Adapts `callback` so that
diff --git a/chrome/updater/win/update_service_proxy.h b/chrome/updater/win/update_service_proxy.h
index a53c4316..612d5560 100644
--- a/chrome/updater/win/update_service_proxy.h
+++ b/chrome/updater/win/update_service_proxy.h
@@ -49,6 +49,7 @@
   void UpdateAll(StateChangeCallback state_update, Callback callback) override;
   void Update(const std::string& app_id,
               Priority priority,
+              PolicySameVersionUpdate policy_same_version_update,
               StateChangeCallback state_update,
               Callback callback) override;
   void Uninitialize() override;
diff --git a/chrome/utility/importer/bookmarks_file_importer.h b/chrome/utility/importer/bookmarks_file_importer.h
index 4094d6a..0998816 100644
--- a/chrome/utility/importer/bookmarks_file_importer.h
+++ b/chrome/utility/importer/bookmarks_file_importer.h
@@ -7,7 +7,6 @@
 
 #include <stdint.h>
 
-#include "base/compiler_specific.h"
 #include "chrome/utility/importer/importer.h"
 
 // Importer for bookmarks files.
diff --git a/chrome/utility/importer/edge_importer_win.h b/chrome/utility/importer/edge_importer_win.h
index c823a94..314cc4a 100644
--- a/chrome/utility/importer/edge_importer_win.h
+++ b/chrome/utility/importer/edge_importer_win.h
@@ -9,7 +9,6 @@
 
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "chrome/utility/importer/importer.h"
 #include "components/favicon_base/favicon_usage_data.h"
diff --git a/chrome/utility/importer/external_process_importer_bridge.h b/chrome/utility/importer/external_process_importer_bridge.h
index ce96def..11698063 100644
--- a/chrome/utility/importer/external_process_importer_bridge.h
+++ b/chrome/utility/importer/external_process_importer_bridge.h
@@ -8,7 +8,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "chrome/common/importer/importer_bridge.h"
 #include "chrome/common/importer/profile_import.mojom.h"
diff --git a/chrome/utility/importer/firefox_importer.h b/chrome/utility/importer/firefox_importer.h
index 0c2a518e..5a9ffd1 100644
--- a/chrome/utility/importer/firefox_importer.h
+++ b/chrome/utility/importer/firefox_importer.h
@@ -14,7 +14,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/gtest_prod_util.h"
diff --git a/chrome/utility/importer/ie_importer_win.h b/chrome/utility/importer/ie_importer_win.h
index 811d8e07..5319751 100644
--- a/chrome/utility/importer/ie_importer_win.h
+++ b/chrome/utility/importer/ie_importer_win.h
@@ -10,7 +10,6 @@
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
 #include "chrome/utility/importer/importer.h"
diff --git a/chrome/utility/importer/profile_import_impl.h b/chrome/utility/importer/profile_import_impl.h
index 07a4ffd..9e29cd2 100644
--- a/chrome/utility/importer/profile_import_impl.h
+++ b/chrome/utility/importer/profile_import_impl.h
@@ -10,7 +10,6 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/common/importer/profile_import.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
diff --git a/chrome/utility/importer/safari_importer.h b/chrome/utility/importer/safari_importer.h
index b8310c0..c7b6027 100644
--- a/chrome/utility/importer/safari_importer.h
+++ b/chrome/utility/importer/safari_importer.h
@@ -11,7 +11,6 @@
 #include <set>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
 #include "chrome/common/importer/importer_url_row.h"
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index bf77c22..ca6cfac 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -110,7 +110,6 @@
   ]
   if (is_chromeos_ash) {
     deps += [
-      "//chromeos/attestation:test_support",
       "//chromeos/dbus:test_support",
       "//chromeos/disks:test_support",
       "//chromeos/login/auth:test_support",
@@ -154,7 +153,6 @@
   if (is_chromeos_ash) {
     deps += [
       ":test_support",
-      "//chromeos/attestation:unit_tests",
       "//chromeos/crosapi/cpp:unit_tests",
       "//chromeos/crosapi/mojom:unit_tests",
       "//chromeos/cryptohome:unit_tests",
diff --git a/chromeos/components/quick_answers/BUILD.gn b/chromeos/components/quick_answers/BUILD.gn
index fbf9ed3..57a9176 100644
--- a/chromeos/components/quick_answers/BUILD.gn
+++ b/chromeos/components/quick_answers/BUILD.gn
@@ -41,9 +41,8 @@
   ]
   deps = [
     "//ash/constants",
-    "//ash/public/cpp",
-    "//ash/public/mojom",
     "//base",
+    "//chromeos/components/quick_answers/public/cpp:cpp",
     "//chromeos/components/quick_answers/public/cpp:prefs",
     "//chromeos/services/assistant/public/shared",
     "//chromeos/services/machine_learning/public/cpp",
@@ -53,6 +52,7 @@
     "//net:net",
     "//services/data_decoder/public/cpp",
     "//services/network/public/cpp:cpp",
+    "//ui/base",
     "//ui/gfx",
   ]
 }
@@ -68,6 +68,8 @@
     "search_result_parsers/result_parser_unittest.cc",
     "search_result_parsers/search_response_parser_unittest.cc",
     "search_result_parsers/unit_conversion_result_parser_unittest.cc",
+    "test/quick_answers_test_base.cc",
+    "test/quick_answers_test_base.h",
     "test/test_helpers.cc",
     "test/test_helpers.h",
     "translation_response_parser_unittest.cc",
@@ -79,13 +81,12 @@
 
   deps = [
     ":quick_answers",
-    "//ash/constants",
     "//ash/public/cpp",
-    "//ash/public/cpp/quick_answers/test_support",
-    "//ash/public/mojom",
     "//base",
     "//base/test:test_support",
+    "//chromeos/components/quick_answers/public/cpp:cpp",
     "//chromeos/components/quick_answers/public/cpp:prefs",
+    "//chromeos/services/assistant:test_support",
     "//chromeos/services/assistant/public/shared",
     "//chromeos/services/machine_learning/public/cpp:stub",
     "//chromeos/services/machine_learning/public/mojom",
diff --git a/chromeos/components/quick_answers/DEPS b/chromeos/components/quick_answers/DEPS
index 13ce065..1eae224 100644
--- a/chromeos/components/quick_answers/DEPS
+++ b/chromeos/components/quick_answers/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+ash/public",
+  "+components/language/core/browser",
   "+services/data_decoder/public",
   "+ui/base/l10n",
   "+ui/base/resource/resource_bundle.h",
diff --git a/chromeos/components/quick_answers/public/cpp/BUILD.gn b/chromeos/components/quick_answers/public/cpp/BUILD.gn
index ab6b2ac..af5b530 100644
--- a/chromeos/components/quick_answers/public/cpp/BUILD.gn
+++ b/chromeos/components/quick_answers/public/cpp/BUILD.gn
@@ -2,6 +2,27 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+source_set("cpp") {
+  sources = [
+    "controller/quick_answers_browser_client.cc",
+    "controller/quick_answers_browser_client.h",
+    "controller/quick_answers_controller.cc",
+    "controller/quick_answers_controller.h",
+    "quick_answers_state.cc",
+    "quick_answers_state.h",
+  ]
+
+  deps = [
+    "//base",
+    "//chromeos/components/quick_answers/public/cpp:prefs",
+    "//components/language/core/browser:browser",
+    "//components/pref_registry",
+    "//components/prefs",
+    "//ui/base",
+    "//ui/gfx",
+  ]
+}
+
 source_set("prefs") {
   sources = [
     "quick_answers_prefs.cc",
diff --git a/ash/public/cpp/quick_answers/controller/quick_answers_browser_client.cc b/chromeos/components/quick_answers/public/cpp/controller/quick_answers_browser_client.cc
similarity index 85%
rename from ash/public/cpp/quick_answers/controller/quick_answers_browser_client.cc
rename to chromeos/components/quick_answers/public/cpp/controller/quick_answers_browser_client.cc
index 044a301..6da5680 100644
--- a/ash/public/cpp/quick_answers/controller/quick_answers_browser_client.cc
+++ b/chromeos/components/quick_answers/public/cpp/controller/quick_answers_browser_client.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/public/cpp/quick_answers/controller/quick_answers_browser_client.h"
+#include "chromeos/components/quick_answers/public/cpp/controller/quick_answers_browser_client.h"
 
 #include "base/check_op.h"
 
diff --git a/ash/public/cpp/quick_answers/controller/quick_answers_browser_client.h b/chromeos/components/quick_answers/public/cpp/controller/quick_answers_browser_client.h
similarity index 74%
rename from ash/public/cpp/quick_answers/controller/quick_answers_browser_client.h
rename to chromeos/components/quick_answers/public/cpp/controller/quick_answers_browser_client.h
index b0eb40e..7a6ea7a1 100644
--- a/ash/public/cpp/quick_answers/controller/quick_answers_browser_client.h
+++ b/chromeos/components/quick_answers/public/cpp/controller/quick_answers_browser_client.h
@@ -2,18 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_PUBLIC_CPP_QUICK_ANSWERS_CONTROLLER_QUICK_ANSWERS_BROWSER_CLIENT_H_
-#define ASH_PUBLIC_CPP_QUICK_ANSWERS_CONTROLLER_QUICK_ANSWERS_BROWSER_CLIENT_H_
+#ifndef CHROMEOS_COMPONENTS_QUICK_ANSWERS_PUBLIC_CPP_CONTROLLER_QUICK_ANSWERS_BROWSER_CLIENT_H_
+#define CHROMEOS_COMPONENTS_QUICK_ANSWERS_PUBLIC_CPP_CONTROLLER_QUICK_ANSWERS_BROWSER_CLIENT_H_
 
 #include <string>
 
-#include "ash/public/cpp/ash_public_export.h"
 #include "base/callback_forward.h"
 
 namespace ash {
 
 // A client class which provides browser access to Quick Answers.
-class ASH_PUBLIC_EXPORT QuickAnswersBrowserClient {
+class QuickAnswersBrowserClient {
  public:
   using GetAccessTokenCallback =
       base::OnceCallback<void(const std::string& access_token)>;
@@ -34,4 +33,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_PUBLIC_CPP_QUICK_ANSWERS_CONTROLLER_QUICK_ANSWERS_BROWSER_CLIENT_H_
+#endif  // CHROMEOS_COMPONENTS_QUICK_ANSWERS_PUBLIC_CPP_CONTROLLER_QUICK_ANSWERS_BROWSER_CLIENT_H_
diff --git a/ash/public/cpp/quick_answers/controller/quick_answers_controller.cc b/chromeos/components/quick_answers/public/cpp/controller/quick_answers_controller.cc
similarity index 85%
rename from ash/public/cpp/quick_answers/controller/quick_answers_controller.cc
rename to chromeos/components/quick_answers/public/cpp/controller/quick_answers_controller.cc
index 856c269..54c7e325 100644
--- a/ash/public/cpp/quick_answers/controller/quick_answers_controller.cc
+++ b/chromeos/components/quick_answers/public/cpp/controller/quick_answers_controller.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/public/cpp/quick_answers/controller/quick_answers_controller.h"
+#include "chromeos/components/quick_answers/public/cpp/controller/quick_answers_controller.h"
 
 #include "base/check_op.h"
 
diff --git a/ash/public/cpp/quick_answers/controller/quick_answers_controller.h b/chromeos/components/quick_answers/public/cpp/controller/quick_answers_controller.h
similarity index 88%
rename from ash/public/cpp/quick_answers/controller/quick_answers_controller.h
rename to chromeos/components/quick_answers/public/cpp/controller/quick_answers_controller.h
index 4c01209..8f9c366 100644
--- a/ash/public/cpp/quick_answers/controller/quick_answers_controller.h
+++ b/chromeos/components/quick_answers/public/cpp/controller/quick_answers_controller.h
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_PUBLIC_CPP_QUICK_ANSWERS_CONTROLLER_QUICK_ANSWERS_CONTROLLER_H_
-#define ASH_PUBLIC_CPP_QUICK_ANSWERS_CONTROLLER_QUICK_ANSWERS_CONTROLLER_H_
+#ifndef CHROMEOS_COMPONENTS_QUICK_ANSWERS_PUBLIC_CPP_CONTROLLER_QUICK_ANSWERS_CONTROLLER_H_
+#define CHROMEOS_COMPONENTS_QUICK_ANSWERS_PUBLIC_CPP_CONTROLLER_QUICK_ANSWERS_CONTROLLER_H_
 
 #include <string>
 
-#include "ash/public/cpp/ash_public_export.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace ash {
@@ -30,7 +29,7 @@
 };
 
 // A controller to manage quick answers UI.
-class ASH_PUBLIC_EXPORT QuickAnswersController {
+class QuickAnswersController {
  public:
   QuickAnswersController();
   virtual ~QuickAnswersController();
@@ -74,4 +73,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_PUBLIC_CPP_QUICK_ANSWERS_CONTROLLER_QUICK_ANSWERS_CONTROLLER_H_
+#endif  // CHROMEOS_COMPONENTS_QUICK_ANSWERS_PUBLIC_CPP_CONTROLLER_QUICK_ANSWERS_CONTROLLER_H_
diff --git a/ash/public/cpp/quick_answers/quick_answers_state.cc b/chromeos/components/quick_answers/public/cpp/quick_answers_state.cc
similarity index 85%
rename from ash/public/cpp/quick_answers/quick_answers_state.cc
rename to chromeos/components/quick_answers/public/cpp/quick_answers_state.cc
index a9ede13..3d098d64 100644
--- a/ash/public/cpp/quick_answers/quick_answers_state.cc
+++ b/chromeos/components/quick_answers/public/cpp/quick_answers_state.cc
@@ -2,15 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/public/cpp/quick_answers/quick_answers_state.h"
+#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h"
 
-#include "ash/constants/ash_features.h"
-#include "ash/public/cpp/assistant/assistant_state.h"
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
-#include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
@@ -21,8 +19,6 @@
 
 namespace {
 
-using chromeos::assistant::prefs::kAssistantContextEnabled;
-using chromeos::assistant::prefs::kAssistantEnabled;
 using quick_answers::prefs::ConsentStatus;
 using quick_answers::prefs::kQuickAnswersConsentStatus;
 using quick_answers::prefs::kQuickAnswersDefinitionEnabled;
@@ -49,32 +45,6 @@
          base::Contains(kAllowedLocales, runtime_locale);
 }
 
-void MigrateQuickAnswersConsentStatus(PrefService* prefs) {
-  // If the consented status has not been set, migrate the current context
-  // enabled value.
-  if (prefs->FindPreference(kQuickAnswersConsentStatus)->IsDefaultValue()) {
-    if (!prefs->FindPreference(kAssistantContextEnabled)->IsDefaultValue()) {
-      // Set the consent status based on current feature eligibility.
-      bool consented =
-          ash::AssistantState::Get()->allowed_state() ==
-              chromeos::assistant::AssistantAllowedState::ALLOWED &&
-          prefs->GetBoolean(kAssistantEnabled) &&
-          prefs->GetBoolean(kAssistantContextEnabled);
-      prefs->SetInteger(
-          kQuickAnswersConsentStatus,
-          consented ? ConsentStatus::kAccepted : ConsentStatus::kRejected);
-      // Enable Quick Answers settings for existing users.
-      if (consented)
-        prefs->SetBoolean(kQuickAnswersEnabled, true);
-    } else {
-      // Set the consent status to unknown for new users.
-      prefs->SetInteger(kQuickAnswersConsentStatus, ConsentStatus::kUnknown);
-      // Reset the impression count for new users.
-      prefs->SetInteger(kQuickAnswersNoticeImpressionCount, 0);
-    }
-  }
-}
-
 void IncrementPrefCounter(PrefService* prefs,
                           const std::string& path,
                           int count) {
@@ -175,7 +145,6 @@
 
   prefs_initialized_ = true;
 
-  MigrateQuickAnswersConsentStatus(pref_service);
   UpdateEligibility();
 }
 
diff --git a/ash/public/cpp/quick_answers/quick_answers_state.h b/chromeos/components/quick_answers/public/cpp/quick_answers_state.h
similarity index 90%
rename from ash/public/cpp/quick_answers/quick_answers_state.h
rename to chromeos/components/quick_answers/public/cpp/quick_answers_state.h
index 812f95c..dd9ad37 100644
--- a/ash/public/cpp/quick_answers/quick_answers_state.h
+++ b/chromeos/components/quick_answers/public/cpp/quick_answers_state.h
@@ -2,13 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_PUBLIC_CPP_QUICK_ANSWERS_QUICK_ANSWERS_STATE_H_
-#define ASH_PUBLIC_CPP_QUICK_ANSWERS_QUICK_ANSWERS_STATE_H_
+#ifndef CHROMEOS_COMPONENTS_QUICK_ANSWERS_PUBLIC_CPP_QUICK_ANSWERS_STATE_H_
+#define CHROMEOS_COMPONENTS_QUICK_ANSWERS_PUBLIC_CPP_QUICK_ANSWERS_STATE_H_
 
 #include <memory>
 #include <string>
 
-#include "ash/public/cpp/ash_public_export.h"
 #include "base/observer_list.h"
 #include "base/observer_list_types.h"
 #include "base/timer/timer.h"
@@ -35,14 +34,13 @@
 };
 
 // A checked observer which receives Quick Answers state change.
-class ASH_PUBLIC_EXPORT QuickAnswersStateObserver
-    : public base::CheckedObserver {
+class QuickAnswersStateObserver : public base::CheckedObserver {
  public:
   virtual void OnSettingsEnabled(bool enabled) {}
 };
 
 // A class that holds Quick Answers related prefs and states.
-class ASH_PUBLIC_EXPORT QuickAnswersState {
+class QuickAnswersState {
  public:
   static QuickAnswersState* Get();
 
@@ -129,4 +127,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_PUBLIC_CPP_QUICK_ANSWERS_QUICK_ANSWERS_STATE_H_
+#endif  // CHROMEOS_COMPONENTS_QUICK_ANSWERS_PUBLIC_CPP_QUICK_ANSWERS_STATE_H_
diff --git a/chromeos/components/quick_answers/quick_answers_client.cc b/chromeos/components/quick_answers/quick_answers_client.cc
index 90689b1..62ca7af7 100644
--- a/chromeos/components/quick_answers/quick_answers_client.cc
+++ b/chromeos/components/quick_answers/quick_answers_client.cc
@@ -7,8 +7,8 @@
 #include <utility>
 
 #include "ash/constants/ash_features.h"
-#include "ash/public/cpp/quick_answers/quick_answers_state.h"
 #include "base/containers/contains.h"
+#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h"
 #include "chromeos/components/quick_answers/quick_answers_model.h"
 #include "chromeos/components/quick_answers/utils/quick_answers_metrics.h"
 #include "chromeos/components/quick_answers/utils/quick_answers_utils.h"
diff --git a/chromeos/components/quick_answers/quick_answers_client_unittest.cc b/chromeos/components/quick_answers/quick_answers_client_unittest.cc
index a3baf02..ad9e5b6 100644
--- a/chromeos/components/quick_answers/quick_answers_client_unittest.cc
+++ b/chromeos/components/quick_answers/quick_answers_client_unittest.cc
@@ -8,12 +8,10 @@
 #include <string>
 #include <utility>
 
-#include "ash/constants/ash_features.h"
-#include "ash/public/cpp/quick_answers/test_support/quick_answers_test_base.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "chromeos/components/quick_answers/quick_answers_model.h"
+#include "chromeos/components/quick_answers/test/quick_answers_test_base.h"
 #include "chromeos/components/quick_answers/test/test_helpers.h"
 #include "chromeos/components/quick_answers/utils/quick_answers_utils.h"
 #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
diff --git a/ash/public/cpp/quick_answers/test_support/quick_answers_test_base.cc b/chromeos/components/quick_answers/test/quick_answers_test_base.cc
similarity index 84%
rename from ash/public/cpp/quick_answers/test_support/quick_answers_test_base.cc
rename to chromeos/components/quick_answers/test/quick_answers_test_base.cc
index 706142be..7bca234 100644
--- a/ash/public/cpp/quick_answers/test_support/quick_answers_test_base.cc
+++ b/chromeos/components/quick_answers/test/quick_answers_test_base.cc
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/public/cpp/quick_answers/test_support/quick_answers_test_base.h"
+#include "chromeos/components/quick_answers/test/quick_answers_test_base.h"
 
 #include "ash/public/cpp/assistant/assistant_state.h"
-#include "ash/public/cpp/quick_answers/quick_answers_state.h"
 
 namespace ash {
 
diff --git a/ash/public/cpp/quick_answers/test_support/quick_answers_test_base.h b/chromeos/components/quick_answers/test/quick_answers_test_base.h
similarity index 75%
rename from ash/public/cpp/quick_answers/test_support/quick_answers_test_base.h
rename to chromeos/components/quick_answers/test/quick_answers_test_base.h
index 5163993..2e49cf4 100644
--- a/ash/public/cpp/quick_answers/test_support/quick_answers_test_base.h
+++ b/chromeos/components/quick_answers/test/quick_answers_test_base.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_PUBLIC_CPP_QUICK_ANSWERS_TEST_SUPPORT_QUICK_ANSWERS_TEST_BASE_H_
-#define ASH_PUBLIC_CPP_QUICK_ANSWERS_TEST_SUPPORT_QUICK_ANSWERS_TEST_BASE_H_
+#ifndef CHROMEOS_COMPONENTS_QUICK_ANSWERS_TEST_QUICK_ANSWERS_TEST_BASE_H_
+#define CHROMEOS_COMPONENTS_QUICK_ANSWERS_TEST_QUICK_ANSWERS_TEST_BASE_H_
 
 #include <memory>
 
-#include "ash/public/cpp/quick_answers/quick_answers_state.h"
+#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h"
 #include "chromeos/services/assistant/test_support/fully_initialized_assistant_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -35,4 +35,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_PUBLIC_CPP_QUICK_ANSWERS_TEST_SUPPORT_QUICK_ANSWERS_TEST_BASE_H_
+#endif  // CHROMEOS_COMPONENTS_QUICK_ANSWERS_TEST_QUICK_ANSWERS_TEST_BASE_H_
diff --git a/chromeos/components/quick_answers/translation_result_loader.cc b/chromeos/components/quick_answers/translation_result_loader.cc
index 119e072e..989cc3b 100644
--- a/chromeos/components/quick_answers/translation_result_loader.cc
+++ b/chromeos/components/quick_answers/translation_result_loader.cc
@@ -6,8 +6,8 @@
 
 #include <utility>
 
-#include "ash/public/cpp/quick_answers/controller/quick_answers_browser_client.h"
 #include "base/json/json_writer.h"
+#include "chromeos/components/quick_answers/public/cpp/controller/quick_answers_browser_client.h"
 #include "chromeos/components/quick_answers/quick_answers_model.h"
 #include "chromeos/components/quick_answers/utils/quick_answers_utils.h"
 #include "chromeos/services/assistant/public/shared/constants.h"
diff --git a/chromeos/components/quick_answers/translation_result_loader_unittest.cc b/chromeos/components/quick_answers/translation_result_loader_unittest.cc
index 5685ce9b..390b036 100644
--- a/chromeos/components/quick_answers/translation_result_loader_unittest.cc
+++ b/chromeos/components/quick_answers/translation_result_loader_unittest.cc
@@ -7,9 +7,9 @@
 #include <memory>
 #include <string>
 
-#include "ash/public/cpp/quick_answers/controller/quick_answers_browser_client.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/test/task_environment.h"
+#include "chromeos/components/quick_answers/public/cpp/controller/quick_answers_browser_client.h"
 #include "chromeos/components/quick_answers/quick_answers_model.h"
 #include "chromeos/components/quick_answers/test/test_helpers.h"
 #include "chromeos/components/quick_answers/utils/quick_answers_utils.h"
diff --git a/chromeos/components/quick_answers/understanding/intent_generator.cc b/chromeos/components/quick_answers/understanding/intent_generator.cc
index ed962fb..08403af 100644
--- a/chromeos/components/quick_answers/understanding/intent_generator.cc
+++ b/chromeos/components/quick_answers/understanding/intent_generator.cc
@@ -7,11 +7,11 @@
 #include <map>
 
 #include "ash/constants/ash_features.h"
-#include "ash/public/cpp/quick_answers/quick_answers_state.h"
 #include "base/i18n/case_conversion.h"
 #include "base/no_destructor.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h"
 #include "chromeos/components/quick_answers/quick_answers_model.h"
 #include "chromeos/components/quick_answers/utils/quick_answers_utils.h"
 #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
diff --git a/chromeos/components/quick_answers/understanding/intent_generator_unittest.cc b/chromeos/components/quick_answers/understanding/intent_generator_unittest.cc
index baf5f249..f20863f 100644
--- a/chromeos/components/quick_answers/understanding/intent_generator_unittest.cc
+++ b/chromeos/components/quick_answers/understanding/intent_generator_unittest.cc
@@ -7,13 +7,11 @@
 #include <memory>
 #include <string>
 
-#include "ash/constants/ash_features.h"
-#include "ash/public/cpp/quick_answers/quick_answers_state.h"
-#include "ash/public/cpp/quick_answers/test_support/quick_answers_test_base.h"
 #include "base/bind.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
+#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h"
 #include "chromeos/components/quick_answers/quick_answers_model.h"
+#include "chromeos/components/quick_answers/test/quick_answers_test_base.h"
 #include "chromeos/components/quick_answers/utils/quick_answers_utils.h"
 #include "chromeos/services/machine_learning/public/cpp/fake_service_connection.h"
 #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
@@ -82,7 +80,6 @@
   base::test::TaskEnvironment task_environment_;
   std::unique_ptr<IntentGenerator> intent_generator_;
   IntentInfo intent_info_;
-  base::test::ScopedFeatureList scoped_feature_list_;
   FakeServiceConnectionImpl fake_service_connection_;
 };
 
diff --git a/chromeos/dbus/BUILD.gn b/chromeos/dbus/BUILD.gn
index ee0393c..208375a6 100644
--- a/chromeos/dbus/BUILD.gn
+++ b/chromeos/dbus/BUILD.gn
@@ -5,7 +5,6 @@
 import("//chromeos/components/chromebox_for_meetings/buildflags/buildflags.gni")
 import("//testing/test.gni")
 import("//third_party/protobuf/proto_library.gni")
-import("use_real_dbus_clients.gni")
 
 assert(is_chromeos, "Non-Chrome-OS builds must not depend on //chromeos")
 
@@ -75,17 +74,12 @@
   ]
 }
 
-config("use_real_dbus_clients_config") {
-  if (use_real_dbus_clients) {
-    defines = [ "USE_REAL_DBUS_CLIENTS" ]
-  }
-}
-
 component("common") {
   output_name = "chromeos_dbus_common"
   defines = [ "IS_CHROMEOS_DBUS_IMPL" ]
 
-  all_dependent_configs = [ ":use_real_dbus_clients_config" ]
+  all_dependent_configs =
+      [ "//chromeos/dbus/config:use_real_dbus_clients_config" ]
   public_deps = [ "//chromeos/dbus/constants" ]
 
   deps = [
diff --git a/chromeos/dbus/config/BUILD.gn b/chromeos/dbus/config/BUILD.gn
new file mode 100644
index 0000000..4875c4d
--- /dev/null
+++ b/chromeos/dbus/config/BUILD.gn
@@ -0,0 +1,15 @@
+# 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")
+import("use_real_dbus_clients.gni")
+
+assert(is_chromeos_ash || is_chromeos_lacros,
+       "Non-Chrome-OS or Lacros builds must not depend on //chromeos")
+
+config("use_real_dbus_clients_config") {
+  if (use_real_dbus_clients) {
+    defines = [ "USE_REAL_DBUS_CLIENTS" ]
+  }
+}
diff --git a/chromeos/dbus/use_real_dbus_clients.gni b/chromeos/dbus/config/use_real_dbus_clients.gni
similarity index 100%
rename from chromeos/dbus/use_real_dbus_clients.gni
rename to chromeos/dbus/config/use_real_dbus_clients.gni
diff --git a/chromeos/dbus/constants/attestation_constants.h b/chromeos/dbus/constants/attestation_constants.h
index ea5397a..d08682ff 100644
--- a/chromeos/dbus/constants/attestation_constants.h
+++ b/chromeos/dbus/constants/attestation_constants.h
@@ -109,6 +109,7 @@
 using ::chromeos::attestation::AttestationStatus;
 using ::chromeos::attestation::DEFAULT_PCA;
 using ::chromeos::attestation::kContentProtectionKeyPrefix;
+using ::chromeos::attestation::kEnterpriseEnrollmentKey;
 using ::chromeos::attestation::kEnterpriseMachineKey;
 using ::chromeos::attestation::kEnterpriseUserKey;
 using ::chromeos::attestation::KEY_DEVICE;
diff --git a/chromeos/dbus/fwupd/BUILD.gn b/chromeos/dbus/fwupd/BUILD.gn
index fd30038..de61295 100644
--- a/chromeos/dbus/fwupd/BUILD.gn
+++ b/chromeos/dbus/fwupd/BUILD.gn
@@ -5,8 +5,8 @@
 assert(is_chromeos, "Non-ChromeOS builds cannot depend on //chromeos")
 
 component("fwupd") {
-  output_name = "chromeos_fwupd"
-  defines = [ "IS_CHROMEOS_DBUS_FUWPD_IMPL" ]
+  output_name = "chromeos_dbus_fwupd"
+  defines = [ "IS_CHROMEOS_DBUS_FWUPD_IMPL" ]
 
   deps = [
     "//ash/constants",
diff --git a/chromeos/dbus/fwupd/fake_fwupd_client.h b/chromeos/dbus/fwupd/fake_fwupd_client.h
index 62ef86a7..ebb4cc2 100644
--- a/chromeos/dbus/fwupd/fake_fwupd_client.h
+++ b/chromeos/dbus/fwupd/fake_fwupd_client.h
@@ -10,7 +10,7 @@
 
 namespace chromeos {
 
-class COMPONENT_EXPORT(CHROMEOS_DBUS_FUWPD) FakeFwupdClient
+class COMPONENT_EXPORT(CHROMEOS_DBUS_FWUPD) FakeFwupdClient
     : public FwupdClient {
  public:
   FakeFwupdClient();
diff --git a/chromeos/dbus/fwupd/fwupd_client.h b/chromeos/dbus/fwupd/fwupd_client.h
index ee9e08a43..e043128b 100644
--- a/chromeos/dbus/fwupd/fwupd_client.h
+++ b/chromeos/dbus/fwupd/fwupd_client.h
@@ -16,7 +16,7 @@
 
 namespace chromeos {
 // FwupdClient is used for handling signals from the fwupd daemon.
-class COMPONENT_EXPORT(CHROMEOS_DBUS_FUWPD) FwupdClient : public DBusClient {
+class COMPONENT_EXPORT(CHROMEOS_DBUS_FWUPD) FwupdClient : public DBusClient {
  public:
   class Observer : public base::CheckedObserver {
    public:
@@ -41,6 +41,9 @@
   // Returns the global instance if initialized. May return null.
   static FwupdClient* Get();
 
+  // Used to call the protected initialization in unit tests.
+  void InitForTesting(dbus::Bus* bus) { Init(bus); }
+
   // Query fwupd for updates that are available for a particular device.
   virtual void RequestUpdates(const std::string& device_id) = 0;
 
diff --git a/chromeos/dbus/fwupd/fwupd_client_unittest.cc b/chromeos/dbus/fwupd/fwupd_client_unittest.cc
index 46f2ce0e..362d898 100644
--- a/chromeos/dbus/fwupd/fwupd_client_unittest.cc
+++ b/chromeos/dbus/fwupd/fwupd_client_unittest.cc
@@ -79,7 +79,7 @@
         .WillRepeatedly(Invoke(this, &FwupdClientTest::ConnectToSignal));
 
     fwupd_client_ = FwupdClient::Create();
-    fwupd_client_->Init(bus_.get());
+    fwupd_client_->InitForTesting(bus_.get());
     fwupd_client_->client_is_in_testing_mode_ = true;
   }
 
diff --git a/chromeos/dbus/fwupd/fwupd_device.cc b/chromeos/dbus/fwupd/fwupd_device.cc
index 2f855dfa..af8ecc1 100644
--- a/chromeos/dbus/fwupd/fwupd_device.cc
+++ b/chromeos/dbus/fwupd/fwupd_device.cc
@@ -11,8 +11,8 @@
 FwupdDevice::FwupdDevice(const std::string& id, const std::string& device_name)
     : id(id), device_name(device_name) {}
 
-FwupdDevice::FwupdDevice(FwupdDevice&& other) = default;
-FwupdDevice& FwupdDevice::operator=(FwupdDevice&& other) = default;
+FwupdDevice::FwupdDevice(const FwupdDevice& other) = default;
+FwupdDevice& FwupdDevice::operator=(const FwupdDevice& other) = default;
 FwupdDevice::~FwupdDevice() = default;
 
 }  // namespace chromeos
diff --git a/chromeos/dbus/fwupd/fwupd_device.h b/chromeos/dbus/fwupd/fwupd_device.h
index c4ed8318..c255250 100644
--- a/chromeos/dbus/fwupd/fwupd_device.h
+++ b/chromeos/dbus/fwupd/fwupd_device.h
@@ -15,8 +15,8 @@
 struct COMPONENT_EXPORT(CHROMEOS_DBUS_FWUPD) FwupdDevice {
   FwupdDevice();
   FwupdDevice(const std::string& id, const std::string& device_name);
-  FwupdDevice(FwupdDevice&& other);
-  FwupdDevice& operator=(FwupdDevice&& other);
+  FwupdDevice(const FwupdDevice& other);
+  FwupdDevice& operator=(const FwupdDevice& other);
   ~FwupdDevice();
 
   std::string id;
diff --git a/chromeos/login/auth/auth_attempt_state.cc b/chromeos/login/auth/auth_attempt_state.cc
index 51a77f4..ecbd54b4 100644
--- a/chromeos/login/auth/auth_attempt_state.cc
+++ b/chromeos/login/auth/auth_attempt_state.cc
@@ -4,12 +4,14 @@
 
 #include "chromeos/login/auth/auth_attempt_state.h"
 
-
+#include <utility>
 
 namespace chromeos {
 
-AuthAttemptState::AuthAttemptState(const UserContext& user_context, bool unlock)
-    : user_context(user_context), unlock(unlock) {}
+AuthAttemptState::AuthAttemptState(std::unique_ptr<UserContext> user_context)
+    : user_context(std::move(user_context)) {
+  DCHECK(this->user_context);
+}
 
 AuthAttemptState::~AuthAttemptState() = default;
 
@@ -24,7 +26,7 @@
 }
 
 void AuthAttemptState::RecordUsernameHash(const std::string& username_hash) {
-  user_context.SetUserIDHash(username_hash);
+  user_context->SetUserIDHash(username_hash);
   username_hash_obtained_ = true;
   username_hash_valid_ = true;
 }
diff --git a/chromeos/login/auth/auth_attempt_state.h b/chromeos/login/auth/auth_attempt_state.h
index 92eb90e..aa5f3b8 100644
--- a/chromeos/login/auth/auth_attempt_state.h
+++ b/chromeos/login/auth/auth_attempt_state.h
@@ -5,6 +5,7 @@
 #ifndef CHROMEOS_LOGIN_AUTH_AUTH_ATTEMPT_STATE_H_
 #define CHROMEOS_LOGIN_AUTH_AUTH_ATTEMPT_STATE_H_
 
+#include <memory>
 #include <string>
 
 #include "base/component_export.h"
@@ -22,7 +23,7 @@
     : public base::SupportsWeakPtr<AuthAttemptState> {
  public:
   // Used to initialize for a login attempt.
-  AuthAttemptState(const UserContext& user_context, bool unlock);
+  explicit AuthAttemptState(std::unique_ptr<UserContext> user_context);
 
   AuthAttemptState(const AuthAttemptState&) = delete;
   AuthAttemptState& operator=(const AuthAttemptState&) = delete;
@@ -64,13 +65,7 @@
 
   // Saved so we can retry client login, and also so we know for whom login
   // has succeeded, in the event of successful completion.
-  UserContext user_context;
-
-  // These fields are saved so we can retry client login.
-  const std::string login_token;
-  const std::string login_captcha;
-
-  const bool unlock;  // True if authenticating to unlock the computer.
+  std::unique_ptr<UserContext> user_context;
 
  protected:
   // Status of our online login attempt.
diff --git a/chromeos/login/auth/auth_session_authenticator.cc b/chromeos/login/auth/auth_session_authenticator.cc
index 15a0fa1..180ce99 100644
--- a/chromeos/login/auth/auth_session_authenticator.cc
+++ b/chromeos/login/auth/auth_session_authenticator.cc
@@ -395,9 +395,86 @@
       /* existing_user_flow */ std::move(guest_exists), std::move(context));
 }
 
+// Public sessions aka Managed Guest Sessions are always ephemeral.
+// Most of the MGS have no credentials, but it optionally can
+// have a password set by extension (so that it is possible to lock session).
 void AuthSessionAuthenticator::LoginAsPublicSession(
     const UserContext& user_context) {
-  NOTIMPLEMENTED();
+  DCHECK_EQ(user_context.GetUserType(), user_manager::USER_TYPE_PUBLIC_ACCOUNT);
+
+  PrepareForNewAttempt("LoginAsPublicSession", "Managed guest session");
+
+  std::unique_ptr<UserContext> context =
+      std::make_unique<UserContext>(user_context);
+
+  if (safe_mode_delegate_->IsSafeMode()) {
+    LOGIN_LOG(EVENT) << "Managed guests can not sign-in in safe mode";
+    NotifyFailure(AuthFailure::OWNER_REQUIRED, std::move(context));
+    return;
+  }
+
+  // (1) Initialize AuthSession & transform keys
+  //   (1.1) MGS are always ephemeral
+  //   (1.2) Key can be empty or be a password
+  //   (2) MGS are ephemeral and can not exist
+  //   For new users:
+  //     (3) Add user key (even if it is empty, this is current limitation)
+  //     (4) Authenticate session with same key
+  //     (5) Mount home directory
+  //        (5.1) with create request (ephemeral is implied by session flag)
+  //     (#) Notify success
+  // (*) Errors are notified as COULD_NOT_MOUNT_TMPFS
+
+  // Callbacks are created in reverse order:
+
+  // (*)
+  auto error_handler_repeating = base::BindRepeating(
+      &AuthSessionAuthenticator::ProcessCryptohomeError,
+      weak_factory_.GetWeakPtr(),
+      /* default_error */ AuthFailure::COULD_NOT_MOUNT_TMPFS);
+  // (#)
+  ContextCallback success = base::BindOnce(
+      &AuthSessionAuthenticator::NotifyAuthSuccess, weak_factory_.GetWeakPtr());
+  // (5.1)
+  ConfigureMountCallback mount_create_cfg =
+      base::BindOnce(&ConfigureCreateMount);
+  // (5)
+  NewUserAuthSessionCallback mgs_mount = base::BindOnce(
+      &AuthSessionAuthenticator::MountGeneric, weak_factory_.GetWeakPtr(),
+      /* error_handler */ base::BindOnce(error_handler_repeating),
+      /* configurator */ std::move(mount_create_cfg),
+      /* continuation */ std::move(success));
+  // (4)
+  ContextCallback authenticate_same_key = base::BindOnce(
+      &AuthSessionAuthenticator::AuthenticateSessionGeneric,
+      weak_factory_.GetWeakPtr(),
+      /* error_handler */ base::BindOnce(error_handler_repeating),
+      /* key_transformer */ base::BindOnce(&TransformToLabeledKey),
+      /* continuation */ std::move(mgs_mount));
+  // (3)
+  NewUserAuthSessionCallback new_user_flow = base::BindOnce(
+      &AuthSessionAuthenticator::AddInitialCredentialsGeneric,
+      weak_factory_.GetWeakPtr(),
+      /* error_handler */ base::BindOnce(error_handler_repeating),
+      /* key_transformer */ base::BindOnce(&TransformToLabeledKey),
+      /* continuation */ std::move(authenticate_same_key));
+  // (2)
+  ExistingUserAuthSessionCallback mgs_exists = base::BindOnce(
+      &AuthSessionAuthenticator::NotifyFailure, weak_factory_.GetWeakPtr(),
+      AuthFailure::COULD_NOT_MOUNT_TMPFS);
+  // (1.2)
+  auto password_hasher = base::BindOnce(&HashPassword);
+  // (1.1)
+  auto ephemeral_session_configurator =
+      base::BindOnce(&ConfigureEphemeralSession);
+  // (1)
+  CreateAuthSessionGeneric(
+      "ManagedGuest",
+      /* error_handler */ base::BindOnce(error_handler_repeating),
+      /* configurator */ std::move(ephemeral_session_configurator),
+      /* key_hasher */ std::move(password_hasher),
+      /* new_user_flow */ std::move(new_user_flow),
+      /* existing_user_flow */ std::move(mgs_exists), std::move(context));
 }
 
 void AuthSessionAuthenticator::LoginAsKioskAccount(
@@ -780,7 +857,6 @@
   // Crash if could not unmount home directory, and let session_manager
   // handle it.
   LOG(FATAL) << "Failed to unmount non-owner home directory " << error;
-  NotifyFailure(AuthFailure::OWNER_REQUIRED, std::move(context));
 }
 
 void AuthSessionAuthenticator::MountErrorHandling(
diff --git a/chromeos/login/auth/cryptohome_authenticator.cc b/chromeos/login/auth/cryptohome_authenticator.cc
index 9746a11..4a0ec20 100644
--- a/chromeos/login/auth/cryptohome_authenticator.cc
+++ b/chromeos/login/auth/cryptohome_authenticator.cc
@@ -198,11 +198,11 @@
 void OnMount(const base::WeakPtr<AuthAttemptState>& attempt,
              scoped_refptr<CryptohomeAuthenticator> resolver,
              absl::optional<user_data_auth::MountReply> reply) {
-  const bool public_mount = attempt->user_context.GetUserType() ==
+  const bool public_mount = attempt->user_context->GetUserType() ==
                                 user_manager::USER_TYPE_KIOSK_APP ||
-                            attempt->user_context.GetUserType() ==
+                            attempt->user_context->GetUserType() ==
                                 user_manager::USER_TYPE_ARC_KIOSK_APP ||
-                            attempt->user_context.GetUserType() ==
+                            attempt->user_context->GetUserType() ==
                                 user_manager::USER_TYPE_WEB_KIOSK_APP;
 
   chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
@@ -226,7 +226,7 @@
              scoped_refptr<CryptohomeAuthenticator> resolver,
              bool ephemeral,
              bool create_if_nonexistent) {
-  const Key* key = attempt->user_context.GetKey();
+  const Key* key = attempt->user_context->GetKey();
   // If the |key| is a plain text password, crash rather than attempting to
   // mount the cryptohome with a plain text password.
   CHECK_NE(Key::KEY_TYPE_PASSWORD_PLAIN, key->GetKeyType());
@@ -238,7 +238,7 @@
   const cryptohome::AuthorizationRequest auth =
       CreateAuthorizationRequestFromKeyDef(
           cryptohome_parameter_utils::CreateAuthorizationKeyDefFromUserContext(
-              attempt->user_context));
+              *attempt->user_context));
 
   user_data_auth::MountRequest mount;
   if (ephemeral)
@@ -246,13 +246,13 @@
   if (create_if_nonexistent) {
     cryptohome::KeyDefinitionToKey(
         cryptohome_parameter_utils::CreateKeyDefFromUserContext(
-            attempt->user_context),
+            *attempt->user_context),
         mount.mutable_create()->add_keys());
   }
-  if (attempt->user_context.IsForcingDircrypto())
+  if (attempt->user_context->IsForcingDircrypto())
     mount.set_force_dircrypto_if_available(true);
   *mount.mutable_account() = cryptohome::CreateAccountIdentifierFromAccountId(
-      attempt->user_context.GetAccountId());
+      attempt->user_context->GetAccountId());
   *mount.mutable_authorization() = auth;
   UserDataAuthClient::Get()->Mount(mount,
                                    base::BindOnce(&OnMount, attempt, resolver));
@@ -267,7 +267,7 @@
   cryptohome::MountError return_code = user_data_auth::ReplyToMountError(reply);
   chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
       "CryptohomeRename-End", false);
-  const AccountId& account_id = attempt->user_context.GetAccountId();
+  const AccountId& account_id = attempt->user_context->GetAccountId();
   if (return_code == cryptohome::MOUNT_ERROR_NONE) {
     cryptohome::SetGaiaIdMigrationStatusDone(account_id);
     UMACryptohomeMigrationToGaiaId(CryptohomeMigrationToGaiaId::SUCCESS);
@@ -291,7 +291,7 @@
     bool create_if_nonexistent) {
   // Set the migration flag for Active Directory accounts since they're using
   // the account id key as cryptohome id.
-  const AccountId& account_id = attempt->user_context.GetAccountId();
+  const AccountId& account_id = attempt->user_context->GetAccountId();
   if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY) {
     cryptohome::SetGaiaIdMigrationStatusDone(account_id);
   }
@@ -358,9 +358,9 @@
                      bool create_if_nonexistent,
                      const std::string& system_salt) {
   DCHECK_EQ(Key::KEY_TYPE_PASSWORD_PLAIN,
-            attempt->user_context.GetKey()->GetKeyType());
+            attempt->user_context->GetKey()->GetKeyType());
 
-  attempt->user_context.GetKey()->Transform(
+  attempt->user_context->GetKey()->Transform(
       Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, system_salt);
 
   EnsureCryptohomeMigratedToGaiaId(attempt, resolver, ephemeral,
@@ -420,7 +420,7 @@
           return;
         }
 
-        attempt->user_context.GetKey()->Transform(
+        attempt->user_context->GetKey()->Transform(
             static_cast<Key::KeyType>(*type), *salt);
         EnsureCryptohomeMigratedToGaiaId(attempt, resolver, ephemeral,
                                          create_if_nonexistent);
@@ -451,7 +451,7 @@
   chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
       "CryptohomeMount-Start", false);
 
-  if (attempt->user_context.GetKey()->GetKeyType() !=
+  if (attempt->user_context->GetKey()->GetKeyType() !=
       Key::KEY_TYPE_PASSWORD_PLAIN) {
     EnsureCryptohomeMigratedToGaiaId(attempt, resolver, ephemeral,
                                      create_if_nonexistent);
@@ -461,7 +461,7 @@
   user_data_auth::GetKeyDataRequest request;
   *request.mutable_account_id() =
       cryptohome::CreateAccountIdentifierFromAccountId(
-          attempt->user_context.GetAccountId());
+          attempt->user_context->GetAccountId());
   // Calling mutable_authorization_request() to ensure
   // has_authorization_request() would return true.
   request.mutable_authorization_request();
@@ -489,7 +489,7 @@
   user_data_auth::GetSanitizedUsernameRequest sanitized_username_request;
   sanitized_username_request.set_username(
       cryptohome::CreateAccountIdentifierFromAccountId(
-          attempt->user_context.GetAccountId())
+          attempt->user_context->GetAccountId())
           .account_id());
   CryptohomeMiscClient::Get()->GetSanitizedUsername(
       sanitized_username_request,
@@ -517,7 +517,7 @@
   // which is a wildcard allowing any key to match to allow cryptohomes created
   // in a legacy way. (See comments in DoMount.)
   *mount.mutable_account() = cryptohome::CreateAccountIdentifierFromAccountId(
-      attempt->user_context.GetAccountId());
+      attempt->user_context->GetAccountId());
   // Calling mutable_authorization() to ensure has_authorization() would return
   // true.
   mount.mutable_authorization();
@@ -536,7 +536,7 @@
 
   cryptohome::AccountIdentifier account_id =
       cryptohome::CreateAccountIdentifierFromAccountId(
-          attempt->user_context.GetAccountId());
+          attempt->user_context->GetAccountId());
 
   cryptohome::AuthorizationRequest auth_request;
   user_data_auth::MigrateKeyRequest migrate_request;
@@ -545,7 +545,7 @@
   std::unique_ptr<Key> old_key =
       TransformKeyIfNeeded(Key(old_password), system_salt);
   std::unique_ptr<Key> new_key =
-      TransformKeyIfNeeded(*attempt->user_context.GetKey(), system_salt);
+      TransformKeyIfNeeded(*attempt->user_context->GetKey(), system_salt);
   if (passing_old_hash) {
     auth_request.mutable_key()->set_secret(old_key->GetSecret());
     migrate_request.set_secret(new_key->GetSecret());
@@ -570,7 +570,7 @@
 
   cryptohome::AccountIdentifier account_id;
   account_id.set_account_id(
-      cryptohome::Identification(attempt->user_context.GetAccountId()).id());
+      cryptohome::Identification(attempt->user_context->GetAccountId()).id());
 
   user_data_auth::RemoveRequest req;
   *req.mutable_identifier() = account_id;
@@ -604,8 +604,8 @@
          user_context.GetUserType() == user_manager::USER_TYPE_CHILD ||
          user_context.GetUserType() ==
              user_manager::USER_TYPE_ACTIVE_DIRECTORY);
-  current_state_ =
-      std::make_unique<AuthAttemptState>(user_context, false /* unlock */);
+  current_state_ = std::make_unique<AuthAttemptState>(
+      std::make_unique<UserContext>(user_context));
   // Reset the verified flag.
   owner_is_verified_ = false;
 
@@ -619,15 +619,16 @@
          user_context.GetUserType() == user_manager::USER_TYPE_CHILD ||
          user_context.GetUserType() ==
              user_manager::USER_TYPE_ACTIVE_DIRECTORY);
-  current_state_ =
-      std::make_unique<AuthAttemptState>(user_context, true /* unlock */);
+  current_state_ = std::make_unique<AuthAttemptState>(
+      std::make_unique<UserContext>(user_context));
 
   // Reset the verified flag.
   owner_is_verified_ = false;
-  if (!user_manager::known_user::FindPrefs(user_context.GetAccountId(),
-                                           nullptr)) {
+  if (!user_manager::known_user::FindPrefs(
+          current_state_->user_context->GetAccountId(), nullptr)) {
     // Save logged in user into local state as early as possible.
-    user_manager::known_user::SaveKnownUser(user_context.GetAccountId());
+    user_manager::known_user::SaveKnownUser(
+        current_state_->user_context->GetAccountId());
   }
 
   StartMount(current_state_->AsWeakPtr(),
@@ -645,10 +646,9 @@
 
 void CryptohomeAuthenticator::LoginOffTheRecord() {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  current_state_ = std::make_unique<AuthAttemptState>(
-      UserContext(user_manager::USER_TYPE_GUEST,
-                  user_manager::GuestAccountId()),
-      false /* unlock */);
+  current_state_ =
+      std::make_unique<AuthAttemptState>(std::make_unique<UserContext>(
+          user_manager::USER_TYPE_GUEST, user_manager::GuestAccountId()));
   remove_user_data_on_failure_ = false;
   ephemeral_mount_attempted_ = true;
   MountGuestAndGetHash(current_state_->AsWeakPtr(),
@@ -666,12 +666,12 @@
   // empty password) or for a normal user.
   // TODO(crbug.com/826417): Introduce a separate constant for the Public
   // Session key label.
-  UserContext new_user_context = user_context;
+  auto new_user_context = std::make_unique<UserContext>(user_context);
   DCHECK(user_context.GetKey()->GetLabel().empty());
-  new_user_context.GetKey()->SetLabel(kCryptohomeGaiaKeyLabel);
+  new_user_context->GetKey()->SetLabel(kCryptohomeGaiaKeyLabel);
 
   current_state_ =
-      std::make_unique<AuthAttemptState>(new_user_context, false /* unlock */);
+      std::make_unique<AuthAttemptState>(std::move(new_user_context));
   remove_user_data_on_failure_ = false;
   ephemeral_mount_attempted_ = true;
   StartMount(current_state_->AsWeakPtr(),
@@ -682,9 +682,9 @@
 void CryptohomeAuthenticator::LoginAsKioskAccount(
     const AccountId& app_account_id) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  current_state_ = std::make_unique<AuthAttemptState>(
-      UserContext(user_manager::USER_TYPE_KIOSK_APP, app_account_id),
-      false /* unlock */);
+  current_state_ =
+      std::make_unique<AuthAttemptState>(std::make_unique<UserContext>(
+          user_manager::USER_TYPE_KIOSK_APP, app_account_id));
 
   remove_user_data_on_failure_ = true;
   MountPublic(current_state_->AsWeakPtr(),
@@ -696,9 +696,9 @@
     const AccountId& app_account_id) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
-  current_state_ = std::make_unique<AuthAttemptState>(
-      UserContext(user_manager::USER_TYPE_ARC_KIOSK_APP, app_account_id),
-      false /* unlock */);
+  current_state_ =
+      std::make_unique<AuthAttemptState>(std::make_unique<UserContext>(
+          user_manager::USER_TYPE_ARC_KIOSK_APP, app_account_id));
 
   remove_user_data_on_failure_ = true;
   MountPublic(current_state_->AsWeakPtr(),
@@ -710,9 +710,9 @@
     const AccountId& app_account_id) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
-  current_state_ = std::make_unique<AuthAttemptState>(
-      UserContext(user_manager::USER_TYPE_WEB_KIOSK_APP, app_account_id),
-      false /* unlock */);
+  current_state_ =
+      std::make_unique<AuthAttemptState>(std::make_unique<UserContext>(
+          user_manager::USER_TYPE_WEB_KIOSK_APP, app_account_id));
 
   remove_user_data_on_failure_ = true;
   MountPublic(current_state_->AsWeakPtr(),
@@ -730,7 +730,7 @@
     already_reported_success_ = true;
   }
   if (consumer_)
-    consumer_->OnAuthSuccess(current_state_->user_context);
+    consumer_->OnAuthSuccess(*current_state_->user_context);
 }
 
 void CryptohomeAuthenticator::OnOffTheRecordAuthSuccess() {
@@ -743,14 +743,14 @@
 void CryptohomeAuthenticator::OnPasswordChangeDetected() {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   if (consumer_)
-    consumer_->OnPasswordChangeDetected(current_state_->user_context);
+    consumer_->OnPasswordChangeDetected(*current_state_->user_context);
 }
 
 void CryptohomeAuthenticator::OnOldEncryptionDetected(
     bool has_incomplete_migration) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   if (consumer_) {
-    consumer_->OnOldEncryptionDetected(current_state_->user_context,
+    consumer_->OnOldEncryptionDetected(*current_state_->user_context,
                                        has_incomplete_migration);
   }
 }
@@ -781,8 +781,8 @@
 
 void CryptohomeAuthenticator::MigrateKey(const UserContext& user_context,
                                          const std::string& old_password) {
-  current_state_ =
-      std::make_unique<AuthAttemptState>(user_context, false /* unlock */);
+  current_state_ = std::make_unique<AuthAttemptState>(
+      std::make_unique<UserContext>(user_context));
   RecoverEncryptedData(old_password);
 }
 
@@ -823,7 +823,7 @@
   }
 
   safe_mode_delegate_->CheckSafeModeOwnership(
-      current_state_->user_context.GetUserIDHash(),
+      current_state_->user_context->GetUserIDHash(),
       base::BindOnce(&CryptohomeAuthenticator::OnOwnershipChecked, this));
   return false;
 }
@@ -934,7 +934,7 @@
       break;
     case KIOSK_ACCOUNT_LOGIN:
     case PUBLIC_ACCOUNT_LOGIN:
-      current_state_->user_context.SetIsUsingOAuth(false);
+      current_state_->user_context->SetIsUsingOAuth(false);
       task_runner_->PostTask(
           FROM_HERE,
           base::BindOnce(&CryptohomeAuthenticator::OnAuthSuccess, this));
@@ -1102,7 +1102,7 @@
     return RECOVER_MOUNT;
 
   const user_manager::UserType user_type =
-      current_state_->user_context.GetUserType();
+      current_state_->user_context->GetUserType();
   if (user_type == user_manager::USER_TYPE_GUEST)
     return GUEST_LOGIN;
   if (user_type == user_manager::USER_TYPE_PUBLIC_ACCOUNT)
diff --git a/chromeos/login/auth/test_attempt_state.cc b/chromeos/login/auth/test_attempt_state.cc
index 74abe58..7b33023 100644
--- a/chromeos/login/auth/test_attempt_state.cc
+++ b/chromeos/login/auth/test_attempt_state.cc
@@ -4,13 +4,15 @@
 
 #include "chromeos/login/auth/test_attempt_state.h"
 
+#include <utility>
+
 #include "components/user_manager/user_type.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace chromeos {
 
-TestAttemptState::TestAttemptState(const UserContext& credentials)
-    : AuthAttemptState(credentials, false /* unlock */) {}
+TestAttemptState::TestAttemptState(std::unique_ptr<UserContext> credentials)
+    : AuthAttemptState(std::move(credentials)) {}
 
 TestAttemptState::~TestAttemptState() = default;
 
diff --git a/chromeos/login/auth/test_attempt_state.h b/chromeos/login/auth/test_attempt_state.h
index dca8588..9393553 100644
--- a/chromeos/login/auth/test_attempt_state.h
+++ b/chromeos/login/auth/test_attempt_state.h
@@ -5,6 +5,8 @@
 #ifndef CHROMEOS_LOGIN_AUTH_TEST_ATTEMPT_STATE_H_
 #define CHROMEOS_LOGIN_AUTH_TEST_ATTEMPT_STATE_H_
 
+#include <memory>
+
 #include "base/compiler_specific.h"
 #include "base/component_export.h"
 #include "chromeos/login/auth/auth_attempt_state.h"
@@ -18,7 +20,7 @@
 class COMPONENT_EXPORT(CHROMEOS_LOGIN_AUTH) TestAttemptState
     : public AuthAttemptState {
  public:
-  explicit TestAttemptState(const UserContext& credentials);
+  explicit TestAttemptState(std::unique_ptr<UserContext> credentials);
 
   TestAttemptState(const TestAttemptState&) = delete;
   TestAttemptState& operator=(const TestAttemptState&) = delete;
diff --git a/chromeos/services/bluetooth_config/fake_bluetooth_device_status_notifier.cc b/chromeos/services/bluetooth_config/fake_bluetooth_device_status_notifier.cc
index 3dd9715..97065b0 100644
--- a/chromeos/services/bluetooth_config/fake_bluetooth_device_status_notifier.cc
+++ b/chromeos/services/bluetooth_config/fake_bluetooth_device_status_notifier.cc
@@ -14,7 +14,7 @@
     default;
 
 void FakeBluetoothDeviceStatusNotifier::SetNewlyPairedDevices(
-    std::vector<mojom::PairedBluetoothDevicePropertiesPtr>& devices) {
+    const std::vector<mojom::PairedBluetoothDevicePropertiesPtr>& devices) {
   NotifyDevicesNewlyPaired(devices);
 }
 
diff --git a/chromeos/services/bluetooth_config/fake_bluetooth_device_status_notifier.h b/chromeos/services/bluetooth_config/fake_bluetooth_device_status_notifier.h
index d17e19e..fe336c2 100644
--- a/chromeos/services/bluetooth_config/fake_bluetooth_device_status_notifier.h
+++ b/chromeos/services/bluetooth_config/fake_bluetooth_device_status_notifier.h
@@ -18,7 +18,7 @@
   ~FakeBluetoothDeviceStatusNotifier() override;
 
   void SetNewlyPairedDevices(
-      std::vector<mojom::PairedBluetoothDevicePropertiesPtr>& devices);
+      const std::vector<mojom::PairedBluetoothDevicePropertiesPtr>& devices);
 };
 
 }  // namespace bluetooth_config
diff --git a/components/BUILD.gn b/components/BUILD.gn
index d3e184e..d8e02d0 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -474,6 +474,7 @@
     deps += [
       # TODO(b/206686476): Move this target to //ash/components:unit_tests
       "//ash/components/arc:unit_tests",
+      "//components/arc:unit_tests",
       "//components/arc/mojom:unit_tests",
       "//components/arc/session:unit_tests",
       "//components/desks_storage:unit_tests",
@@ -774,6 +775,7 @@
         "autofill_assistant/browser/mock_script_executor_delegate.cc",
         "autofill_assistant/browser/mock_script_executor_delegate.h",
         "autofill_assistant/browser/web/web_controller_browsertest.cc",
+        "autofill_assistant/content/renderer/autofill_assistant_agent_browsertest.cc",
         "browser_ui/client_certificate/android/ssl_client_certificate_request_browsertest.cc",
         "test/android/browsertests_apk/components_browser_tests_jni_onload.cc",
       ]
@@ -781,6 +783,8 @@
       deps += [
         "//components/autofill_assistant/browser",
         "//components/autofill_assistant/browser:proto",
+        "//components/autofill_assistant/content/common:mojo_interfaces",
+        "//components/autofill_assistant/content/renderer",
         "//components/browser_ui/client_certificate/android",
         "//components/browser_ui/client_certificate/android:java",
         "//components/download/internal/common:internal_java",
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index e7671963..d9116231 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -104,3 +104,35 @@
     "//url:url",
   ]
 }
+
+static_library("arc_test_support") {
+  testonly = true
+  sources = [
+    "test/fake_intent_helper_instance.cc",
+    "test/fake_intent_helper_instance.h",
+  ]
+
+  deps = [ "//components/arc/mojom" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "intent_helper/activity_icon_loader_unittest.cc",
+    "intent_helper/arc_intent_helper_bridge_unittest.cc",
+    "intent_helper/custom_tab_unittest.cc",
+    "intent_helper/intent_filter_unittest.cc",
+    "intent_helper/link_handler_model_unittest.cc",
+  ]
+
+  deps = [
+    ":arc",
+    ":arc_test_support",
+    "//base/test:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//ui/aura:test_support",
+    "//ui/views",
+    "//ui/views:test_support",
+  ]
+}
diff --git a/ash/components/arc/intent_helper/activity_icon_loader_unittest.cc b/components/arc/intent_helper/activity_icon_loader_unittest.cc
similarity index 100%
rename from ash/components/arc/intent_helper/activity_icon_loader_unittest.cc
rename to components/arc/intent_helper/activity_icon_loader_unittest.cc
diff --git a/ash/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc b/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc
similarity index 100%
rename from ash/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc
rename to components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc
diff --git a/ash/components/arc/intent_helper/custom_tab_unittest.cc b/components/arc/intent_helper/custom_tab_unittest.cc
similarity index 100%
rename from ash/components/arc/intent_helper/custom_tab_unittest.cc
rename to components/arc/intent_helper/custom_tab_unittest.cc
diff --git a/ash/components/arc/intent_helper/intent_filter_unittest.cc b/components/arc/intent_helper/intent_filter_unittest.cc
similarity index 100%
rename from ash/components/arc/intent_helper/intent_filter_unittest.cc
rename to components/arc/intent_helper/intent_filter_unittest.cc
diff --git a/ash/components/arc/intent_helper/link_handler_model_unittest.cc b/components/arc/intent_helper/link_handler_model_unittest.cc
similarity index 100%
rename from ash/components/arc/intent_helper/link_handler_model_unittest.cc
rename to components/arc/intent_helper/link_handler_model_unittest.cc
diff --git a/ash/components/arc/test/fake_intent_helper_instance.cc b/components/arc/test/fake_intent_helper_instance.cc
similarity index 98%
rename from ash/components/arc/test/fake_intent_helper_instance.cc
rename to components/arc/test/fake_intent_helper_instance.cc
index de0f50a..d96b98e 100644
--- a/ash/components/arc/test/fake_intent_helper_instance.cc
+++ b/components/arc/test/fake_intent_helper_instance.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/arc/test/fake_intent_helper_instance.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
 
 #include <algorithm>
 #include <iterator>
diff --git a/ash/components/arc/test/fake_intent_helper_instance.h b/components/arc/test/fake_intent_helper_instance.h
similarity index 95%
rename from ash/components/arc/test/fake_intent_helper_instance.h
rename to components/arc/test/fake_intent_helper_instance.h
index 16a18ed..7e77a26 100644
--- a/ash/components/arc/test/fake_intent_helper_instance.h
+++ b/components/arc/test/fake_intent_helper_instance.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_ARC_TEST_FAKE_INTENT_HELPER_INSTANCE_H_
-#define ASH_COMPONENTS_ARC_TEST_FAKE_INTENT_HELPER_INSTANCE_H_
+#ifndef COMPONENTS_ARC_TEST_FAKE_INTENT_HELPER_INSTANCE_H_
+#define COMPONENTS_ARC_TEST_FAKE_INTENT_HELPER_INSTANCE_H_
 
 #include <map>
 #include <string>
@@ -142,4 +142,4 @@
 
 }  // namespace arc
 
-#endif  // ASH_COMPONENTS_ARC_TEST_FAKE_INTENT_HELPER_INSTANCE_H_
+#endif  // COMPONENTS_ARC_TEST_FAKE_INTENT_HELPER_INSTANCE_H_
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
index 32ab188..50d911b 100644
--- a/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -1437,6 +1437,8 @@
   if (!form_structure)
     return;
 
+  driver()->SendAutofillTypePredictionsToRenderer({form_structure});
+
   if (ShouldTriggerRefill(*form_structure))
     TriggerRefill(form);
 }
diff --git a/components/autofill/core/browser/data_model/credit_card.cc b/components/autofill/core/browser/data_model/credit_card.cc
index 301e007..1ba8bbbe 100644
--- a/components/autofill/core/browser/data_model/credit_card.cc
+++ b/components/autofill/core/browser/data_model/credit_card.cc
@@ -983,6 +983,10 @@
   return data_util::Expiration2DigitMonthAsString(expiration_month_);
 }
 
+std::u16string CreditCard::Expiration2DigitYearAsString() const {
+  return data_util::Expiration2DigitYearAsString(expiration_year_);
+}
+
 std::u16string CreditCard::Expiration4DigitYearAsString() const {
   return data_util::Expiration4DigitYearAsString(expiration_year_);
 }
@@ -1021,10 +1025,6 @@
   return virtual_card;
 }
 
-std::u16string CreditCard::Expiration2DigitYearAsString() const {
-  return data_util::Expiration2DigitYearAsString(expiration_year_);
-}
-
 void CreditCard::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
   supported_types->insert(CREDIT_CARD_NAME_FULL);
   supported_types->insert(CREDIT_CARD_NAME_FIRST);
diff --git a/components/autofill/core/browser/data_model/credit_card.h b/components/autofill/core/browser/data_model/credit_card.h
index 825eedc..2cfeea5 100644
--- a/components/autofill/core/browser/data_model/credit_card.h
+++ b/components/autofill/core/browser/data_model/credit_card.h
@@ -316,6 +316,7 @@
   std::u16string ExpirationDateForDisplay() const;
   // Expiration functions.
   std::u16string Expiration2DigitMonthAsString() const;
+  std::u16string Expiration2DigitYearAsString() const;
   std::u16string Expiration4DigitYearAsString() const;
 
   // Whether the cardholder name was created from separate first name and last
@@ -353,8 +354,6 @@
   FRIEND_TEST_ALL_PREFIXES(CreditCardTest, SetExpirationDateFromString);
   FRIEND_TEST_ALL_PREFIXES(CreditCardTest, SetExpirationYearFromString);
 
-  std::u16string Expiration2DigitYearAsString() const;
-
   // FormGroup:
   void GetSupportedTypes(ServerFieldTypeSet* supported_types) const override;
   std::u16string GetInfoImpl(const AutofillType& type,
diff --git a/components/autofill/core/browser/field_filler.cc b/components/autofill/core/browser/field_filler.cc
index 7b7113d..c1a6c767 100644
--- a/components/autofill/core/browser/field_filler.cc
+++ b/components/autofill/core/browser/field_filler.cc
@@ -508,27 +508,29 @@
       field, number, phone_home_city_and_number, *field_data);
 }
 
-// Set |field_data|'s value to |number|, or possibly an appropriate substring
-// of |number| for cases where credit card number splits across multiple HTML
-// form input fields.
-// The |field| specifies the |credit_card_number_offset_| to the substring
-// within credit card number.
-void FillCreditCardNumberField(const AutofillField& field,
-                               const std::u16string& number,
-                               FormFieldData* field_data) {
-  std::u16string value = number;
+// Return the appropriate credit card number from |credit_card|. Truncates the
+// credit card number to be split across HTML form input fields depending on if
+// |field.credit_card_number_offset()| is less than the length of the credit
+// card number.
+std::u16string GetCreditCardNumberForInput(
+    const CreditCard& credit_card,
+    const AutofillField& field,
+    const std::string& app_locale,
+    mojom::RendererFormDataAction action) {
+  std::u16string value;
+
+  // In preview, only show the last four of the credit card number.
+  value = action == mojom::RendererFormDataAction::kPreview
+              ? credit_card.ObfuscatedLastFourDigits()
+              : credit_card.GetInfo(CREDIT_CARD_NUMBER, app_locale);
 
   // |field|'s max_length truncates credit card number to fit within.
-  if (field.credit_card_number_offset() < number.length()) {
-    field_data->value = number.substr(
+  if (field.credit_card_number_offset() < value.length()) {
+    value = value.substr(
         field.credit_card_number_offset(),
         field.max_length > 0 ? field.max_length : std::u16string::npos);
-  } else {
-    // If the offset exceeds the length of the number, simply fill the whole
-    // number. By this, a wrongly detected second credit card number field
-    // before the actual field will not prevent the filling.
-    field_data->value = number;
   }
+  return value;
 }
 
 // Fills in the select control |field| with |value|. If an exact match is not
@@ -577,10 +579,11 @@
   return false;
 }
 
-// Fills in the month control |field| with the expiration date in |card|.
-void FillMonthControl(const CreditCard& card, FormFieldData* field) {
-  field->value = card.Expiration4DigitYearAsString() + u"-" +
-                 card.Expiration2DigitMonthAsString();
+// Gets the appropriate expiration date from the |card| for a month control
+// field. (i.e. a <input type="month">)
+std::u16string GetExpirationForMonthControl(const CreditCard& card) {
+  return card.Expiration4DigitYearAsString() + u"-" +
+         card.Expiration2DigitMonthAsString();
 }
 
 // Fills |field| with the street address in |value|. Translates newlines into
@@ -661,100 +664,67 @@
   return false;
 }
 
-// Fills the expiration year |value| into the |field|. Uses the |field_type|
-// and the |field|'s max_length attribute to determine if the |value| needs to
-// be truncated.
-void FillExpirationYearInput(std::u16string value,
-                             ServerFieldType field_type,
-                             FormFieldData* field) {
-  // If the |field_type| requires only 2 digits, keep only the last 2 digits of
-  // |value|.
-  if (field_type == CREDIT_CARD_EXP_2_DIGIT_YEAR && value.length() > 2)
-    value = value.substr(value.length() - 2, 2);
+// Returns the appropriate expiration year from |credit_card| for the field.
+// Uses the |field_type| and the |field|'s max_length attribute to
+// determine if the year needs to be truncated.
+std::u16string GetExpirationYearForInput(const CreditCard& credit_card,
+                                         ServerFieldType field_type,
+                                         const AutofillField& field) {
+  std::u16string value;
+  value = field_type == CREDIT_CARD_EXP_2_DIGIT_YEAR
+              ? credit_card.Expiration2DigitYearAsString()
+              : credit_card.Expiration4DigitYearAsString();
 
-  if (field->max_length == 0 || field->max_length >= value.size()) {
-    // No length restrictions, fill the year value directly.
-    field->value = value;
-  } else {
-    // Truncate the front of |value| to keep only the number of characters equal
-    // to the |field|'s max length.
-    field->value =
-        value.substr(value.length() - field->max_length, field->max_length);
+  // In case the field's max_length is less than the length of the year, shorten
+  // the year to field.max_length.
+  if (field.max_length != 0 && field.max_length < value.length()) {
+    value = value.substr(value.length() - field.max_length, field.max_length);
   }
+
+  return value;
 }
 
-// Returns whether the expiration date |value| was filled into the |field|.
-// Uses the |field|'s max_length attribute to determine if the |value| needs to
-// be truncated. |value| should be a date formatted as either MM/YY or MM/YYYY.
-// If it isn't, the field doesn't get filled.
-bool FillExpirationDateInput(const std::u16string& value,
-                             FormFieldData* field,
-                             std::string* failure_to_fill) {
+// Returns the appropriate expiration date from |credit_card| for the field
+// based on the |field_type|. Uses the |field|'s max_length attribute to
+// determine if the |value| needs to be truncated or padded. Returns an empty
+// string in case of a failure.
+std::u16string GetExpirationDateForInput(const CreditCard& credit_card,
+                                         const AutofillField& field,
+                                         ServerFieldType field_type,
+                                         std::string* failure_to_fill) {
   const std::u16string kSeparator = u"/";
-  // Autofill formats a combined date as month/year.
-  std::vector<std::u16string> pieces = base::SplitString(
-      value, kSeparator, base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-  if (pieces.size() != 2) {
-    if (failure_to_fill)
-      *failure_to_fill += "Could not split expiration into two pieces. ";
-    return false;
-  }
+  std::u16string month = credit_card.Expiration2DigitMonthAsString();
+  std::u16string two_digit_year = credit_card.Expiration2DigitYearAsString();
+  std::u16string four_digit_year = credit_card.Expiration4DigitYearAsString();
 
-  std::u16string month = pieces[0];
-  std::u16string year = pieces[1];
-  if (month.length() != 2 || (year.length() != 2 && year.length() != 4)) {
-    if (failure_to_fill)
-      *failure_to_fill += "Unexpected length of month or year to fill. ";
-    return false;
-  }
 
-  switch (field->max_length) {
+  switch (field.max_length) {
     case 1:
     case 2:
     case 3:
-      if (failure_to_fill)
-        *failure_to_fill += "Field to fill had a lenght of 1-3. ";
-      return false;
+      if (failure_to_fill) {
+        *failure_to_fill +=
+            "Field to fill must have a max length of at least 4. ";
+      }
+      return std::u16string();
     case 4:
       // Field likely expects MMYY
-      if (year.length() != 2) {
-        // Shorten year to 2 characters from 4
-        year = year.substr(2);
-      }
-
-      field->value = month + year;
-      break;
+      return month + two_digit_year;
     case 5:
       // Field likely expects MM/YY
-      if (year.length() != 2) {
-        // Shorten year to 2 characters
-        year = year.substr(2);
-        field->value = month + kSeparator + year;
-      } else {
-        field->value = value;
-      }
-      break;
+      return month + kSeparator + two_digit_year;
     case 6:
+      // Field likely expects MMYYYY
+      return month + four_digit_year;
     case 7:
-      if (year.length() != 4) {
-        // Will normalize 2-digit years to the 4-digit version.
-        year = u"20" + year;
-      }
-
-      if (field->max_length == 6) {
-        // Field likely expects MMYYYY
-        field->value = month + year;
-      } else {
-        // Field likely expects MM/YYYY
-        field->value = month + kSeparator + year;
-      }
-      break;
+      // Field likely expects MM/YYYY
+      return month + kSeparator + four_digit_year;
     default:
       // Includes the case where max_length is not specified (0).
-      field->value = month + kSeparator + year;
+      return field_type == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR
+                 ? month + kSeparator + two_digit_year
+                 : month + kSeparator + four_digit_year;
   }
-
-  return true;
 }
 
 std::u16string RemoveWhitespace(const std::u16string& value) {
@@ -792,6 +762,39 @@
   }
 }
 
+// Returns the appropriate |credit_card| value based on |storable_type| to fill
+// into |field|.
+std::u16string GetValueForCreditCard(const CreditCard& credit_card,
+                                     const std::u16string& cvc,
+                                     const std::string& app_locale,
+                                     mojom::RendererFormDataAction action,
+                                     const AutofillField& field,
+                                     std::string* failure_to_fill) {
+  ServerFieldType storable_type = field.Type().GetStorableType();
+
+  if (field.form_control_type == "month") {
+    return GetExpirationForMonthControl(credit_card);
+  } else {
+    switch (storable_type) {
+      case CREDIT_CARD_VERIFICATION_CODE:
+        return cvc;
+      case CREDIT_CARD_NUMBER:
+        return GetCreditCardNumberForInput(credit_card, field, app_locale,
+                                           action);
+      case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
+      case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
+        return GetExpirationDateForInput(credit_card, field, storable_type,
+                                         failure_to_fill);
+      case CREDIT_CARD_EXP_2_DIGIT_YEAR:
+      case CREDIT_CARD_EXP_4_DIGIT_YEAR:
+        return GetExpirationYearForInput(credit_card, storable_type, field);
+      default:
+        // All other cases handled here.
+        return credit_card.GetInfo(storable_type, app_locale);
+    }
+  }
+}
+
 }  // namespace
 
 FieldFiller::FieldFiller(const std::string& app_locale,
@@ -809,34 +812,43 @@
     mojom::RendererFormDataAction action,
     std::string* failure_to_fill) {
   const AutofillType type = field.Type();
-
   std::u16string value;
-  if (absl::holds_alternative<const AutofillProfile*>(profile_or_credit_card)) {
-    const AutofillProfile* profile =
-        absl::get<const AutofillProfile*>(profile_or_credit_card);
-    if (profile->ShouldSkipFillingOrSuggesting(type.GetStorableType())) {
+
+  if (absl::holds_alternative<const CreditCard*>(profile_or_credit_card)) {
+    const CreditCard* credit_card =
+        absl::get<const CreditCard*>(profile_or_credit_card);
+
+    value = GetValueForCreditCard(*credit_card, cvc, app_locale_, action, field,
+                                  failure_to_fill);
+
+    // Do not attempt to fill empty values as it would skew the metrics.
+    if (value.empty()) {
       if (failure_to_fill)
-        *failure_to_fill += "ShouldSkipFillingOrSuggesting() returned true. ";
+        *failure_to_fill += "No value to fill available. ";
       return false;
     }
-
-    value = profile->GetInfo(type, app_locale_);
-  } else {
-    DCHECK(absl::holds_alternative<const CreditCard*>(profile_or_credit_card));
-
-    if (type.GetStorableType() == CREDIT_CARD_VERIFICATION_CODE) {
-      value = cvc;
-    } else if (type.GetStorableType() == CREDIT_CARD_NUMBER &&
-               action == mojom::RendererFormDataAction::kPreview) {
-      const CreditCard* credit_card =
-          absl::get<const CreditCard*>(profile_or_credit_card);
-      value = credit_card->ObfuscatedLastFourDigits();
-    } else {
-      value = absl::get<const CreditCard*>(profile_or_credit_card)
-                  ->GetInfo(type, app_locale_);
+    if (field.form_control_type == "select-one") {
+      return FillSelectControl(type, value, credit_card, app_locale_,
+                               field_data, address_normalizer_,
+                               failure_to_fill);
     }
+    field_data->value = value;
+    return true;
   }
 
+  // Grab AutofillProfile data.
+  DCHECK(
+      absl::holds_alternative<const AutofillProfile*>(profile_or_credit_card));
+  const AutofillProfile* profile =
+      absl::get<const AutofillProfile*>(profile_or_credit_card);
+  if (profile->ShouldSkipFillingOrSuggesting(type.GetStorableType())) {
+    if (failure_to_fill)
+      *failure_to_fill += "ShouldSkipFillingOrSuggesting() returned true. ";
+    return false;
+  }
+
+  value = profile->GetInfo(type, app_locale_);
+
   // Do not attempt to fill empty values as it would skew the metrics.
   if (value.empty()) {
     if (failure_to_fill)
@@ -844,6 +856,7 @@
     return false;
   }
 
+  // Filling of AutofillProfile.
   if (type.group() == FieldTypeGroup::kPhoneHome) {
     // If the |field_data| is a selection box and having the type
     // |PHONE_HOME_COUNTRY_CODE|, call |FillPhoneCountryCodeSelectControl|.
@@ -867,12 +880,6 @@
     return FillSelectControl(type, value, profile_or_credit_card, app_locale_,
                              field_data, address_normalizer_, failure_to_fill);
   }
-  if (field_data->form_control_type == "month") {
-    DCHECK(absl::holds_alternative<const CreditCard*>(profile_or_credit_card));
-    FillMonthControl(*absl::get<const CreditCard*>(profile_or_credit_card),
-                     field_data);
-    return true;
-  }
   if (type.GetStorableType() == ADDRESS_HOME_STREET_ADDRESS) {
     DCHECK(absl::holds_alternative<const AutofillProfile*>(
         profile_or_credit_card));
@@ -882,10 +889,6 @@
     FillStreetAddress(value, profile_language_code, field_data);
     return true;
   }
-  if (type.GetStorableType() == CREDIT_CARD_NUMBER) {
-    FillCreditCardNumberField(field, value, field_data);
-    return true;
-  }
   if (type.GetStorableType() == ADDRESS_HOME_STATE) {
     DCHECK(absl::holds_alternative<const AutofillProfile*>(
         profile_or_credit_card));
@@ -894,18 +897,6 @@
         app_locale_);
     return FillStateText(value, country_code, field_data, failure_to_fill);
   }
-  if (field_data->form_control_type == "text" &&
-      (type.GetStorableType() == CREDIT_CARD_EXP_2_DIGIT_YEAR ||
-       type.GetStorableType() == CREDIT_CARD_EXP_4_DIGIT_YEAR)) {
-    FillExpirationYearInput(value, type.GetStorableType(), field_data);
-    return true;
-  }
-  if (field_data->form_control_type == "text" &&
-      (type.GetStorableType() == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR ||
-       type.GetStorableType() == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR)) {
-    return FillExpirationDateInput(value, field_data, failure_to_fill);
-  }
-
   field_data->value = value;
   return true;
 }
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index 5e54253..f950043 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -73,7 +73,8 @@
     base::WeakPtr<RuntimeManagerImpl> runtime_manager,
     std::unique_ptr<Service> service,
     std::unique_ptr<AutofillAssistantTtsController> tts_controller,
-    ukm::UkmRecorder* ukm_recorder)
+    ukm::UkmRecorder* ukm_recorder,
+    AnnotateDomModelService* annotate_dom_model_service)
     : content::WebContentsObserver(web_contents),
       client_(client),
       tick_clock_(tick_clock),
@@ -83,7 +84,8 @@
                                              client_)),
       navigating_to_new_document_(web_contents->IsWaitingForResponse()),
       tts_controller_(std::move(tts_controller)),
-      ukm_recorder_(ukm_recorder) {
+      ukm_recorder_(ukm_recorder),
+      annotate_dom_model_service_(annotate_dom_model_service) {
   user_model_.AddObserver(this);
   tts_controller_->SetTtsEventDelegate(weak_ptr_factory_.GetWeakPtr());
 }
@@ -935,6 +937,10 @@
   return true;
 }
 
+AutofillAssistantState Controller::GetState() {
+  return state_;
+}
+
 void Controller::SetOverlayBehavior(
     ConfigureUiStateProto::OverlayBehavior overlay_behavior) {
   overlay_behavior_ = overlay_behavior;
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index 30cbbd49..5df3aa1 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -32,6 +32,7 @@
 #include "components/autofill_assistant/browser/user_data.h"
 #include "components/autofill_assistant/browser/user_model.h"
 #include "components/autofill_assistant/browser/web/web_controller.h"
+#include "components/autofill_assistant/content/browser/annotate_dom_model_service.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
@@ -68,7 +69,8 @@
              base::WeakPtr<RuntimeManagerImpl> runtime_manager,
              std::unique_ptr<Service> service,
              std::unique_ptr<AutofillAssistantTtsController> tts_controller,
-             ukm::UkmRecorder* ukm_recorder);
+             ukm::UkmRecorder* ukm_recorder,
+             AnnotateDomModelService* annotate_dom_model_service);
 
   Controller(const Controller&) = delete;
   Controller& operator=(const Controller&) = delete;
@@ -192,6 +194,7 @@
   void SetBrowseDomainsAllowlist(std::vector<std::string> domains) override;
 
   bool EnterState(AutofillAssistantState state) override;
+  AutofillAssistantState GetState() override;
   void SetOverlayBehavior(
       ConfigureUiStateProto::OverlayBehavior overlay_behavior) override;
   void SetCollectUserDataOptions(CollectUserDataOptions* options) override;
@@ -639,6 +642,10 @@
 
   ukm::UkmRecorder* ukm_recorder_;
 
+  // If instantiated, will start delivering the required model for annotating
+  // DOM nodes. May be nullptr.
+  AnnotateDomModelService* const annotate_dom_model_service_;
+
   base::WeakPtrFactory<Controller> weak_ptr_factory_{this};
 };
 
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index bc24d72..2b72a255 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -119,7 +119,8 @@
     controller_ = std::make_unique<Controller>(
         web_contents(), &mock_client_, task_environment()->GetMockTickClock(),
         mock_runtime_manager_->GetWeakPtr(), std::move(service),
-        std::move(tts_controller), &ukm_recorder_);
+        std::move(tts_controller), &ukm_recorder_,
+        /* annotate_dom_model_service= */ nullptr);
     controller_->SetWebControllerForTest(std::move(web_controller));
 
     ON_CALL(mock_client_, AttachUI()).WillByDefault(Invoke([this]() {
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.cc b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
index eebbb82..b6f2276 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.cc
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
@@ -70,6 +70,11 @@
   return true;
 }
 
+AutofillAssistantState FakeScriptExecutorDelegate::GetState() {
+  return state_history_.empty() ? AutofillAssistantState::INACTIVE
+                                : state_history_.back();
+}
+
 void FakeScriptExecutorDelegate::SetTouchableElementArea(
     const ElementAreaProto& element) {}
 
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.h b/components/autofill_assistant/browser/fake_script_executor_delegate.h
index 01a326f3..723d6143 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.h
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.h
@@ -41,6 +41,7 @@
   std::string GetEmailAddressForAccessTokenAccount() override;
   ukm::UkmRecorder* GetUkmRecorder() override;
   bool EnterState(AutofillAssistantState state) override;
+  AutofillAssistantState GetState() override;
   void SetTouchableElementArea(const ElementAreaProto& element) override;
   void SetStatusMessage(const std::string& message) override;
   std::string GetStatusMessage() const override;
@@ -136,11 +137,6 @@
     return state_history_;
   }
 
-  AutofillAssistantState GetState() const {
-    return state_history_.empty() ? AutofillAssistantState::INACTIVE
-                                  : state_history_.back();
-  }
-
   const std::vector<Details>& GetDetails() { return details_; }
 
   const GenericUserInterfaceProto* GetPersistentGenericUi() {
diff --git a/components/autofill_assistant/browser/features.cc b/components/autofill_assistant/browser/features.cc
index 5388e868..7a2f790 100644
--- a/components/autofill_assistant/browser/features.cc
+++ b/components/autofill_assistant/browser/features.cc
@@ -9,9 +9,15 @@
 namespace autofill_assistant {
 namespace features {
 
+// Controls whether to enable Autofill Assistant.
 const base::Feature kAutofillAssistant{"AutofillAssistant",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Controls whether to enable Autofill Assistant's way of annotating DOM. If
+// enabled will create an |AnnotateDomModelService|.
+const base::Feature kAutofillAssistantAnnotateDom{
+    "AutofillAssistantAnnotateDom", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Controls whether to enable Assistant Autofill in a normal Chrome tab.
 const base::Feature kAutofillAssistantChromeEntry{
     "AutofillAssistantChromeEntry", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/autofill_assistant/browser/features.h b/components/autofill_assistant/browser/features.h
index be76b5d..4a9e63c 100644
--- a/components/autofill_assistant/browser/features.h
+++ b/components/autofill_assistant/browser/features.h
@@ -14,6 +14,7 @@
 
 // All features in alphabetical order.
 extern const base::Feature kAutofillAssistant;
+extern const base::Feature kAutofillAssistantAnnotateDom;
 extern const base::Feature kAutofillAssistantChromeEntry;
 extern const base::Feature kAutofillAssistantDialogOnboarding;
 extern const base::Feature kAutofillAssistantDirectActions;
diff --git a/components/autofill_assistant/browser/mock_script_executor_delegate.h b/components/autofill_assistant/browser/mock_script_executor_delegate.h
index a79f2a1..c93e3d6 100644
--- a/components/autofill_assistant/browser/mock_script_executor_delegate.h
+++ b/components/autofill_assistant/browser/mock_script_executor_delegate.h
@@ -52,6 +52,7 @@
               (override));
   MOCK_METHOD(ukm::UkmRecorder*, GetUkmRecorder, (), (override));
   MOCK_METHOD(bool, EnterState, (AutofillAssistantState state), (override));
+  MOCK_METHOD(AutofillAssistantState, GetState, (), (override));
   MOCK_METHOD(void,
               SetOverlayBehavior,
               (ConfigureUiStateProto::OverlayBehavior overlay_behavior),
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index 385a38a..9d74aee 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -1265,7 +1265,7 @@
   if (observer_)
     observer_->OnInterruptFinished();
 
-  RestoreStatusMessage();
+  RestorePreInterruptState();
   RestorePreInterruptScroll();
 
   // Restart. We use the original wait time since the interruption could have
@@ -1300,15 +1300,18 @@
   if (saved_pre_interrupt_state_)
     return;
 
-  pre_interrupt_status_ = delegate_->GetStatusMessage();
-  saved_pre_interrupt_state_ = true;
+  ExecutorState pre_interrupt_state;
+  pre_interrupt_state.status_message = delegate_->GetStatusMessage();
+  pre_interrupt_state.controller_state = delegate_->GetState();
+  saved_pre_interrupt_state_ = pre_interrupt_state;
 }
 
-void ScriptExecutor::WaitForDomOperation::RestoreStatusMessage() {
+void ScriptExecutor::WaitForDomOperation::RestorePreInterruptState() {
   if (!saved_pre_interrupt_state_)
     return;
 
-  delegate_->SetStatusMessage(pre_interrupt_status_);
+  delegate_->SetStatusMessage(saved_pre_interrupt_state_->status_message);
+  delegate_->EnterState(saved_pre_interrupt_state_->controller_state);
 }
 
 void ScriptExecutor::WaitForDomOperation::RestorePreInterruptScroll() {
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index 1e6db634..ef7d4f9 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -296,6 +296,13 @@
     void SetTimeoutWarningCallback(WarningCallback timeout_warning);
 
    private:
+    struct ExecutorState {
+      // The status message that was displayed when the interrupt started.
+      std::string status_message;
+      // The state the controller was in when the interrupt triggered.
+      AutofillAssistantState controller_state;
+    };
+
     void Start();
     void Pause();
     void Continue();
@@ -326,8 +333,8 @@
     // Saves the current state and sets save_pre_interrupt_state_.
     void SavePreInterruptState();
 
-    // Restores the UI states as found by SavePreInterruptState.
-    void RestoreStatusMessage();
+    // Restores the state as found by SavePreInterruptState.
+    void RestorePreInterruptState();
 
     // if save_pre_interrupt_state_ is set, attempt to scroll the page back to
     // the original area.
@@ -367,12 +374,9 @@
     // The interrupt that's currently running.
     std::unique_ptr<ScriptExecutor> interrupt_executor_;
 
-    // If true, pre-interrupt state was saved already. This happens just before
-    // the first interrupt.
-    bool saved_pre_interrupt_state_ = false;
-
-    // The status message that was displayed when the interrupt started.
-    std::string pre_interrupt_status_;
+    // The state of the ScriptExecutor, as registered before the first interrupt
+    // is run.
+    absl::optional<ExecutorState> saved_pre_interrupt_state_;
 
     // Paths of the interrupts that were just run. These interrupts are
     // prevented from firing for one round.
diff --git a/components/autofill_assistant/browser/script_executor_delegate.h b/components/autofill_assistant/browser/script_executor_delegate.h
index 3953ff75..8ada6c9 100644
--- a/components/autofill_assistant/browser/script_executor_delegate.h
+++ b/components/autofill_assistant/browser/script_executor_delegate.h
@@ -71,6 +71,9 @@
   // Enters the given state. Returns true if the state was changed.
   virtual bool EnterState(AutofillAssistantState state) = 0;
 
+  // Returns the current state.
+  virtual AutofillAssistantState GetState() = 0;
+
   virtual void SetOverlayBehavior(
       ConfigureUiStateProto::OverlayBehavior overlay_behavior) = 0;
 
diff --git a/components/autofill_assistant/content/browser/content_autofill_assistant_driver.cc b/components/autofill_assistant/content/browser/content_autofill_assistant_driver.cc
index 20b8fc7..5e23f949 100644
--- a/components/autofill_assistant/content/browser/content_autofill_assistant_driver.cc
+++ b/components/autofill_assistant/content/browser/content_autofill_assistant_driver.cc
@@ -4,6 +4,8 @@
 
 #include "components/autofill_assistant/content/browser/content_autofill_assistant_driver.h"
 
+#include "base/files/file.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 
 namespace autofill_assistant {
@@ -33,4 +35,45 @@
   return autofill_assistant_agent_;
 }
 
+void ContentAutofillAssistantDriver::SetAnnotateDomModelService(
+    AnnotateDomModelService* annotate_dom_model_service) {
+  DCHECK(annotate_dom_model_service);
+  annotate_dom_model_service_ = annotate_dom_model_service;
+}
+
+void ContentAutofillAssistantDriver::GetAnnotateDomModel(
+    GetAnnotateDomModelCallback callback) {
+  DCHECK(annotate_dom_model_service_);
+  if (!annotate_dom_model_service_) {
+    std::move(callback).Run(base::File());
+  }
+
+  absl::optional<base::File> file = annotate_dom_model_service_->GetModelFile();
+  if (file) {
+    std::move(callback).Run(file->Duplicate());
+    return;
+  }
+
+  annotate_dom_model_service_->NotifyOnModelFileAvailable(base::BindOnce(
+      &ContentAutofillAssistantDriver::OnModelAvailabilityChanged,
+      weak_pointer_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void ContentAutofillAssistantDriver::OnModelAvailabilityChanged(
+    GetAnnotateDomModelCallback callback,
+    bool is_available) {
+  if (!is_available) {
+    std::move(callback).Run(base::File());
+    return;
+  }
+
+  auto file_opt = annotate_dom_model_service_->GetModelFile();
+  DCHECK(file_opt);
+  if (!file_opt) {
+    std::move(callback).Run(base::File());
+    return;
+  }
+  std::move(callback).Run(file_opt->Duplicate());
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/content/browser/content_autofill_assistant_driver.h b/components/autofill_assistant/content/browser/content_autofill_assistant_driver.h
index a69a0ea..b6e2ea7 100644
--- a/components/autofill_assistant/content/browser/content_autofill_assistant_driver.h
+++ b/components/autofill_assistant/content/browser/content_autofill_assistant_driver.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_CONTENT_BROWSER_CONTENT_AUTOFILL_ASSISTANT_DRIVER_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_CONTENT_BROWSER_CONTENT_AUTOFILL_ASSISTANT_DRIVER_H_
 
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/content/browser/annotate_dom_model_service.h"
 #include "components/autofill_assistant/content/common/autofill_assistant_agent.mojom.h"
 #include "components/autofill_assistant/content/common/autofill_assistant_driver.mojom.h"
 #include "content/public/browser/document_user_data.h"
@@ -35,6 +37,12 @@
   const mojo::AssociatedRemote<mojom::AutofillAssistantAgent>&
   GetAutofillAssistantAgent();
 
+  void SetAnnotateDomModelService(
+      AnnotateDomModelService* annotate_dom_model_service);
+
+  // autofill_assistant::mojom::AutofillAssistantDriver:
+  void GetAnnotateDomModel(GetAnnotateDomModelCallback callback) override;
+
  private:
   explicit ContentAutofillAssistantDriver(
       content::RenderFrameHost* render_frame_host);
@@ -42,10 +50,18 @@
   friend DocumentUserData;
   DOCUMENT_USER_DATA_KEY_DECL();
 
+  void OnModelAvailabilityChanged(GetAnnotateDomModelCallback callback,
+                                  bool is_available);
+
+  AnnotateDomModelService* annotate_dom_model_service_ = nullptr;
+
   mojo::AssociatedReceiver<mojom::AutofillAssistantDriver> receiver_{this};
 
   mojo::AssociatedRemote<mojom::AutofillAssistantAgent>
       autofill_assistant_agent_;
+
+  base::WeakPtrFactory<ContentAutofillAssistantDriver> weak_pointer_factory_{
+      this};
 };
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/content/common/autofill_assistant_driver.mojom b/components/autofill_assistant/content/common/autofill_assistant_driver.mojom
index 8f68e4f..f7192f3 100644
--- a/components/autofill_assistant/content/common/autofill_assistant_driver.mojom
+++ b/components/autofill_assistant/content/common/autofill_assistant_driver.mojom
@@ -4,7 +4,12 @@
 
 module autofill_assistant.mojom;
 
+import "mojo/public/mojom/base/read_only_file.mojom";
+
 // There is one instance of this interface per render frame host in the browser
 // process. All methods are called by renderer on browser.
 interface AutofillAssistantDriver {
+  // Request that the annotate DOM model is being loaded and returned for use
+  // by the AutofillAssistantAgent.
+  GetAnnotateDomModel() => (mojo_base.mojom.ReadOnlyFile? model_file);
 };
diff --git a/components/autofill_assistant/content/renderer/DEPS b/components/autofill_assistant/content/renderer/DEPS
index f81e93c..f0556f5 100644
--- a/components/autofill_assistant/content/renderer/DEPS
+++ b/components/autofill_assistant/content/renderer/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+content/public/common",
   "+content/public/renderer",
+  "+content/public/test",
   "+mojo/public/cpp/bindings/binding.h",
   "+services/service_manager/public/cpp",
   "+third_party/blink/public/common",
diff --git a/components/autofill_assistant/content/renderer/autofill_assistant_agent.cc b/components/autofill_assistant/content/renderer/autofill_assistant_agent.cc
index c0e8ca5..0137215 100644
--- a/components/autofill_assistant/content/renderer/autofill_assistant_agent.cc
+++ b/components/autofill_assistant/content/renderer/autofill_assistant_agent.cc
@@ -5,6 +5,7 @@
 #include "components/autofill_assistant/content/renderer/autofill_assistant_agent.h"
 
 #include "content/public/renderer/render_frame.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/public/web/modules/autofill_assistant/node_signals.h"
 #include "third_party/blink/public/web/web_local_frame.h"
@@ -65,4 +66,30 @@
   std::move(callback).Run(nodes);
 }
 
+void AutofillAssistantAgent::GetAnnotateDomModel(
+    base::OnceCallback<void(base::File)> callback) {
+  GetDriver()->GetAnnotateDomModel(std::move(callback));
+}
+
+const mojo::Remote<mojom::AutofillAssistantDriver>&
+AutofillAssistantAgent::GetDriver() {
+  if (!driver_) {
+    render_frame()->GetBrowserInterfaceBroker()->GetInterface(
+        driver_.BindNewPipeAndPassReceiver());
+    return driver_;
+  }
+
+  // The driver_ can become unbound or disconnected in testing so this catches
+  // that case and reconnects so `this` can connect to the driver in the
+  // browser.
+  if (driver_.is_bound() && driver_.is_connected()) {
+    return driver_;
+  }
+
+  driver_.reset();
+  render_frame()->GetBrowserInterfaceBroker()->GetInterface(
+      driver_.BindNewPipeAndPassReceiver());
+  return driver_;
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/content/renderer/autofill_assistant_agent.h b/components/autofill_assistant/content/renderer/autofill_assistant_agent.h
index 16bad73..790a8f0 100644
--- a/components/autofill_assistant/content/renderer/autofill_assistant_agent.h
+++ b/components/autofill_assistant/content/renderer/autofill_assistant_agent.h
@@ -5,8 +5,11 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_CONTENT_RENDERER_AUTOFILL_ASSISTANT_AGENT_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_CONTENT_RENDERER_AUTOFILL_ASSISTANT_AGENT_H_
 
+#include "base/callback_forward.h"
+#include "base/files/file.h"
 #include "base/memory/weak_ptr.h"
 #include "components/autofill_assistant/content/common/autofill_assistant_agent.mojom.h"
+#include "components/autofill_assistant/content/common/autofill_assistant_driver.mojom.h"
 #include "components/autofill_assistant/content/common/node_data.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
@@ -37,10 +40,16 @@
                         int32_t objective,
                         GetSemanticNodesCallback callback) override;
 
+  void GetAnnotateDomModel(base::OnceCallback<void(base::File)> callback);
+
  private:
   // content::RenderFrameObserver:
   void OnDestruct() override;
 
+  const mojo::Remote<mojom::AutofillAssistantDriver>& GetDriver();
+
+  mojo::Remote<mojom::AutofillAssistantDriver> driver_;
+
   mojo::AssociatedReceiver<mojom::AutofillAssistantAgent> receiver_{this};
   base::WeakPtrFactory<AutofillAssistantAgent> weak_ptr_factory_{this};
 };
diff --git a/components/autofill_assistant/content/renderer/autofill_assistant_agent_browsertest.cc b/components/autofill_assistant/content/renderer/autofill_assistant_agent_browsertest.cc
new file mode 100644
index 0000000..a44d75d3
--- /dev/null
+++ b/components/autofill_assistant/content/renderer/autofill_assistant_agent_browsertest.cc
@@ -0,0 +1,96 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill_assistant/content/renderer/autofill_assistant_agent.h"
+
+#include "base/files/file.h"
+#include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "components/autofill_assistant/content/common/autofill_assistant_driver.mojom.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/test/render_view_test.h"
+#include "mojo/public/cpp/bindings/associated_receiver_set.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::base::test::RunOnceCallback;
+
+class MockAutofillAssistantDriver : public mojom::AutofillAssistantDriver {
+ public:
+  void BindHandle(mojo::ScopedMessagePipeHandle handle) {
+    receivers_.Add(this, mojo::PendingReceiver<mojom::AutofillAssistantDriver>(
+                             std::move(handle)));
+  }
+
+  void BindPendingReceiver(mojo::ScopedInterfaceEndpointHandle handle) {
+    associated_receivers_.Add(
+        this, mojo::PendingAssociatedReceiver<mojom::AutofillAssistantDriver>(
+                  std::move(handle)));
+  }
+
+  MOCK_METHOD(void,
+              GetAnnotateDomModel,
+              (base::OnceCallback<void(base::File)> callback),
+              (override));
+
+ private:
+  mojo::ReceiverSet<mojom::AutofillAssistantDriver> receivers_;
+  mojo::AssociatedReceiverSet<mojom::AutofillAssistantDriver>
+      associated_receivers_;
+};
+
+class AutofillAssistantAgentBrowserTest : public content::RenderViewTest {
+ public:
+  AutofillAssistantAgentBrowserTest() = default;
+
+  void SetUp() override {
+    RenderViewTest::SetUp();
+
+    GetMainRenderFrame()->GetBrowserInterfaceBroker()->SetBinderForTesting(
+        mojom::AutofillAssistantDriver::Name_,
+        base::BindRepeating(&MockAutofillAssistantDriver::BindHandle,
+                            base::Unretained(&autofill_assistant_driver_)));
+    blink::AssociatedInterfaceProvider* remote_interfaces =
+        GetMainRenderFrame()->GetRemoteAssociatedInterfaces();
+    remote_interfaces->OverrideBinderForTesting(
+        mojom::AutofillAssistantDriver::Name_,
+        base::BindRepeating(&MockAutofillAssistantDriver::BindPendingReceiver,
+                            base::Unretained(&autofill_assistant_driver_)));
+    autofill_assistant_agent_ = std::make_unique<AutofillAssistantAgent>(
+        GetMainRenderFrame(), &associated_interfaces_);
+  }
+
+  void TearDown() override {
+    autofill_assistant_agent_.reset();
+    RenderViewTest::TearDown();
+  }
+
+ protected:
+  MockAutofillAssistantDriver autofill_assistant_driver_;
+  std::unique_ptr<AutofillAssistantAgent> autofill_assistant_agent_;
+  base::MockCallback<base::OnceCallback<void(base::File)>> callback_;
+
+ private:
+  blink::AssociatedInterfaceRegistry associated_interfaces_;
+};
+
+TEST_F(AutofillAssistantAgentBrowserTest, GetModelFile) {
+  EXPECT_CALL(autofill_assistant_driver_, GetAnnotateDomModel)
+      .WillOnce(RunOnceCallback<0>(base::File()));
+
+  EXPECT_CALL(callback_, Run);
+  autofill_assistant_agent_->GetAnnotateDomModel(callback_.Get());
+
+  base::RunLoop().RunUntilIdle();
+}
+
+}  // namespace
+}  // namespace autofill_assistant
diff --git a/components/browser_ui/styles/android/java/res/values/semantic_colors_dynamic.xml b/components/browser_ui/styles/android/java/res/values/semantic_colors_dynamic.xml
index 7d21625..de4631a 100644
--- a/components/browser_ui/styles/android/java/res/values/semantic_colors_dynamic.xml
+++ b/components/browser_ui/styles/android/java/res/values/semantic_colors_dynamic.xml
@@ -4,14 +4,18 @@
      found in the LICENSE file. -->
 <resources>
     <!-- Full dynamic colors ?attr version. Use for development. -->
-    <!--<macro name="default_icon_color">?attr/colorOnSurface</macro>
+    <!--
+    <macro name="default_bg_color">?attr/colorSurface</macro>
+    <macro name="default_icon_color">?attr/colorOnSurface</macro>
     <macro name="default_icon_color_accent1">?attr/colorPrimary</macro>
     <macro name="default_text_color">?attr/colorOnSurface</macro>
     <macro name="default_text_color_accent1">?attr/colorPrimary</macro>
     <macro name="hairline_stroke_color">?attr/colorOutline</macro>
-    <macro name="divider_line_bg_color">?attr/colorSurfaceVariant</macro>-->
+    <macro name="divider_line_bg_color">?attr/colorSurfaceVariant</macro>
+    -->
 
     <!-- Temporarily holdback @color version. Use for checkin. -->
+    <macro name="default_bg_color">@color/default_bg_color_baseline</macro>
     <macro name="default_icon_color">@color/default_icon_color_baseline</macro>
     <macro name="default_icon_color_accent1">@color/default_icon_color_accent1_baseline</macro>
     <macro name="default_text_color">@color/default_text_color_baseline</macro>
diff --git a/components/browser_ui/styles/android/java/src/org/chromium/components/browser_ui/styles/SemanticColorUtils.java b/components/browser_ui/styles/android/java/src/org/chromium/components/browser_ui/styles/SemanticColorUtils.java
index c540eea..e497174 100644
--- a/components/browser_ui/styles/android/java/src/org/chromium/components/browser_ui/styles/SemanticColorUtils.java
+++ b/components/browser_ui/styles/android/java/src/org/chromium/components/browser_ui/styles/SemanticColorUtils.java
@@ -31,6 +31,11 @@
         }
     }
 
+    /** Returns the semantic color value that corresponds to default_bg_color. */
+    public static @ColorInt int getDefaultBgColor(Context context) {
+        return resolve(R.attr.colorSurface, R.color.default_bg_color_baseline, context);
+    }
+
     /** Returns the semantic color value that corresponds to default_text_color. */
     public static @ColorInt int getDefaultTextColor(Context context) {
         return resolve(R.attr.colorOnSurface, R.color.default_text_color_baseline, context);
diff --git a/components/cbor/reader.cc b/components/cbor/reader.cc
index f81eaf2..9ff53853 100644
--- a/components/cbor/reader.cc
+++ b/components/cbor/reader.cc
@@ -6,6 +6,7 @@
 
 #include <math.h>
 
+#include <map>
 #include <utility>
 
 #include "base/check_op.h"
@@ -58,6 +59,7 @@
     "Floating point numbers are not supported.";
 const char kOutOfRangeIntegerValue[] =
     "Integer values must be between INT64_MIN and INT64_MAX.";
+const char kMapKeyDuplicate[] = "Duplicate map keys are not allowed.";
 const char kUnknownError[] = "An unknown error occured.";
 
 }  // namespace
@@ -313,7 +315,7 @@
     int max_nesting_level) {
   const uint64_t length = header.value;
 
-  Value::MapValue cbor_map;
+  std::map<Value, Value, Value::Less> cbor_map;
   for (uint64_t i = 0; i < length; ++i) {
     absl::optional<Value> key =
         DecodeCompleteDataItem(config, max_nesting_level - 1);
@@ -336,13 +338,24 @@
         error_code_ = DecoderError::INCORRECT_MAP_KEY_TYPE;
         return absl::nullopt;
     }
-    if (!IsKeyInOrder(key.value(), &cbor_map)) {
+    if (IsDuplicateKey(key.value(), cbor_map))
+      return absl::nullopt;
+
+    if (!config.allow_and_canonicalize_out_of_order_keys &&
+        !IsKeyInOrder(key.value(), cbor_map)) {
       return absl::nullopt;
     }
 
-    cbor_map.insert_or_assign(std::move(key.value()), std::move(value.value()));
+    cbor_map.emplace(std::move(key.value()), std::move(value.value()));
   }
-  return Value(std::move(cbor_map));
+
+  Value::MapValue map;
+  map.reserve(cbor_map.size());
+  // TODO(crbug/1271599): when Chromium switches to C++17, this code can be
+  // optimized using std::map::extract().
+  for (auto& it : cbor_map)
+    map.emplace_hint(map.end(), it.first.Clone(), std::move(it.second));
+  return Value(std::move(map));
 }
 
 absl::optional<uint8_t> Reader::ReadByte() {
@@ -370,13 +383,14 @@
   return true;
 }
 
-bool Reader::IsKeyInOrder(const Value& new_key, Value::MapValue* map) {
-  if (map->empty()) {
+bool Reader::IsKeyInOrder(const Value& new_key,
+                          const std::map<Value, Value, Value::Less>& map) {
+  if (map.empty()) {
     return true;
   }
 
-  const auto& max_current_key = map->rbegin()->first;
-  const auto less = map->key_comp();
+  const auto& max_current_key = map.rbegin()->first;
+  const auto less = map.key_comp();
   if (!less(max_current_key, new_key)) {
     error_code_ = DecoderError::OUT_OF_ORDER_KEY;
     return false;
@@ -384,6 +398,15 @@
   return true;
 }
 
+bool Reader::IsDuplicateKey(const Value& new_key,
+                            const std::map<Value, Value, Value::Less>& map) {
+  if (map.find(new_key) == map.end()) {
+    return false;
+  }
+  error_code_ = DecoderError::DUPLICATE_KEY;
+  return true;
+}
+
 // static
 const char* Reader::ErrorCodeToString(DecoderError error) {
   switch (error) {
@@ -413,6 +436,8 @@
       return kUnsupportedFloatingPointValue;
     case DecoderError::OUT_OF_RANGE_INTEGER_VALUE:
       return kOutOfRangeIntegerValue;
+    case DecoderError::DUPLICATE_KEY:
+      return kMapKeyDuplicate;
     case DecoderError::UNKNOWN_ERROR:
       return kUnknownError;
     default:
diff --git a/components/cbor/reader.h b/components/cbor/reader.h
index 6190bd74..a1eb01b 100644
--- a/components/cbor/reader.h
+++ b/components/cbor/reader.h
@@ -7,6 +7,8 @@
 
 #include <stddef.h>
 
+#include <map>
+
 #include "base/containers/span.h"
 #include "components/cbor/cbor_export.h"
 #include "components/cbor/values.h"
@@ -32,7 +34,7 @@
 // Requirements for canonical CBOR representation:
 //  - Duplicate keys in maps are not allowed.
 //  - Keys for maps must be sorted first by length and then by byte-wise
-//    lexical order.
+//    lexical order, as defined in Section 3.9.
 //
 // Known limitations and interpretations of the RFC (and the reasons):
 //  - Does not support indefinite-length data streams or semantic tags (major
@@ -70,6 +72,7 @@
     UNSUPPORTED_SIMPLE_VALUE,
     UNSUPPORTED_FLOATING_POINT_VALUE,
     OUT_OF_RANGE_INTEGER_VALUE,
+    DUPLICATE_KEY,
     UNKNOWN_ERROR,
   };
 
@@ -107,6 +110,18 @@
     // the motivating case and because it adds complexity to handle the ordering
     // correctly.)
     bool allow_invalid_utf8 = false;
+
+    // Causes an input to be accepted even if it contains one or more maps with
+    // keys that are not in the canonical ordering as defined in Section 3.9,
+    // and suppresses the OUT_OF_ORDER_KEY error. The original ordering of keys
+    // will _not_ be preserved, but instead, in the returned cbor::Value, all
+    // maps are re-sorted so that their keys are in canonical order. By
+    // definition, enabling this option may result in loss of information (i.e.
+    // the original key ordering).
+    //
+    // Enabling this option will still not allow duplicate keys, in case of
+    // which the DUPLICATE_KEY error will be emitted.
+    bool allow_and_canonicalize_out_of_order_keys = false;
   };
 
   Reader(const Reader&) = delete;
@@ -181,7 +196,12 @@
                                        int max_nesting_level);
   absl::optional<uint8_t> ReadByte();
   absl::optional<base::span<const uint8_t>> ReadBytes(uint64_t num_bytes);
-  bool IsKeyInOrder(const Value& new_key, Value::MapValue* map);
+  bool IsKeyInOrder(const Value& new_key,
+                    const std::map<Value, Value, Value::Less>& map);
+  // Check if `new_key` is a duplicate of a key that already exists in the
+  // `map`.
+  bool IsDuplicateKey(const Value& new_key,
+                      const std::map<Value, Value, Value::Less>& map);
   bool IsEncodingMinimal(uint8_t additional_bytes, uint64_t uint_data);
 
   DecoderError GetErrorCode() { return error_code_; }
diff --git a/components/cbor/reader_fuzzer.cc b/components/cbor/reader_fuzzer.cc
index 439154c..a513c20 100644
--- a/components/cbor/reader_fuzzer.cc
+++ b/components/cbor/reader_fuzzer.cc
@@ -12,8 +12,8 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   std::vector<uint8_t> input(data, data + size);
-  absl::optional<Value> cbor = Reader::Read(input);
 
+  absl::optional<Value> cbor = Reader::Read(input);
   if (cbor.has_value()) {
     absl::optional<std::vector<uint8_t>> serialized_cbor =
         Writer::Write(cbor.value());
@@ -24,6 +24,20 @@
                    input.size()) == 0);
     }
   }
+
+  Reader::Config config;
+  config.allow_and_canonicalize_out_of_order_keys = true;
+  absl::optional<Value> cbor_1 = Reader::Read(input, config);
+
+  if (cbor_1.has_value()) {
+    absl::optional<std::vector<uint8_t>> serialized_cbor =
+        Writer::Write(cbor_1.value());
+    CHECK(serialized_cbor.has_value());
+    if (serialized_cbor.has_value()) {
+      CHECK(serialized_cbor.value().size() == input.size());
+    }
+  }
+
   return 0;
 }
 
diff --git a/components/cbor/reader_unittest.cc b/components/cbor/reader_unittest.cc
index 5b8f836..926f8030 100644
--- a/components/cbor/reader_unittest.cc
+++ b/components/cbor/reader_unittest.cc
@@ -1081,16 +1081,91 @@
   };
 
   int test_element_index = 0;
-  Reader::DecoderError error_code;
   for (const auto& unsorted_map : kMapsWithUnsortedKeys) {
     testing::Message scope_message;
     scope_message << "testing unsorted map : " << test_element_index++;
     SCOPED_TRACE(scope_message);
 
-    absl::optional<Value> cbor =
-        Reader::Read(unsorted_map, &error_code);
-    EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_ORDER_KEY);
+    // Expect `OUT_OF_ORDER_KEY`.
+    {
+      Reader::DecoderError error_code;
+      absl::optional<Value> cbor =
+          Reader::Read(unsorted_map, &error_code);
+      EXPECT_FALSE(cbor.has_value());
+      EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_ORDER_KEY);
+    }
+
+    // When `allow_and_canonicalize_out_of_order_keys` flag is set, expect
+    // `CBOR_NO_ERROR`.
+    {
+      Reader::DecoderError error_code;
+      Reader::Config config;
+      config.error_code_out = &error_code;
+      config.allow_and_canonicalize_out_of_order_keys = true;
+
+      absl::optional<Value> cbor =
+          Reader::Read(unsorted_map, config);
+      EXPECT_TRUE(cbor);
+      EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
+    }
+  }
+}
+
+TEST(CBORReaderTest, TestOutOfOrderKeyErrorWithDuplicateKeys) {
+  static const std::vector<uint8_t> kMapsWithUnsortedKeys[] = {
+      // clang-format off
+      {0xa3,  // map with 3 keys with same major type and length
+         0x61, 0x62,  // key "b"
+         0x61, 0x42,  // value "B"
+
+         0x61, 0x61,  // key "a" (out of order byte-wise lexically)
+         0x61, 0x45,   // value "E"
+
+         0x61, 0x62,  // key "b" (duplicate)
+         0x61, 0x42,  // value "B"
+      },
+      {0xa3,  // map with 3 byte string keys
+         0x42, 'x', 'x', // key byte string "xx"
+                         // (out of order due to longer length)
+         0x02,
+
+         0x41, 'y',  // key byte string "y"
+         0x01,
+
+         0x41, 'y',  // key byte string "y" (duplicate)
+         0x02,
+      },
+      //clang-format on
+  };
+
+  int test_element_index = 0;
+  for (const auto& unsorted_map : kMapsWithUnsortedKeys) {
+    testing::Message scope_message;
+    scope_message << "testing unsorted map : " << test_element_index++;
+    SCOPED_TRACE(scope_message);
+
+    // Expect `OUT_OF_ORDER_KEY`.
+    {
+      Reader::DecoderError error_code;
+      absl::optional<Value> cbor =
+          Reader::Read(unsorted_map, &error_code);
+      EXPECT_FALSE(cbor.has_value());
+      EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_ORDER_KEY);
+    }
+
+    // When `allow_and_canonicalize_out_of_order_keys` flag is set, expect
+    // `DUPLICATE_KEY`.
+    {
+      Reader::DecoderError error_code;
+      Reader::Config config;
+      config.error_code_out = &error_code;
+      config.allow_and_canonicalize_out_of_order_keys = true;
+
+      absl::optional<Value> cbor =
+          Reader::Read(unsorted_map, config);
+      EXPECT_FALSE(cbor);
+      EXPECT_EQ(error_code, Reader::DecoderError::DUPLICATE_KEY);
+    }
   }
 }
 
@@ -1118,11 +1193,24 @@
       // clang-format on
   };
 
-  Reader::DecoderError error_code;
+  {
+    Reader::DecoderError error_code;
+    absl::optional<Value> cbor =
+        Reader::Read(kMapWithDuplicateKey, &error_code);
+    EXPECT_FALSE(cbor.has_value());
+    EXPECT_EQ(error_code, Reader::DecoderError::DUPLICATE_KEY);
+  }
 
-  absl::optional<Value> cbor = Reader::Read(kMapWithDuplicateKey, &error_code);
-  EXPECT_FALSE(cbor.has_value());
-  EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_ORDER_KEY);
+  {
+    Reader::DecoderError error_code;
+    Reader::Config config;
+    config.error_code_out = &error_code;
+    config.allow_and_canonicalize_out_of_order_keys = true;
+
+    absl::optional<Value> cbor = Reader::Read(kMapWithDuplicateKey, config);
+    EXPECT_FALSE(cbor.has_value());
+    EXPECT_EQ(error_code, Reader::DecoderError::DUPLICATE_KEY);
+  }
 }
 
 // Leveraging Markus Kuhn’s UTF-8 decoder stress test. See
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index 2eb78fc5..fbcff57 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "4.32",
-  "log_list_timestamp": "2021-11-18T01:34:13Z",
+  "version": "4.35",
+  "log_list_timestamp": "2021-11-21T01:34:15Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/download/internal/background_service/logger_impl.cc b/components/download/internal/background_service/logger_impl.cc
index 5663e4fa..4d040bb 100644
--- a/components/download/internal/background_service/logger_impl.cc
+++ b/components/download/internal/background_service/logger_impl.cc
@@ -39,33 +39,6 @@
   return "UNKNOWN";
 }
 
-// TODO(xingliu): Reuse ClientToHistogramSuffix in stats.cc.
-std::string ClientToString(DownloadClient client) {
-  switch (client) {
-    case DownloadClient::TEST:
-    case DownloadClient::TEST_2:
-    case DownloadClient::TEST_3:
-    case DownloadClient::INVALID:
-      return "TEST";
-    case DownloadClient::OFFLINE_PAGE_PREFETCH:
-      return "OfflinePagePrefetch";
-    case DownloadClient::BACKGROUND_FETCH:
-      return "BackgroundFetch";
-    case DownloadClient::DEBUGGING:
-      return "Debugging";
-    case DownloadClient::MOUNTAIN_INTERNAL:
-      return "MountainInternal";
-    case DownloadClient::PLUGIN_VM_IMAGE:
-      return "PluginVmImage";
-    case DownloadClient::OPTIMIZATION_GUIDE_PREDICTION_MODELS:
-      return "OptimizationGuidePredictionModels";
-    case DownloadClient::BOUNDARY:  // Intentional fallthrough.
-    default:
-      NOTREACHED();
-      return std::string();
-  }
-}
-
 std::string EntryStateToString(Entry::State state) {
   switch (state) {
     case Entry::State::NEW:
@@ -157,7 +130,8 @@
     const absl::optional<DriverEntry>& driver,
     const absl::optional<CompletionType>& completion_type) {
   base::Value serialized_entry(base::Value::Type::DICTIONARY);
-  serialized_entry.SetStringKey("client", ClientToString(entry.client));
+  serialized_entry.SetStringKey("client",
+                                BackgroundDownloadClientToString(entry.client));
   serialized_entry.SetStringKey("state", EntryStateToString(entry.state));
   serialized_entry.SetStringKey("guid", entry.guid);
 
@@ -294,7 +268,8 @@
     return;
 
   base::Value serialized_request(base::Value::Type::DICTIONARY);
-  serialized_request.SetStringKey("client", ClientToString(client));
+  serialized_request.SetStringKey("client",
+                                  BackgroundDownloadClientToString(client));
   serialized_request.SetStringKey("guid", guid);
   serialized_request.SetStringKey("result", StartResultToString(start_result));
   for (auto& observer : observers_)
diff --git a/components/download/internal/background_service/stats.cc b/components/download/internal/background_service/stats.cc
index aa1309a..25e95f68 100644
--- a/components/download/internal/background_service/stats.cc
+++ b/components/download/internal/background_service/stats.cc
@@ -10,6 +10,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "components/download/internal/background_service/startup_status.h"
+#include "components/download/public/background_service/clients.h"
 
 namespace download {
 namespace stats {
@@ -59,35 +60,6 @@
   return std::string();
 }
 
-// Converts DownloadClient to histogram suffix.
-// Should maps to suffix string in histograms.xml.
-std::string ClientToHistogramSuffix(DownloadClient client) {
-  switch (client) {
-    case DownloadClient::TEST:
-    case DownloadClient::TEST_2:
-    case DownloadClient::TEST_3:
-    case DownloadClient::INVALID:
-      return "__Test__";
-    case DownloadClient::OFFLINE_PAGE_PREFETCH:
-      return "OfflinePage";
-    case DownloadClient::BACKGROUND_FETCH:
-      return "BackgroundFetch";
-    case DownloadClient::DEBUGGING:
-      return "Debugging";
-    case DownloadClient::MOUNTAIN_INTERNAL:
-      return "MountainInternal";
-    case DownloadClient::PLUGIN_VM_IMAGE:
-      return "PluginVmImage";
-    case DownloadClient::OPTIMIZATION_GUIDE_PREDICTION_MODELS:
-      return "OptimizationGuidePredictionModels";
-    case DownloadClient::BOUNDARY:
-      NOTREACHED();
-      break;
-  }
-  NOTREACHED();
-  return std::string();
-}
-
 // Converts FileCleanupReason to histogram suffix.
 // Should maps to suffix string in histograms.xml.
 std::string FileCleanupReasonToHistogramSuffix(FileCleanupReason reason) {
@@ -151,7 +123,7 @@
   base::UmaHistogramEnumeration(name, action, ServiceApiAction::COUNT);
 
   // Total count for each action with client suffix.
-  name.append(".").append(ClientToHistogramSuffix(client));
+  name.append(".").append(BackgroundDownloadClientToString(client));
   base::UmaHistogramEnumeration(name, action, ServiceApiAction::COUNT);
 }
 
@@ -163,7 +135,7 @@
                                 DownloadParams::StartResult::COUNT);
 
   // Total count for each client result with client suffix.
-  name.append(".").append(ClientToHistogramSuffix(client));
+  name.append(".").append(BackgroundDownloadClientToString(client));
   base::UmaHistogramEnumeration(name, result,
                                 DownloadParams::StartResult::COUNT);
 }
@@ -177,7 +149,7 @@
 
   // Records the file size.
   std::string name("Download.Service.Complete.FileSize.");
-  name.append(ClientToHistogramSuffix(client));
+  name.append(BackgroundDownloadClientToString(client));
   uint64_t file_size_kb = file_size_bytes / 1024;
   base::UmaHistogramCustomCounts(name, static_cast<int>(file_size_kb), 1,
                                  kMaxFileSizeKB, 50);
@@ -258,7 +230,7 @@
 
 void LogHasUploadData(DownloadClient client, bool has_upload_data) {
   std::string name("Download.Service.Upload.HasUploadData");
-  name.append(".").append(ClientToHistogramSuffix(client));
+  name.append(".").append(BackgroundDownloadClientToString(client));
   base::UmaHistogramBoolean(name, has_upload_data);
 }
 
diff --git a/components/download/public/background_service/BUILD.gn b/components/download/public/background_service/BUILD.gn
index 6ab9547..d4dbf84f 100644
--- a/components/download/public/background_service/BUILD.gn
+++ b/components/download/public/background_service/BUILD.gn
@@ -12,6 +12,7 @@
     "background_download_service.h",
     "client.cc",
     "client.h",
+    "clients.cc",
     "clients.h",
     "download_metadata.cc",
     "download_metadata.h",
diff --git a/components/download/public/background_service/clients.cc b/components/download/public/background_service/clients.cc
new file mode 100644
index 0000000..a5a1096
--- /dev/null
+++ b/components/download/public/background_service/clients.cc
@@ -0,0 +1,36 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/download/public/background_service/clients.h"
+
+namespace download {
+
+// Must sync variants "DownloadClient" in histograms.xml
+std::string BackgroundDownloadClientToString(DownloadClient client) {
+  switch (client) {
+    case DownloadClient::TEST:
+    case DownloadClient::TEST_2:
+    case DownloadClient::TEST_3:
+    case DownloadClient::INVALID:
+      return "__Test__";
+    case DownloadClient::OFFLINE_PAGE_PREFETCH:
+      return "OfflinePage";
+    case DownloadClient::BACKGROUND_FETCH:
+      return "BackgroundFetch";
+    case DownloadClient::DEBUGGING:
+      return "Debugging";
+    case DownloadClient::MOUNTAIN_INTERNAL:
+      return "MountainInternal";
+    case DownloadClient::PLUGIN_VM_IMAGE:
+      return "PluginVmImage";
+    case DownloadClient::OPTIMIZATION_GUIDE_PREDICTION_MODELS:
+      return "OptimizationGuidePredictionModels";
+    case DownloadClient::BOUNDARY:
+      break;
+  }
+  NOTREACHED();
+  return std::string();
+}
+
+}  // namespace download
diff --git a/components/download/public/background_service/clients.h b/components/download/public/background_service/clients.h
index 6f05751..0ab4e95 100644
--- a/components/download/public/background_service/clients.h
+++ b/components/download/public/background_service/clients.h
@@ -7,6 +7,7 @@
 
 #include <map>
 #include <memory>
+#include <string>
 
 #include "components/download/public/background_service/client.h"
 
@@ -47,6 +48,11 @@
   BOUNDARY = 7,
 };
 
+// Get a string that represents a particular client. Used in histograms and
+// debugging web UI. Must never change existing value and sync value with
+// variants "DownloadClient" in histograms.xml.
+std::string BackgroundDownloadClientToString(DownloadClient client);
+
 using DownloadClientMap = std::map<DownloadClient, std::unique_ptr<Client>>;
 
 }  // namespace download
diff --git a/components/download/public/background_service/logger.h b/components/download/public/background_service/logger.h
index 4aa4c9a..513874f 100644
--- a/components/download/public/background_service/logger.h
+++ b/components/download/public/background_service/logger.h
@@ -7,7 +7,7 @@
 
 namespace base {
 class Value;
-}
+}  // namespace base
 
 namespace download {
 
diff --git a/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc b/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc
index 7af61a3..9fb3eb8 100644
--- a/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc
+++ b/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc
@@ -554,19 +554,20 @@
 };
 
 IN_PROC_BROWSER_TEST_F(NetErrorAutoReloaderFencedFrameBrowserTest,
-                       NoAutoReloadOnFecnedFrames) {
+                       NoAutoReloadOnFencedFrames) {
   const GURL main_url = embedded_test_server()->GetURL("/title1.html");
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
 
   const GURL fenced_frame_url = embedded_test_server()->GetURL("/title2.html");
   content::RenderFrameHost* fenced_frame_host =
       fenced_frame_test_helper().CreateFencedFrame(
-          shell()->web_contents()->GetMainFrame(), fenced_frame_url);
-  fenced_frame_host = fenced_frame_test_helper().NavigateFrameInFencedFrameTree(
-      fenced_frame_host, fenced_frame_url);
+          shell()->web_contents()->GetMainFrame(), fenced_frame_url,
+          net::ERR_BLOCKED_BY_RESPONSE);
+
   // The fenced frame navigation failed since it doesn't have the
   // Supports-Loading-Mode HTTP response header "fenced-frame".
   EXPECT_TRUE(fenced_frame_host->GetLastCommittedOrigin().opaque());
+  EXPECT_TRUE(fenced_frame_host->IsErrorDocument());
   EXPECT_EQ(absl::nullopt, GetCurrentAutoReloadDelay());
 }
 
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index dce5cdb..ccd6667 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -261,12 +261,14 @@
       "wayland_keyboard_delegate_unittest.cc",
       "wayland_positioner_unittest.cc",
       "zaura_shell_unittest.cc",
+      "zcr_remote_shell_impl_unittest.cc",
       "zcr_remote_shell_unittest.cc",
     ]
     deps += [
       "//ash",
       "//ash:test_support",
       "//ash/public/cpp",
+      "//third_party/wayland-protocols:remote_shell_protocol",
       "//third_party/wayland-protocols:xdg_shell_protocol",
       "//ui/compositor",
       "//ui/compositor:test_support",
diff --git a/components/exo/wayland/zcr_remote_shell_impl.cc b/components/exo/wayland/zcr_remote_shell_impl.cc
index ded2f06..2ddaa7d 100644
--- a/components/exo/wayland/zcr_remote_shell_impl.cc
+++ b/components/exo/wayland/zcr_remote_shell_impl.cc
@@ -522,6 +522,15 @@
   ScheduleSendDisplayMetrics(0);
 }
 
+void WaylandRemoteShell::OnDisplayTabletStateChanged(
+    display::TabletState state) {
+  const bool layout_change_started =
+      state == display::TabletState::kEnteringTabletMode ||
+      state == display::TabletState::kExitingTabletMode;
+  if (layout_change_started)
+    ScheduleSendDisplayMetrics(kConfigureDelayAfterLayoutSwitchMs);
+}
+
 void WaylandRemoteShell::OnDisplayMetricsChanged(
     const display::Display& display,
     uint32_t changed_metrics) {
@@ -541,14 +550,12 @@
   if (wl_resource_get_version(remote_shell_resource_) >=
       event_mapping_.layout_mode_since_version)
     event_mapping_.send_layout_mode(remote_shell_resource_, layout_mode_);
-  ScheduleSendDisplayMetrics(kConfigureDelayAfterLayoutSwitchMs);
 }
 void WaylandRemoteShell::OnTabletModeEnding() {
   layout_mode_ = ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
   if (wl_resource_get_version(remote_shell_resource_) >=
       event_mapping_.layout_mode_since_version)
     event_mapping_.send_layout_mode(remote_shell_resource_, layout_mode_);
-  ScheduleSendDisplayMetrics(kConfigureDelayAfterLayoutSwitchMs);
 }
 void WaylandRemoteShell::OnTabletModeEnded() {}
 
diff --git a/components/exo/wayland/zcr_remote_shell_impl.h b/components/exo/wayland/zcr_remote_shell_impl.h
index 75382de..2df39831b7 100644
--- a/components/exo/wayland/zcr_remote_shell_impl.h
+++ b/components/exo/wayland/zcr_remote_shell_impl.h
@@ -84,10 +84,11 @@
   void SetUseDefaultScaleCancellation(bool use_default_scale);
 
   void OnRemoteSurfaceDestroyed(wl_resource* resource);
+
   // Overridden from display::DisplayObserver:
   void OnDisplayAdded(const display::Display& new_display) override;
   void OnDisplayRemoved(const display::Display& old_display) override;
-
+  void OnDisplayTabletStateChanged(display::TabletState state) override;
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t changed_metrics) override;
 
diff --git a/components/exo/wayland/zcr_remote_shell_impl_unittest.cc b/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
new file mode 100644
index 0000000..244e51bf
--- /dev/null
+++ b/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
@@ -0,0 +1,213 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/exo/wayland/zcr_remote_shell_impl.h"
+
+#include <wayland-server-core.h>
+#include <wayland-server.h>
+
+#include <memory>
+
+#include "ash/shell.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "base/bind.h"
+#include "base/posix/unix_domain_socket.h"
+#include "components/exo/display.h"
+#include "components/exo/test/exo_test_base.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/views/widget/widget.h"
+
+namespace exo {
+namespace wayland {
+namespace {
+
+struct WlDisplayDeleter {
+  void operator()(wl_display* ptr) const { wl_display_destroy(ptr); }
+};
+using ScopedWlDisplay = std::unique_ptr<wl_display, WlDisplayDeleter>;
+
+struct WlClientDeleter {
+  void operator()(wl_client* ptr) const { wl_client_destroy(ptr); }
+};
+using ScopedWlClient = std::unique_ptr<wl_client, WlClientDeleter>;
+
+struct WlResourceDeleter {
+  void operator()(wl_resource* ptr) const { wl_resource_destroy(ptr); }
+};
+using ScopedWlResource = std::unique_ptr<wl_resource, WlResourceDeleter>;
+
+}  // namespace
+
+class WaylandRemoteShellTest : public test::ExoTestBase {
+ public:
+  WaylandRemoteShellTest()
+      : test::ExoTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+  WaylandRemoteShellTest(const WaylandRemoteShellTest&) = delete;
+  WaylandRemoteShellTest& operator=(const WaylandRemoteShellTest&) = delete;
+
+  // test::ExoTestBase:
+  void SetUp() override {
+    test::ExoTestBase::SetUp();
+
+    ResetCounter();
+
+    UpdateDisplay("800x600");
+
+    base::CreateSocketPair(&reader_, &writer_);
+
+    wl_display_.reset(wl_display_create());
+    wl_client_.reset(wl_client_create(wl_display_.get(), reader_.release()));
+    wl_shell_resource_.reset(wl_resource_create(
+        wl_client_.get(), &zcr_remote_shell_v2_interface, 1, 1));
+
+    display_ = std::make_unique<Display>();
+    shell_ = std::make_unique<WaylandRemoteShell>(
+        display_.get(), wl_shell_resource_.get(),
+        base::BindRepeating(
+            [](int64_t) { return static_cast<wl_resource*>(nullptr); }),
+        test_event_mapping_,
+        /*use_default_scale_cancellation_default=*/true);
+  }
+  void TearDown() override {
+    shell_.reset();
+    display_.reset();
+
+    test::ExoTestBase::TearDown();
+  }
+
+  void EnableTabletMode(bool enable) {
+    ash::Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enable);
+  }
+
+  void ResetCounter() { send_bounds_changed_counter_ = 0; }
+
+  WaylandRemoteShell* shell() { return shell_.get(); }
+
+  wl_client* wl_client() { return wl_client_.get(); }
+
+  static int send_bounds_changed_counter() {
+    return send_bounds_changed_counter_;
+  }
+
+ private:
+  std::unique_ptr<Display> display_;
+
+  base::ScopedFD reader_, writer_;
+  ScopedWlDisplay wl_display_;
+  ScopedWlClient wl_client_;
+  ScopedWlResource wl_shell_resource_;
+
+  std::unique_ptr<WaylandRemoteShell> shell_;
+
+  static int send_bounds_changed_counter_;
+
+  const WaylandRemoteShellEventMapping test_event_mapping_ = {
+      /*send_window_geometry_changed=*/+[](struct wl_resource*,
+                                           int32_t,
+                                           int32_t,
+                                           int32_t,
+                                           int32_t) {},
+      /*send_change_zoom_level=*/+[](struct wl_resource*, int32_t) {},
+      /*send_state_type_changed=*/+[](struct wl_resource*, uint32_t) {},
+      /*send_bounds_changed_in_output=*/
+      +[](struct wl_resource*,
+          struct wl_resource*,
+          int32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          uint32_t) {},
+      /*send_bounds_changed=*/
+      +[](struct wl_resource*,
+          uint32_t,
+          uint32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          uint32_t) { send_bounds_changed_counter_++; },
+      /*send_activated=*/
+      +[](struct wl_resource*, struct wl_resource*, struct wl_resource*) {},
+      /*send_desktop_focus_state_changed=*/
+      +[](struct wl_resource*, uint32_t) {},
+      /*send_workspace_info=*/
+      +[](struct wl_resource*,
+          uint32_t,
+          uint32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          int32_t,
+          uint32_t,
+          struct wl_array*) {},
+      /*send_drag_finished=*/
+      +[](struct wl_resource*, int32_t, int32_t, int32_t) {},
+      /*send_drag_started=*/+[](struct wl_resource*, uint32_t) {},
+      /*send_layout_mode=*/+[](struct wl_resource*, uint32_t) {},
+      /*send_default_device_scale_factor=*/+[](struct wl_resource*, int32_t) {},
+      /*send_configure=*/+[](struct wl_resource*, uint32_t) {},
+      /*bounds_changed_in_output_since_version=*/0,
+      /*desktop_focus_state_changed_since_version=*/0,
+      /*layout_mode_since_version=*/0,
+      /*default_device_scale_factor_since_version=*/0,
+      /*change_zoom_level_since_version=*/0,
+      /*send_workspace_info_since_version=*/0,
+      /*send_bounds_changed_since_version=*/0,
+      /*set_use_default_scale_cancellation_since_version=*/0,
+  };
+};
+
+int WaylandRemoteShellTest::send_bounds_changed_counter_ = 0;
+
+// Test that all bounds change requests are deferred while the tablet transition
+// is happening until it's finished.
+TEST_F(WaylandRemoteShellTest, DeferBoundsChangeWhileTabletTransition) {
+  // Setup buffer/surface/window.
+  const gfx::Size buffer_size(256, 256);
+  std::unique_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+
+  std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface =
+      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+
+  ScopedWlResource wl_res(
+      wl_resource_create(wl_client(), &zcr_remote_surface_v2_interface, 1, 1));
+  shell_surface->set_delegate(
+      shell()->CreateShellSurfaceDelegate(wl_res.get()));
+
+  surface->Attach(buffer.get());
+  surface->Commit();
+  auto* const widget = shell_surface->GetWidget();
+  auto* const window = widget->GetNativeWindow();
+
+  // Snap window.
+  ash::WMEvent event(ash::WM_EVENT_SNAP_PRIMARY);
+  ash::WindowState::Get(window)->OnWMEvent(&event);
+  shell_surface->SetSnappedToPrimary();
+  shell_surface->SetGeometry(gfx::Rect(0, 0, 400, 520));
+  surface->Commit();
+
+  // Enable tablet mode.
+  ResetCounter();
+  EnableTabletMode(true);
+  task_environment()->FastForwardBy(base::Seconds(1));
+  task_environment()->RunUntilIdle();
+
+  EXPECT_EQ(send_bounds_changed_counter(), 1);
+}
+
+}  // namespace wayland
+}  // namespace exo
diff --git a/components/feature_engagement/public/tracker.h b/components/feature_engagement/public/tracker.h
index f30837f..18e423e 100644
--- a/components/feature_engagement/public/tracker.h
+++ b/components/feature_engagement/public/tracker.h
@@ -64,6 +64,9 @@
   };
 
   // Represents the action taken by the user on the snooze UI.
+  // These enums are persisted as histogram entries, so this enum should be
+  // treated as append-only and kept in sync with InProductHelpSnoozeAction in
+  // enums.xml.
   // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.feature_engagement
   enum class SnoozeAction : int {
     // User chose to snooze the IPH.
diff --git a/components/gcm_driver/android/BUILD.gn b/components/gcm_driver/android/BUILD.gn
index 6d43304..f7de29aa 100644
--- a/components/gcm_driver/android/BUILD.gn
+++ b/components/gcm_driver/android/BUILD.gn
@@ -11,7 +11,6 @@
 android_library("gcm_driver_java") {
   deps = [
     "//base:base_java",
-    "//content/public/android:content_java",
     "//third_party/android_deps:com_google_code_findbugs_jsr305_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
   ]
diff --git a/components/history/core/browser/visitsegment_database.cc b/components/history/core/browser/visitsegment_database.cc
index d9ddf14..01f5ef8 100644
--- a/components/history/core/browser/visitsegment_database.cc
+++ b/components/history/core/browser/visitsegment_database.cc
@@ -104,15 +104,14 @@
   // TODO(brettw) this should probably use the registry controlled
   // domains service.
   GURL::Replacements r;
-  std::string host = url.host();
+  base::StringPiece host = url.host_piece();
 
   // Strip various common prefixes in order to group the resulting hostnames
   // together and avoid duplicates.
   for (base::StringPiece prefix : {"www.", "m.", "mobile.", "touch."}) {
     if (host.size() > prefix.size() &&
         base::StartsWith(host, prefix, base::CompareCase::INSENSITIVE_ASCII)) {
-      r.SetHost(host.c_str(),
-                url::Component(prefix.size(), host.size() - prefix.size()));
+      r.SetHostStr(host.substr(prefix.size()));
       break;
     }
   }
diff --git a/components/history_clusters/core/history_clusters_service.cc b/components/history_clusters/core/history_clusters_service.cc
index 7c401048..73af7ec7 100644
--- a/components/history_clusters/core/history_clusters_service.cc
+++ b/components/history_clusters/core/history_clusters_service.cc
@@ -22,6 +22,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
+#include "base/task/thread_pool.h"
 #include "base/time/time.h"
 #include "base/time/time_to_iso8601.h"
 #include "base/timer/elapsed_timer.h"
@@ -32,6 +33,7 @@
 #include "components/history/core/browser/history_types.h"
 #include "components/history_clusters/core/history_clusters_buildflags.h"
 #include "components/history_clusters/core/history_clusters_db_tasks.h"
+#include "components/history_clusters/core/history_clusters_types.h"
 #include "components/history_clusters/core/memories_features.h"
 #include "components/history_clusters/core/remote_clustering_backend.h"
 #include "components/optimization_guide/core/entity_metadata_provider.h"
@@ -284,7 +286,10 @@
     TemplateURLService* template_url_service,
     optimization_guide::EntityMetadataProvider* entity_metadata_provider,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
-    : history_service_(history_service), visit_deletion_observer_(this) {
+    : history_service_(history_service),
+      visit_deletion_observer_(this),
+      post_processing_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::TaskPriority::USER_VISIBLE})) {
   DCHECK(history_service_);
 
   visit_deletion_observer_.AttachToHistoryService(history_service);
@@ -485,6 +490,11 @@
         &cache_query_task_tracker_);
   }
 
+  // Early exit for single-character queries, even if it's an exact match.
+  // We still want to allow for two-character exact matches like "uk".
+  if (query.length() <= 1)
+    return false;
+
   query_parser::QueryNodeVector query_nodes;
   query_parser::QueryParser::ParseQueryNodes(
       base::UTF8ToUTF16(query), query_parser::MatchingAlgorithm::DEFAULT,
@@ -498,8 +508,9 @@
                                                    /*exact=*/true);
 }
 
+// static
 std::vector<Cluster> HistoryClustersService::CollapseDuplicateVisits(
-    const std::vector<history::Cluster>& raw_clusters) const {
+    const std::vector<history::Cluster>& raw_clusters) {
   std::vector<Cluster> result_clusters;
   for (const auto& raw_cluster : raw_clusters) {
     Cluster cluster;
@@ -528,18 +539,14 @@
       for (auto& duplicate_id : raw_visit.duplicate_visit_ids) {
         auto duplicate_visit = visits_map.find(duplicate_id);
         if (duplicate_visit == visits_map.end()) {
-          NotifyDebugMessage(
-              base::StringPrintf("Visit id=%d has missing duplicate_id=%d",
-                                 int(visit_id), int(duplicate_id)));
+          NOTREACHED() << "Visit has missing duplicate ID.";
           continue;
         }
 
         // Move the duplicate visit into the vector of the canonical visit.
-        if (!duplicate_visit->second.duplicate_visits.empty()) {
-          NotifyDebugMessage(
-              "Duplicates shouldn't themselves have duplicates. "
-              "If they do, the output is undefined.");
-        }
+        DCHECK(duplicate_visit->second.duplicate_visits.empty())
+            << "Duplicates shouldn't themselves have duplicates. "
+               "If they do, the output is undefined.";
         auto& canonical_visit = visits_map[visit_id];
         canonical_visit.duplicate_visits.push_back(
             std::move(duplicate_visit->second));
@@ -645,41 +652,71 @@
                                static_cast<int>(annotated_visits.size()));
 
   backend_->GetClusters(
-      base::BindOnce(&HistoryClustersService::OnGotClusters,
+      base::BindOnce(&HistoryClustersService::OnGotRawClusters,
                      weak_ptr_factory_.GetWeakPtr(), query,
                      continuation_end_time, base::TimeTicks::Now(),
                      std::move(callback)),
       annotated_visits);
 }
 
-void HistoryClustersService::OnGotClusters(
+void HistoryClustersService::OnGotRawClusters(
     const std::string& query,
     base::Time continuation_end_time,
     base::TimeTicks cluster_start_time,
     QueryClustersCallback callback,
     std::vector<history::Cluster> clusters) const {
-  NotifyDebugMessage("HistoryClustersService::OnGotClusters()");
+  NotifyDebugMessage("HistoryClustersService::OnGotRawClusters()");
+
+  int clusters_from_backend_count = clusters.size();
+  base::UmaHistogramTimes("History.Clusters.Backend.GetClustersLatency",
+                          base::TimeTicks::Now() - cluster_start_time);
+  base::UmaHistogramCounts1000("History.Clusters.Backend.NumClustersReturned",
+                               clusters_from_backend_count);
+
+  NotifyDebugMessage("  Raw Clusters from Backend JSON follows:");
+  NotifyDebugMessage(GetDebugJSONForClusters(clusters));
+
+  // Post-process the clusters (expensive task) on an anonymous thread to
+  // prevent janks.
+  base::ElapsedTimer post_processing_timer;  // Create here to time the task.
+  post_processing_task_runner_->PostTaskAndReplyWithResult(
+      FROM_HERE,
+      base::BindOnce(&HistoryClustersService::PostProcessClusters, query,
+                     continuation_end_time, std::move(clusters)),
+      base::BindOnce(&HistoryClustersService::OnProcessedClusters,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(post_processing_timer),
+                     clusters_from_backend_count, std::move(callback)));
+}
+
+// static
+QueryClustersResult HistoryClustersService::PostProcessClusters(
+    const std::string& query,
+    base::Time continuation_end_time,
+    std::vector<history::Cluster> raw_clusters) {
   QueryClustersResult result;
   if (!continuation_end_time.is_null()) {
     result.continuation_end_time = continuation_end_time;
   }
 
-  int clusters_from_backend_count = clusters.size();
-  base::UmaHistogramTimes("History.Clusters.Backend.GetClustersLatency",
-                          base::TimeTicks::Now() - cluster_start_time);
-
-  base::ElapsedTimer timer;
-  FilterClustersMatchingQuery(query, &clusters);
-  result.clusters = CollapseDuplicateVisits(clusters);
+  FilterClustersMatchingQuery(query, &raw_clusters);
+  result.clusters = CollapseDuplicateVisits(raw_clusters);
   SortClusters(&result.clusters);
 
-  base::TimeDelta clustering_duration = timer.Elapsed();
+  return result;
+}
+
+void HistoryClustersService::OnProcessedClusters(
+    base::ElapsedTimer post_processing_timer,
+    size_t clusters_from_backend_count,
+    QueryClustersCallback callback,
+    QueryClustersResult result) const {
+  NotifyDebugMessage("HistoryClustersService::OnProcesedClusters()");
+
+  base::TimeDelta clustering_duration = post_processing_timer.Elapsed();
   base::UmaHistogramLongTimes("History.Clusters.ProcessClustersDuration",
                               clustering_duration);
 
-  base::UmaHistogramCounts1000("History.Clusters.Backend.NumClustersReturned",
-                               clusters_from_backend_count);
-
   if (clusters_from_backend_count > 0) {
     // Log the percentage of clusters that get filtered (e.g., 100 - % of
     // clusters that remain).
@@ -689,9 +726,6 @@
                                 (1.0 * clusters_from_backend_count) * 100)));
   }
 
-  NotifyDebugMessage("  Clusters JSON follows:");
-  NotifyDebugMessage(GetDebugJSONForClusters(clusters));
-
   NotifyDebugMessage("  Passing results back to original caller now.");
   std::move(callback).Run(std::move(result));
 }
diff --git a/components/history_clusters/core/history_clusters_service.h b/components/history_clusters/core/history_clusters_service.h
index b50c10a..24c1da1 100644
--- a/components/history_clusters/core/history_clusters_service.h
+++ b/components/history_clusters/core/history_clusters_service.h
@@ -17,7 +17,9 @@
 #include "base/observer_list.h"
 #include "base/scoped_observation.h"
 #include "base/task/cancelable_task_tracker.h"
+#include "base/task/sequenced_task_runner.h"
 #include "base/time/time.h"
+#include "base/timer/elapsed_timer.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"
@@ -147,9 +149,9 @@
 
   // Converts the vector of history::Cluster types to history_clusters::Cluster
   // by collapsing all the duplicate visits into the canonical visits, thereby
-  // "unflattening" the output of the backend. Exposed for testing.
-  std::vector<Cluster> CollapseDuplicateVisits(
-      const std::vector<history::Cluster>& raw_clusters) const;
+  // "unflattening" the output of the backend. Public for testing purposes.
+  static std::vector<Cluster> CollapseDuplicateVisits(
+      const std::vector<history::Cluster>& raw_clusters);
 
   // Clears `all_keywords_cache_` and cancels any pending tasks to populate it.
   void ClearKeywordCache();
@@ -173,12 +175,24 @@
                           std::vector<history::AnnotatedVisit> annotated_visits,
                           base::Time continuation_end_time) const;
 
-  // Internally used callback for `OnGotHistoryVisits()`.
-  void OnGotClusters(const std::string& query,
-                     base::Time continuation_end_time,
-                     base::TimeTicks cluster_start_time,
-                     QueryClustersCallback callback,
-                     std::vector<history::Cluster> clusters) const;
+  // Runs on UI thread. Internally used callback for `OnGotHistoryVisits()`.
+  void OnGotRawClusters(const std::string& query,
+                        base::Time continuation_end_time,
+                        base::TimeTicks cluster_start_time,
+                        QueryClustersCallback callback,
+                        std::vector<history::Cluster> clusters) const;
+
+  // Runs on `post_processing_task_runner_`, posted by `OnGotRawClusters()`.
+  static QueryClustersResult PostProcessClusters(
+      const std::string& query,
+      base::Time continuation_end_time,
+      std::vector<history::Cluster> clusters);
+
+  // Runs on UI thread. Used as the 'reply' part from `PostProcessClusters()`.
+  void OnProcessedClusters(base::ElapsedTimer post_processing_timer,
+                           size_t clusters_from_backend_count,
+                           QueryClustersCallback callback,
+                           QueryClustersResult result) const;
 
   // `VisitContextAnnotations`s are constructed stepwise; they're initially
   // placed in `incomplete_visit_context_annotations_` and saved to the history
@@ -218,6 +232,9 @@
 
   VisitDeletionObserver visit_deletion_observer_;
 
+  // A task runner to run all the post-processing tasks on.
+  scoped_refptr<base::SequencedTaskRunner> post_processing_task_runner_;
+
   // Weak pointers issued from this factory never get invalidated before the
   // service is destroyed.
   base::WeakPtrFactory<HistoryClustersService> weak_ptr_factory_{this};
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 19370d62..4209c68 100644
--- a/components/history_clusters/core/history_clusters_service_test_api.h
+++ b/components/history_clusters/core/history_clusters_service_test_api.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/time/time.h"
 #include "components/history/core/browser/history_service.h"
@@ -57,6 +58,13 @@
     history_clusters_service_->short_keyword_cache_timestamp_ = time;
   }
 
+  void FlushPostProcessingTaskRunner() {
+    base::RunLoop loop;
+    history_clusters_service_->post_processing_task_runner_->PostTask(
+        FROM_HERE, loop.QuitClosure());
+    loop.Run();
+  }
+
   HistoryClustersService* const history_clusters_service_;
   history::HistoryService* const 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 32fd1ff..1ba1ffca 100644
--- a/components/history_clusters/core/history_clusters_service_unittest.cc
+++ b/components/history_clusters/core/history_clusters_service_unittest.cc
@@ -785,7 +785,7 @@
                            test_clustering_backend_->GetVisitById(1),
                            test_clustering_backend_->GetVisitById(2),
                        },
-                       {u"apples", u"oranges"},
+                       {u"apples", u"oranges", u"z"},
                        /*should_show_on_prominent_ui_surfaces=*/true));
   clusters.push_back(
       history::Cluster(0,
@@ -803,6 +803,7 @@
                        {u"singlevisit"},
                        /*should_show_on_prominent_ui_surfaces=*/true));
   test_clustering_backend_->FulfillCallback(clusters);
+  history_clusters_service_test_api_->FlushPostProcessingTaskRunner();
 
   // Now the exact query should match the populated cache.
   EXPECT_TRUE(history_clusters_service_->DoesQueryMatchAnyCluster("apples"));
@@ -816,9 +817,12 @@
   EXPECT_FALSE(
       history_clusters_service_->DoesQueryMatchAnyCluster("singlevisit"));
 
-  // Too-short queries rejected.
+  // Too-short prefix queries rejected.
   EXPECT_FALSE(history_clusters_service_->DoesQueryMatchAnyCluster("ap"));
 
+  // Single character exact queries are also rejected.
+  EXPECT_FALSE(history_clusters_service_->DoesQueryMatchAnyCluster("z"));
+
   // Non-exact matches are rejected too.
   EXPECT_FALSE(history_clusters_service_->DoesQueryMatchAnyCluster("appl"));
 
@@ -838,6 +842,7 @@
   // The keyword cache should be repopulated.
   test_clustering_backend_->WaitForGetClustersCall();
   test_clustering_backend_->FulfillCallback(clusters);
+  history_clusters_service_test_api_->FlushPostProcessingTaskRunner();
   EXPECT_TRUE(history_clusters_service_->DoesQueryMatchAnyCluster("apples"));
   history::BlockUntilHistoryProcessesPendingRequests(history_service_.get());
 }
@@ -881,6 +886,7 @@
                        {u"peach", u""},
                        /*should_show_on_prominent_ui_surfaces=*/true));
   test_clustering_backend_->FulfillCallback(clusters2);
+  history_clusters_service_test_api_->FlushPostProcessingTaskRunner();
   EXPECT_TRUE(history_clusters_service_->DoesQueryMatchAnyCluster("peach"));
 
   history::BlockUntilHistoryProcessesPendingRequests(history_service_.get());
diff --git a/components/minidump_uploader/BUILD.gn b/components/minidump_uploader/BUILD.gn
index 485e31e..c6ae7a3 100644
--- a/components/minidump_uploader/BUILD.gn
+++ b/components/minidump_uploader/BUILD.gn
@@ -21,6 +21,7 @@
     "//third_party/crashpad/crashpad/handler",
     "//third_party/crashpad/crashpad/snapshot",
     "//third_party/crashpad/crashpad/util",
+    "//third_party/crashpad/crashpad/util:net",
   ]
 }
 
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index a1b5fa3..0475ad1 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -721,7 +721,14 @@
 bool AutocompleteMatch::IsActionCompatibleType(Type type) {
   // Note: There is a PEDAL type, but it is deprecated because Pedals always
   // attach to matches of other types instead of creating dedicated matches.
-  return type != AutocompleteMatchType::SEARCH_SUGGEST_ENTITY;
+  return type != AutocompleteMatchType::SEARCH_SUGGEST_ENTITY &&
+         // Attaching to Tail Suggest types looks weird, and is actually
+         // technically wrong because the Pedals annotator (and history clusters
+         // annotator) both use match.contents. If we do want to turn on Actions
+         // for tail suggest in the future, we should switch to using
+         // match.fill_into_edit or maybe page title for URL matches, and come
+         // up with a UI design for the button in the tail suggest layout.
+         type != AutocompleteMatchType::SEARCH_SUGGEST_TAIL;
 }
 
 // static
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
index d9a8685..c3a0021 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
@@ -146,13 +146,12 @@
      * @param publisher                The name of the content publisher, if any.
      * @param delegate                 The PageInfoControllerDelegate used to provide
      *                                 embedder-specific info.
-     * @param highlightedPermission    The ContentSettingsType to be highlighted on this page or
-     *                                 NO_HIGHLIGHTED_PERMISSION for no highlight.
+     * @param pageInfoHighlight        Providing the highlight row info related to this dialog.
      */
     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
     public PageInfoController(WebContents webContents, @ConnectionSecurityLevel int securityLevel,
             String publisher, PageInfoControllerDelegate delegate,
-            @ContentSettingsType int highlightedPermission) {
+            PageInfoHighlight pageInfoHighlight) {
         mWebContents = webContents;
         mSecurityLevel = securityLevel;
         mDelegate = delegate;
@@ -257,8 +256,9 @@
         // Create Subcontrollers.
         mConnectionController = new PageInfoConnectionController(this, mView.getConnectionRowView(),
                 mWebContents, mDelegate, publisher, mIsInternalPage);
-        mPermissionsController = new PageInfoPermissionsController(
-                this, mView.getPermissionsRowView(), mDelegate, highlightedPermission);
+        mPermissionsController =
+                new PageInfoPermissionsController(this, mView.getPermissionsRowView(), mDelegate,
+                        pageInfoHighlight.getHighlightedPermission());
         mCookiesController =
                 new PageInfoCookiesController(this, mView.getCookiesRowView(), mDelegate);
 
@@ -506,13 +506,11 @@
      * @param contentPublisher The name of the publisher of the content.
      * @param source Determines the source that triggered the popup.
      * @param delegate The PageInfoControllerDelegate used to provide embedder-specific info.
-     * @param highlightedPermission The ContentSettingsType to be highlighted on this page or
-     *            NO_HIGHLIGHTED_PERMISSION for no highlight.
+     * @param pageInfoHighlight Providing the highlight row info related to this dialog.
      */
     public static void show(final Activity activity, WebContents webContents,
             final String contentPublisher, @OpenedFromSource int source,
-            PageInfoControllerDelegate delegate,
-            @ContentSettingsType int highlightedPermission) {
+            PageInfoControllerDelegate delegate, PageInfoHighlight pageInfoHighlight) {
         // Don't show the dialog if this tab doesn't have an activity. See https://crbug.com/1267383
         if (activity == null) return;
         // If the activity's decor view is not attached to window, we don't show the dialog because
@@ -533,7 +531,7 @@
 
         sLastPageInfoControllerForTesting = new WeakReference<>(new PageInfoController(webContents,
                 SecurityStateModel.getSecurityLevelForWebContents(webContents), contentPublisher,
-                delegate, highlightedPermission));
+                delegate, pageInfoHighlight));
     }
 
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
diff --git a/components/password_manager/core/browser/fake_password_store_backend.cc b/components/password_manager/core/browser/fake_password_store_backend.cc
index f024acf..6cad99d7 100644
--- a/components/password_manager/core/browser/fake_password_store_backend.cc
+++ b/components/password_manager/core/browser/fake_password_store_backend.cc
@@ -127,11 +127,6 @@
   return nullptr;
 }
 
-void FakePasswordStoreBackend::GetSyncStatus(
-    base::OnceCallback<void(bool)> callback) {
-  NOTIMPLEMENTED();
-}
-
 LoginsResult FakePasswordStoreBackend::GetAllLoginsInternal() {
   LoginsResult result;
   for (const auto& elements : stored_passwords_) {
diff --git a/components/password_manager/core/browser/fake_password_store_backend.h b/components/password_manager/core/browser/fake_password_store_backend.h
index 7e3a53ac..0957d6ae 100644
--- a/components/password_manager/core/browser/fake_password_store_backend.h
+++ b/components/password_manager/core/browser/fake_password_store_backend.h
@@ -63,7 +63,6 @@
   FieldInfoStore* GetFieldInfoStore() override;
   std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() override;
-  void GetSyncStatus(base::OnceCallback<void(bool)> callback) override;
 
   LoginsResult GetAllLoginsInternal();
   LoginsResult GetAutofillableLoginsInternal();
diff --git a/components/password_manager/core/browser/mock_password_store_backend.h b/components/password_manager/core/browser/mock_password_store_backend.h
index 7245dd8..0f4d1dc 100644
--- a/components/password_manager/core/browser/mock_password_store_backend.h
+++ b/components/password_manager/core/browser/mock_password_store_backend.h
@@ -87,10 +87,6 @@
               CreateSyncControllerDelegate,
               (),
               (override));
-  MOCK_METHOD(void,
-              GetSyncStatus,
-              (base::OnceCallback<void(bool)>),
-              (override));
 
  private:
   base::WeakPtrFactory<MockPasswordStoreBackend> weak_ptr_factory_{this};
diff --git a/components/password_manager/core/browser/password_store_backend.h b/components/password_manager/core/browser/password_store_backend.h
index 3b4cd7b3..54a3e61 100644
--- a/components/password_manager/core/browser/password_store_backend.h
+++ b/components/password_manager/core/browser/password_store_backend.h
@@ -128,10 +128,6 @@
   virtual std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() = 0;
 
-  // Tells whether backend is actively syncing data. Callback is called on a
-  // main sequence.
-  virtual void GetSyncStatus(base::OnceCallback<void(bool)> callback) = 0;
-
   // Factory function for creating the backend. The Local backend requires the
   // provided `login_db` for storage and Android backend for migration purposes.
   static std::unique_ptr<PasswordStoreBackend> Create(
diff --git a/components/password_manager/core/browser/password_store_backend_migration_decorator.cc b/components/password_manager/core/browser/password_store_backend_migration_decorator.cc
index 25fa93d..ff6ec7b74 100644
--- a/components/password_manager/core/browser/password_store_backend_migration_decorator.cc
+++ b/components/password_manager/core/browser/password_store_backend_migration_decorator.cc
@@ -34,7 +34,8 @@
   DCHECK(built_in_backend_);
   DCHECK(android_backend_);
   active_backend_ = std::make_unique<PasswordStoreProxyBackend>(
-      built_in_backend_.get(), android_backend_.get());
+      built_in_backend_.get(), android_backend_.get(),
+      is_syncing_passwords_callback_);
 }
 
 PasswordStoreBackendMigrationDecorator::
@@ -159,11 +160,6 @@
   return active_backend_->CreateSyncControllerDelegate();
 }
 
-void PasswordStoreBackendMigrationDecorator::GetSyncStatus(
-    base::OnceCallback<void(bool)> callback) {
-  return active_backend_->GetSyncStatus(std::move(callback));
-}
-
 void PasswordStoreBackendMigrationDecorator::StartMigration() {
   migrator_ = std::make_unique<BuiltInBackendToAndroidBackendMigrator>(
       built_in_backend_.get(), android_backend_.get(), prefs_,
diff --git a/components/password_manager/core/browser/password_store_backend_migration_decorator.h b/components/password_manager/core/browser/password_store_backend_migration_decorator.h
index b47cdee..2b147b9 100644
--- a/components/password_manager/core/browser/password_store_backend_migration_decorator.h
+++ b/components/password_manager/core/browser/password_store_backend_migration_decorator.h
@@ -76,7 +76,6 @@
   FieldInfoStore* GetFieldInfoStore() override;
   std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() override;
-  void GetSyncStatus(base::OnceCallback<void(bool)> callback) override;
 
   // Creates 'migrator_' and starts migration process.
   void StartMigration();
diff --git a/components/password_manager/core/browser/password_store_built_in_backend.cc b/components/password_manager/core/browser/password_store_built_in_backend.cc
index 68022af..72d0f94a 100644
--- a/components/password_manager/core/browser/password_store_built_in_backend.cc
+++ b/components/password_manager/core/browser/password_store_built_in_backend.cc
@@ -439,17 +439,6 @@
           weak_ptr_factory_.GetWeakPtr()));
 }
 
-void PasswordStoreBuiltInBackend::GetSyncStatus(
-    base::OnceCallback<void(bool)> callback) {
-  DCHECK(!was_shutdown_);
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  background_task_runner_->PostTaskAndReplyWithResult(
-      FROM_HERE,
-      base::BindOnce(&PasswordStoreBuiltInBackend::IsSyncEnabled,
-                     base::Unretained(this)),  // Safe until `Shutdown()`.
-      std::move(callback));
-}
-
 void PasswordStoreBuiltInBackend::AddSiteStats(const InteractionsStats& stats) {
   DCHECK(!was_shutdown_);
   DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
@@ -754,11 +743,4 @@
     login_db_->field_info_table().RemoveRowsByTime(remove_begin, remove_end);
 }
 
-bool PasswordStoreBuiltInBackend::IsSyncEnabled() const {
-  DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
-  if (!sync_bridge_ || !sync_bridge_->change_processor())
-    return false;
-  return sync_bridge_->change_processor()->IsTrackingMetadata();
-}
-
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_built_in_backend.h b/components/password_manager/core/browser/password_store_built_in_backend.h
index bbd543f..b9094d3 100644
--- a/components/password_manager/core/browser/password_store_built_in_backend.h
+++ b/components/password_manager/core/browser/password_store_built_in_backend.h
@@ -113,7 +113,6 @@
   FieldInfoStore* GetFieldInfoStore() override;
   std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() override;
-  void GetSyncStatus(base::OnceCallback<void(bool)> callback) override;
 
   // SmartBubbleStatsStore:
   void AddSiteStats(const InteractionsStats& stats) override;
@@ -190,8 +189,6 @@
   // and bubble statistics.
   void ReportMetrics();
 
-  bool IsSyncEnabled() const;
-
   // Used to trigger DCHECKs if tasks are posted after shut down.
   bool was_shutdown_{false};
 
diff --git a/components/password_manager/core/browser/password_store_proxy_backend.cc b/components/password_manager/core/browser/password_store_proxy_backend.cc
index 67b324c..5f696ee0 100644
--- a/components/password_manager/core/browser/password_store_proxy_backend.cc
+++ b/components/password_manager/core/browser/password_store_proxy_backend.cc
@@ -131,20 +131,16 @@
   absl::optional<LoginsResult> first_result_;
 };
 
-void InvokeCallbackIfShadowingAllowed(base::OnceClosure callback,
-                                      bool sync_enabled) {
-  if (sync_enabled && base::FeatureList::IsEnabled(
-                          features::kUnifiedPasswordManagerShadowAndroid)) {
-    std::move(callback).Run();
-  }
-}
-
 }  // namespace
 
 PasswordStoreProxyBackend::PasswordStoreProxyBackend(
     PasswordStoreBackend* main_backend,
-    PasswordStoreBackend* shadow_backend)
-    : main_backend_(main_backend), shadow_backend_(shadow_backend) {}
+    PasswordStoreBackend* shadow_backend,
+    base::RepeatingCallback<bool()> is_syncing_passwords_callback)
+    : main_backend_(main_backend),
+      shadow_backend_(shadow_backend),
+      is_syncing_passwords_callback_(std::move(is_syncing_passwords_callback)) {
+}
 
 PasswordStoreProxyBackend::~PasswordStoreProxyBackend() = default;
 
@@ -183,13 +179,12 @@
                      handler)
           .Then(std::move(callback)));
 
-  auto sync_status_callback = base::BindOnce(
-      &PasswordStoreBackend::GetAllLoginsAsync, shadow_backend_->GetWeakPtr(),
-      base::BindOnce(&GetAllLoginsAsyncMetricsRecorder::RecordShadowResult,
-                     handler));
-
-  GetSyncStatus(base::BindOnce(&InvokeCallbackIfShadowingAllowed,
-                               std::move(sync_status_callback)));
+  if (is_syncing_passwords_callback_.Run() &&
+      base::FeatureList::IsEnabled(
+          features::kUnifiedPasswordManagerShadowAndroid)) {
+    shadow_backend_->GetAllLoginsAsync(base::BindOnce(
+        &GetAllLoginsAsyncMetricsRecorder::RecordShadowResult, handler));
+  }
 }
 
 void PasswordStoreProxyBackend::GetAutofillableLoginsAsync(
@@ -278,9 +273,4 @@
   return main_backend_->CreateSyncControllerDelegate();
 }
 
-void PasswordStoreProxyBackend::GetSyncStatus(
-    base::OnceCallback<void(bool)> callback) {
-  return main_backend_->GetSyncStatus(std::move(callback));
-}
-
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_proxy_backend.h b/components/password_manager/core/browser/password_store_proxy_backend.h
index 7bb3f05..9aca716 100644
--- a/components/password_manager/core/browser/password_store_proxy_backend.h
+++ b/components/password_manager/core/browser/password_store_proxy_backend.h
@@ -20,8 +20,10 @@
  public:
   // `main_backend` and `shadow_backend` must not be null and must outlive this
   // object as long as Shutdown() is not called.
-  PasswordStoreProxyBackend(PasswordStoreBackend* main_backend,
-                            PasswordStoreBackend* shadow_backend);
+  PasswordStoreProxyBackend(
+      PasswordStoreBackend* main_backend,
+      PasswordStoreBackend* shadow_backend,
+      base::RepeatingCallback<bool()> is_syncing_passwords_callback);
   PasswordStoreProxyBackend(const PasswordStoreProxyBackend&) = delete;
   PasswordStoreProxyBackend(PasswordStoreProxyBackend&&) = delete;
   PasswordStoreProxyBackend& operator=(const PasswordStoreProxyBackend&) =
@@ -66,10 +68,9 @@
   std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() override;
 
-  void GetSyncStatus(base::OnceCallback<void(bool)> callback) override;
-
   PasswordStoreBackend* const main_backend_;
   PasswordStoreBackend* const shadow_backend_;
+  base::RepeatingCallback<bool()> is_syncing_passwords_callback_;
   base::WeakPtrFactory<PasswordStoreProxyBackend> weak_ptr_factory_{this};
 };
 
diff --git a/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc b/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc
index 497df3a..1cf66e2a 100644
--- a/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc
+++ b/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc
@@ -30,6 +30,7 @@
 using ::testing::Eq;
 using ::testing::Invoke;
 using ::testing::Pointer;
+using ::testing::Return;
 using ::testing::StrictMock;
 using ::testing::WithArg;
 using Type = PasswordStoreChange::Type;
@@ -67,7 +68,7 @@
  protected:
   PasswordStoreProxyBackendTest() {
     proxy_backend_ = std::make_unique<PasswordStoreProxyBackend>(
-        &main_backend_, &shadow_backend_);
+        &main_backend_, &shadow_backend_, is_syncing_passwords_callback_.Get());
 
     feature_list_.InitAndEnableFeature(
         features::kUnifiedPasswordManagerShadowAndroid);
@@ -85,6 +86,9 @@
   MockPasswordStoreBackend& main_backend() { return main_backend_; }
   MockPasswordStoreBackend& shadow_backend() { return shadow_backend_; }
 
+  base::MockCallback<base::RepeatingCallback<bool(void)>>
+      is_syncing_passwords_callback_;
+
  private:
   base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<PasswordStoreProxyBackend> proxy_backend_;
@@ -140,9 +144,7 @@
       .WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
         std::move(reply).Run(CreateTestLogins());
       })));
-  EXPECT_CALL(main_backend(), GetSyncStatus)
-      .WillOnce(WithArg<0>(
-          Invoke([](auto callback) { std::move(callback).Run(true); })));
+  EXPECT_CALL(is_syncing_passwords_callback_, Run).WillRepeatedly(Return(true));
   EXPECT_CALL(shadow_backend(), GetAllLoginsAsync)
       .WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
         std::move(reply).Run(CreateTestLogins());
@@ -296,9 +298,8 @@
       .WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
         std::move(reply).Run(CreateTestLogins());
       })));
-  EXPECT_CALL(main_backend(), GetSyncStatus)
-      .WillOnce(WithArg<0>(
-          Invoke([](auto callback) { std::move(callback).Run(false); })));
+  EXPECT_CALL(is_syncing_passwords_callback_, Run)
+      .WillRepeatedly(Return(false));
   EXPECT_CALL(shadow_backend(), GetAllLoginsAsync).Times(0);
   proxy_backend().GetAllLoginsAsync(mock_reply.Get());
 
@@ -368,9 +369,8 @@
         .WillOnce(WithArg<0>(Invoke([&p](LoginsOrErrorReply reply) -> void {
           std::move(reply).Run(p.GetMainLogins());
         })));
-    EXPECT_CALL(main_backend(), GetSyncStatus)
-        .WillOnce(WithArg<0>(
-            Invoke([](auto callback) { std::move(callback).Run(true); })));
+    EXPECT_CALL(is_syncing_passwords_callback_, Run)
+        .WillRepeatedly(Return(true));
     EXPECT_CALL(shadow_backend(), GetAllLoginsAsync)
         .WillOnce(WithArg<0>(Invoke([&p](LoginsOrErrorReply reply) -> void {
           std::move(reply).Run(p.GetShadowLogins());
diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc
index 92d1c969..10355365 100644
--- a/components/password_manager/core/browser/test_password_store.cc
+++ b/components/password_manager/core/browser/test_password_store.cc
@@ -257,10 +257,6 @@
   return nullptr;
 }
 
-void TestPasswordStore::GetSyncStatus(base::OnceCallback<void(bool)> callback) {
-  NOTIMPLEMENTED();
-}
-
 bool TestPasswordStore::IsAccountStore() const {
   return is_account_store_.value();
 }
diff --git a/components/password_manager/core/browser/test_password_store.h b/components/password_manager/core/browser/test_password_store.h
index d182362..98568ca 100644
--- a/components/password_manager/core/browser/test_password_store.h
+++ b/components/password_manager/core/browser/test_password_store.h
@@ -99,7 +99,6 @@
   FieldInfoStore* GetFieldInfoStore() override;
   std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
   CreateSyncControllerDelegate() override;
-  void GetSyncStatus(base::OnceCallback<void(bool)> callback) override;
 
  private:
   LoginsResult GetAllLoginsInternal();
diff --git a/components/performance_manager/performance_manager_browsertest.cc b/components/performance_manager/performance_manager_browsertest.cc
index 57a19cc..39e742a 100644
--- a/components/performance_manager/performance_manager_browsertest.cc
+++ b/components/performance_manager/performance_manager_browsertest.cc
@@ -148,7 +148,8 @@
   EXPECT_EQ(tab_helper->frames_.size(), 1U);
 
   // Load a fenced frame.
-  GURL fenced_frame_url = embedded_test_server()->GetURL("/title1.html");
+  GURL fenced_frame_url =
+      embedded_test_server()->GetURL("/fenced_frames/title1.html");
   content::RenderFrameHost* fenced_frame_host =
       fenced_frame_test_helper().CreateFencedFrame(
           GetWebContents()->GetMainFrame(), fenced_frame_url);
diff --git a/components/permissions/features.cc b/components/permissions/features.cc
index 47555f2..50b190b 100644
--- a/components/permissions/features.cc
+++ b/components/permissions/features.cc
@@ -67,11 +67,6 @@
     "kPermissionPredictionServiceUseUrlOverride",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// When enabled, permission verification and requesting is done on
-// RFH->GetLastCommittedOrigin() instead of RFH->GetLastCommittedURL().
-const base::Feature kRevisedOriginHandling{"PermissionsRevisedOriginHandling",
-                                           base::FEATURE_ENABLED_BY_DEFAULT};
-
 #if defined(OS_ANDROID)
 // When enabled, the Default Search Engine does not automatically receive the
 // "geolocation" and "notifications" permissions. DSE only applies to Android.
diff --git a/components/permissions/features.h b/components/permissions/features.h
index 12ad6ec..21b08c17 100644
--- a/components/permissions/features.h
+++ b/components/permissions/features.h
@@ -49,9 +49,6 @@
 COMPONENT_EXPORT(PERMISSIONS_COMMON)
 extern const base::Feature kPermissionPredictionServiceUseUrlOverride;
 
-COMPONENT_EXPORT(PERMISSIONS_COMMON)
-extern const base::Feature kRevisedOriginHandling;
-
 #if defined(OS_ANDROID)
 COMPONENT_EXPORT(PERMISSIONS_COMMON)
 extern const base::Feature kRevertDSEAutomaticPermissions;
diff --git a/components/permissions/permission_util.cc b/components/permissions/permission_util.cc
index 30a6b8f4..495fc3bb 100644
--- a/components/permissions/permission_util.cc
+++ b/components/permissions/permission_util.cc
@@ -259,27 +259,22 @@
     content::RenderFrameHost* render_frame_host) {
   DCHECK(render_frame_host);
 
-  if (base::FeatureList::IsEnabled(features::kRevisedOriginHandling)) {
-    content::WebContents* web_contents =
-        content::WebContents::FromRenderFrameHost(render_frame_host);
-    // If `allow_universal_access_from_file_urls` flag is enabled, a file can
-    // introduce discrepancy between GetLastCommittedURL and
-    // GetLastCommittedOrigin. In that case GetLastCommittedURL should be used
-    // for requesting and verifying permissions.
-    // Disabling `kRevisedOriginHandling` feature introduces no side effects,
-    // because in both cases we rely on
-    // GetLastCommittedURL().DeprecatedGetOriginAsURL().
-    if (web_contents->GetOrCreateWebPreferences()
-            .allow_universal_access_from_file_urls &&
-        render_frame_host->GetLastCommittedOrigin().GetURL().SchemeIsFile()) {
-      return render_frame_host->GetLastCommittedURL()
-          .DeprecatedGetOriginAsURL();
-    }
-
-    return render_frame_host->GetLastCommittedOrigin().GetURL();
+  content::WebContents* web_contents =
+      content::WebContents::FromRenderFrameHost(render_frame_host);
+  // If `allow_universal_access_from_file_urls` flag is enabled, a file can
+  // introduce discrepancy between GetLastCommittedURL and
+  // GetLastCommittedOrigin. In that case GetLastCommittedURL should be used
+  // for requesting and verifying permissions.
+  // Disabling `kRevisedOriginHandling` feature introduces no side effects,
+  // because in both cases we rely on
+  // GetLastCommittedURL().DeprecatedGetOriginAsURL().
+  if (web_contents->GetOrCreateWebPreferences()
+          .allow_universal_access_from_file_urls &&
+      render_frame_host->GetLastCommittedOrigin().GetURL().SchemeIsFile()) {
+    return render_frame_host->GetLastCommittedURL().DeprecatedGetOriginAsURL();
   }
 
-  return render_frame_host->GetLastCommittedURL().DeprecatedGetOriginAsURL();
+  return render_frame_host->GetLastCommittedOrigin().GetURL();
 }
 
 }  // namespace permissions
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto
index f5bee831..609a77b 100644
--- a/components/policy/proto/device_management_backend.proto
+++ b/components/policy/proto/device_management_backend.proto
@@ -1416,6 +1416,37 @@
   optional bool secure_boot = 2 [deprecated = true];
 }
 
+// Hardware component bus device classes.
+// Maps to BusDeviceClass from cros_healthd.
+enum BusDeviceClass {
+  DEVICE_CLASS_UNSPECIFIED = 0;
+  DISPLAY_CONTROLLER = 1;
+  ETHERNET_CONTROLLER = 2;
+  WIRELESS_CONTROLLER = 3;
+  BLUETOOTH_ADAPTER = 4;
+  THUNDERBOLT_CONTROLLER = 5;
+}
+
+// Hardware component busses.
+// Maps to BusInfo types from cros_healthd.
+enum BusType {
+  BUS_TYPE_UNSPECIFIED = 0;
+  PCI_BUS = 1;
+  USB_BUS = 2;
+  THUNDERBOLT_BUS = 3;
+}
+
+// Information about a device's network hardware.
+message NetworkAdapterInfo {
+  optional BusDeviceClass device_class = 1;
+  optional BusType bus_type = 2;
+  optional int32 vendor_id = 3;
+  optional string vendor_name = 4;
+  optional int32 device_id = 5;
+  optional string device_name = 6;
+  repeated string driver = 7;
+}
+
 // Report device level status.
 message DeviceStatusReportRequest {
   reserved 4, 7, 13, 20;
@@ -1550,6 +1581,9 @@
 
   // Information about how the os was booted.
   optional BootInfo boot_info = 44;
+
+  // Information about the device's network hardware.
+  repeated NetworkAdapterInfo network_adapter_info = 45;
 }
 
 message OsUpdateStatus {
@@ -4349,6 +4383,7 @@
   optional BrowserPublicKeyUploadResponse browser_public_key_upload_response =
       36;
 
+  // Response to EUICC info upload request.
   optional UploadEuiccInfoResponse upload_euicc_info_response = 37;
 
   // Next id: 38.
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 9526864c..3dfe22a 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -19887,8 +19887,7 @@
         'type': 'array',
         'items': { 'type': 'string' }
       },
-      'supported_on': ['android:65-'],
-      'future_on': ['ios'],
+      'supported_on': ['android:65-', 'ios:97-'],
       'features': {
         'dynamic_refresh': True,
         'per_profile': False,
diff --git a/components/policy/test_support/BUILD.gn b/components/policy/test_support/BUILD.gn
index 173d599..b8d7860 100644
--- a/components/policy/test_support/BUILD.gn
+++ b/components/policy/test_support/BUILD.gn
@@ -5,10 +5,7 @@
 static_library("test_support") {
   testonly = true
 
-  data = [
-    "asn1der.py",
-    "policy_testserver.py",
-  ]
+  data = [ "policy_testserver.py" ]
 
   sources = [
     "client_storage.cc",
diff --git a/components/policy/test_support/OWNERS b/components/policy/test_support/OWNERS
index a60e0da6..76cec38b 100644
--- a/components/policy/test_support/OWNERS
+++ b/components/policy/test_support/OWNERS
@@ -1,4 +1,3 @@
 # policy_testserver.py is used in tast and autotest integration tests.
 
 per-file policy_testserver.py=ftirelo@chromium.org, pmarko@chromium.org, vsavu@google.com
-per-file asn1der.py=ftirelo@chromium.org, pmarko@chromium.org, vsavu@google.com
diff --git a/components/policy/test_support/asn1der.py b/components/policy/test_support/asn1der.py
deleted file mode 100644
index 00aca5c..0000000
--- a/components/policy/test_support/asn1der.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright (c) 2011 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.
-
-"""Helper module for ASN.1/DER encoding."""
-
-import binascii
-import struct
-
-# Tags as defined by ASN.1.
-INTEGER = 2
-BIT_STRING = 3
-NULL = 5
-OBJECT_IDENTIFIER = 6
-SEQUENCE = 0x30
-
-def Data(tag, data):
-  """Generic type-length-value encoder.
-
-  Args:
-    tag: the tag.
-    data: the data for the given tag.
-  Returns:
-    encoded TLV value.
-  """
-  if len(data) < 128:
-    return struct.pack(">BB", tag, len(data)) + data;
-  assert len(data) <= 0xffff;
-  return struct.pack(">BBH", tag, 0x82, len(data)) + data;
-
-def Integer(value):
-  """Encodes an integer.
-
-  Args:
-    value: the long value.
-  Returns:
-    encoded TLV value.
-  """
-  data = '%x' % value
-  if (len(data) % 2 == 1):
-    # Odd number of non-zero bytes - pad out our data to a full number of bytes.
-    data = '0' + data
-
-  # If the high bit is set, need to prepend a null byte to denote a positive
-  # number.
-  if (int(data[0], 16) >= 8):
-    data = '00' + data
-
-  return Data(INTEGER, binascii.unhexlify(data))
-
-def Bitstring(value):
-  """Encodes a bit string.
-
-  Args:
-    value: a string holding the binary data.
-  Returns:
-    encoded TLV value.
-  """
-  return Data(BIT_STRING, b'\x00' + value)
-
-def Sequence(values):
-  """Encodes a sequence of other values.
-
-  Args:
-    values: the list of values, must be strings holding already encoded data.
-  Returns:
-    encoded TLV value.
-  """
-  return Data(SEQUENCE, b''.join(values))
diff --git a/components/policy/test_support/policy_testserver.py b/components/policy/test_support/policy_testserver.py
index d123cbe0..06980ee 100644
--- a/components/policy/test_support/policy_testserver.py
+++ b/components/policy/test_support/policy_testserver.py
@@ -65,6 +65,8 @@
 
 import base64
 from six.moves import BaseHTTPServer
+from cryptography.hazmat.primitives.asymmetric import padding, rsa
+from cryptography.hazmat.primitives import hashes, serialization
 import glob
 import google.protobuf.text_format
 import hashlib
@@ -76,15 +78,10 @@
 import six
 import sys
 import time
-import tlslite
-import tlslite.api
-import tlslite.utils
-import tlslite.utils.cryptomath
 from six.moves import urllib
 from six.moves.urllib import request as urllib_request
 from six.moves.urllib import parse as urlparse
 
-import asn1der
 import testserver_base
 
 import device_management_backend_pb2 as dm
@@ -113,9 +110,6 @@
 except ImportError:
   crypto = None
 
-# ASN.1 object identifier for PKCS#1/RSA.
-PKCS1_RSA_OID = b'\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01'
-
 # List of machines that trigger the server to send kiosk enrollment response
 # for the register request.
 KIOSK_MACHINE_IDS = [ 'KIOSK' ]
@@ -1342,8 +1336,8 @@
 
     # Sign the serialized policy data
     if msg.signature_type == dm.PolicyFetchRequest.SHA1_RSA:
-      response.policy_data_signature = bytes(
-          signing_key['private_key'].hashAndSign(response.policy_data))
+      response.policy_data_signature = signing_key['private_key'].sign(
+          response.policy_data, padding.PKCS1v15(), hashes.SHA1())
       if msg.public_key_version != signing_key_version:
         response.new_public_key = signing_key['public_key']
 
@@ -1359,8 +1353,8 @@
                 verification_sig)
 
         if client_key is not None:
-          response.new_public_key_signature = bytes(
-              client_key['private_key'].hashAndSign(response.new_public_key))
+          response.new_public_key_signature = client_key['private_key'].sign(
+              response.new_public_key, padding.PKCS1v15(), hashes.SHA1())
 
     return (200, response.SerializeToString())
 
@@ -1562,15 +1556,14 @@
           print('Failed to load private key from %s' % key_path)
           continue
         try:
-          # Decode with replacement characters to avoid decode errors if was
-          # actually DER.
-          key = tlslite.api.parsePEMKey(key_str.decode('utf-8', 'replace'),
-                                        private=True)
-        except SyntaxError:
-          key = tlslite.utils.python_rsakey.Python_RSAKey._parsePKCS8(
-              bytearray(key_str))
+          key = serialization.load_pem_private_key(key_str, password=None)
+        except ValueError:
+          key = serialization.load_der_private_key(key_str, password=None)
 
         assert key is not None
+        if not isinstance(key, rsa.RSAPrivateKey):
+          raise TypeError('Unexpected key type')
+
         key_info = { 'private_key' : key }
 
         # Now try to read in a signature, if one exists.
@@ -1585,9 +1578,9 @@
       # Use the canned private keys if none were passed from the command line.
       for signing_key in SIGNING_KEYS:
         decoded_key = base64.b64decode(signing_key['key']);
-        key = tlslite.utils.python_rsakey.Python_RSAKey._parsePKCS8(
-            bytearray(decoded_key))
+        key = serialization.load_der_private_key(decoded_key, password=None)
         assert key is not None
+        assert isinstance(key, rsa.RSAPrivateKey)
         # Grab the signature dictionary for this key and decode all of the
         # signatures.
         signature_dict = signing_key['signatures']
@@ -1599,15 +1592,9 @@
 
     # Derive the public keys from the private keys.
     for entry in self.keys:
-      key = entry['private_key']
-
-      algorithm = asn1der.Sequence(
-          [ asn1der.Data(asn1der.OBJECT_IDENTIFIER, PKCS1_RSA_OID),
-            asn1der.Data(asn1der.NULL, b'') ])
-      rsa_pubkey = asn1der.Sequence([ asn1der.Integer(key.n),
-                                      asn1der.Integer(key.e) ])
-      pubkey = asn1der.Sequence([ algorithm, asn1der.Bitstring(rsa_pubkey) ])
-      entry['public_key'] = pubkey
+      entry['public_key'] = entry['private_key'].public_key().public_bytes(
+          encoding=serialization.Encoding.DER,
+          format=serialization.PublicFormat.SubjectPublicKeyInfo)
 
     try:
       self.ReadClientStateFile()
diff --git a/components/reporting/metrics/metric_event_observer_manager.h b/components/reporting/metrics/metric_event_observer_manager.h
index 324b284..c99d680 100644
--- a/components/reporting/metrics/metric_event_observer_manager.h
+++ b/components/reporting/metrics/metric_event_observer_manager.h
@@ -44,7 +44,7 @@
 
   void OnEventObserved(MetricData metric_data);
 
-  virtual void Report(MetricData metric_data);
+  void Report(MetricData metric_data);
 
   const std::unique_ptr<MetricEventObserver> event_observer_;
 
diff --git a/components/reporting/resources/resource_interface.cc b/components/reporting/resources/resource_interface.cc
index 413c8c75..2cf8a9e 100644
--- a/components/reporting/resources/resource_interface.cc
+++ b/components/reporting/resources/resource_interface.cc
@@ -19,7 +19,7 @@
 
 ScopedReservation::ScopedReservation(ScopedReservation&& other)
     : resource_interface_(other.resource_interface_),
-      size_(std::move(other.size_)) {}
+      size_(std::exchange(other.size_, absl::nullopt)) {}
 
 bool ScopedReservation::reserved() const {
   return size_.has_value();
diff --git a/components/reporting/resources/resource_interface_unittest.cc b/components/reporting/resources/resource_interface_unittest.cc
index 56b594c..ade669e 100644
--- a/components/reporting/resources/resource_interface_unittest.cc
+++ b/components/reporting/resources/resource_interface_unittest.cc
@@ -100,6 +100,18 @@
   waiter.Wait();
 }
 
+TEST_P(ResourceInterfaceTest, MoveScopedReservationTest) {
+  uint64_t size = resource_interface()->GetTotal();
+  ScopedReservation scoped_reservation(size / 2, resource_interface());
+  EXPECT_TRUE(scoped_reservation.reserved());
+  {
+    ScopedReservation moved_scoped_reservation(std::move(scoped_reservation));
+    EXPECT_TRUE(moved_scoped_reservation.reserved());
+    EXPECT_FALSE(scoped_reservation.reserved());
+  }
+  EXPECT_FALSE(scoped_reservation.reserved());
+}
+
 TEST_P(ResourceInterfaceTest, ScopedReservationBasicReduction) {
   uint64_t size = resource_interface()->GetTotal() / 2;
   ScopedReservation scoped_reservation(size, resource_interface());
diff --git a/components/search_engines/prepopulated_engines.json b/components/search_engines/prepopulated_engines.json
index 60366b8..d683def 100644
--- a/components/search_engines/prepopulated_engines.json
+++ b/components/search_engines/prepopulated_engines.json
@@ -28,7 +28,7 @@
     // Increment this if you change the data in ways that mean users with
     // existing data should get a new version. Otherwise, existing data may
     // continue to be used and updates made here will not always appear.
-    "kCurrentDataVersion": 126
+    "kCurrentDataVersion": 127
   },
 
   // The following engines are included in country lists and are added to the
@@ -117,7 +117,7 @@
       "keyword": "google.com",
       "favicon_url": "https://www.google.com/images/branding/product/ico/googleg_lodp.ico",
       "search_url": "{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:iOSSearchLanguage}{google:prefetchSource}{google:searchClient}{google:sourceId}{google:contextualSearchVersion}ie={inputEncoding}",
-      "suggest_url": "{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client={google:suggestClient}&gs_ri={google:suggestRid}&xssi=t&q={searchTerms}&{google:inputType}{google:omniboxFocusType}{google:cursorPosition}{google:currentPageUrl}{google:pageClassification}{google:searchVersion}{google:sessionToken}{google:prefetchQuery}sugkey={google:suggestAPIKeyParameter}",
+      "suggest_url": "{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client={google:suggestClient}&gs_ri={google:suggestRid}&xssi=t&q={searchTerms}&{google:inputType}{google:omniboxFocusType}{google:cursorPosition}{google:currentPageUrl}{google:pageClassification}{google:clientCacheTimeToLive}{google:searchVersion}{google:sessionToken}{google:prefetchQuery}sugkey={google:suggestAPIKeyParameter}",
       "image_url": "{google:baseSearchByImageURL}upload",
       "contextual_search_url": "{google:baseURL}_/contextualsearch?{google:contextualSearchVersion}{google:contextualSearchContextData}",
       "image_url_post_params": "encoded_image={google:imageThumbnail},image_url={google:imageURL},sbisrc={google:imageSearchSource},original_width={google:imageOriginalWidth},original_height={google:imageOriginalHeight}",
diff --git a/components/search_engines/template_url.cc b/components/search_engines/template_url.cc
index d0bf950..36e25919 100644
--- a/components/search_engines/template_url.cc
+++ b/components/search_engines/template_url.cc
@@ -714,6 +714,9 @@
                                         start));
   } else if (parameter == "google:pageClassification") {
     replacements->push_back(Replacement(GOOGLE_PAGE_CLASSIFICATION, start));
+  } else if (parameter == "google:clientCacheTimeToLive") {
+    replacements->push_back(
+        Replacement(GOOGLE_CLIENT_CACHE_TIME_TO_LIVE, start));
   } else if (parameter == "google:pathWildcard") {
     // Do nothing, we just want the path wildcard removed from the URL.
   } else if (parameter == "google:prefetchQuery") {
@@ -1133,6 +1136,17 @@
         }
         break;
 
+      case GOOGLE_CLIENT_CACHE_TIME_TO_LIVE:
+        if (search_terms_args.search_terms.size() == 0 &&
+            search_terms_args.zero_suggest_cache_duration_sec > 0) {
+          HandleReplacement(
+              "ccttl",
+              base::NumberToString(
+                  search_terms_args.zero_suggest_cache_duration_sec),
+              *i, &url);
+        }
+        break;
+
       case GOOGLE_PREFETCH_QUERY: {
         const std::string& query = search_terms_args.prefetch_query;
         const std::string& type = search_terms_args.prefetch_query_type;
diff --git a/components/search_engines/template_url.h b/components/search_engines/template_url.h
index 23d8de5a..b104d5ca 100644
--- a/components/search_engines/template_url.h
+++ b/components/search_engines/template_url.h
@@ -252,6 +252,10 @@
     bool is_prefetch = false;
 
     ContextualSearchParams contextual_search_params;
+
+    // The cache duration to be sent as a query string parameter in the zero
+    // suggest requests, if non-zero.
+    uint32_t zero_suggest_cache_duration_sec = 0;
   };
 
   TemplateURLRef(const TemplateURL* owner, Type type);
@@ -379,18 +383,19 @@
   enum ReplacementType {
     ENCODING,
     GOOGLE_ASSISTED_QUERY_STATS,
-    GOOGLE_BASE_URL,
     GOOGLE_BASE_SEARCH_BY_IMAGE_URL,
     GOOGLE_BASE_SUGGEST_URL,
-    GOOGLE_CONTEXTUAL_SEARCH_VERSION,
+    GOOGLE_BASE_URL,
+    GOOGLE_CLIENT_CACHE_TIME_TO_LIVE,
     GOOGLE_CONTEXTUAL_SEARCH_CONTEXT_DATA,
+    GOOGLE_CONTEXTUAL_SEARCH_VERSION,
     GOOGLE_CURRENT_PAGE_URL,
     GOOGLE_CURSOR_POSITION,
     GOOGLE_IMAGE_ORIGINAL_HEIGHT,
     GOOGLE_IMAGE_ORIGINAL_WIDTH,
     GOOGLE_IMAGE_SEARCH_SOURCE,
-    GOOGLE_IMAGE_THUMBNAIL,
     GOOGLE_IMAGE_THUMBNAIL_BASE64,
+    GOOGLE_IMAGE_THUMBNAIL,
     GOOGLE_IMAGE_URL,
     GOOGLE_INPUT_TYPE,
     GOOGLE_IOS_SEARCH_LANGUAGE,
diff --git a/components/search_engines/template_url_unittest.cc b/components/search_engines/template_url_unittest.cc
index cf14fd08..109f13f 100644
--- a/components/search_engines/template_url_unittest.cc
+++ b/components/search_engines/template_url_unittest.cc
@@ -1152,6 +1152,57 @@
   EXPECT_EQ("http://google.com/?client=suggest_client", result_2.spec());
 }
 
+TEST_F(TemplateURLTest, ZeroSuggestCacheDuration) {
+  const std::string base_url_str("http://google.com/?");
+  const std::string query_params_str("{google:clientCacheTimeToLive}");
+  const std::string full_url_str = base_url_str + query_params_str;
+  search_terms_data_.set_google_base_url(base_url_str);
+  TemplateURLData data;
+  data.SetURL(full_url_str);
+  TemplateURL url(data);
+  EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
+  ASSERT_FALSE(url.url_ref().SupportsReplacement(search_terms_data_));
+
+  {
+    // 'ccttl' query param should not be present if no cache duration is given.
+    TemplateURLRef::SearchTermsArgs search_terms_args;
+    GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
+                                                 search_terms_data_));
+    ASSERT_TRUE(result.is_valid());
+    EXPECT_EQ("http://google.com/?", result.spec());
+  }
+  {
+    // 'ccttl' query param should be present if a positive cache duration is
+    // given.
+    TemplateURLRef::SearchTermsArgs search_terms_args;
+    search_terms_args.zero_suggest_cache_duration_sec = 300;
+    GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
+                                                 search_terms_data_));
+    ASSERT_TRUE(result.is_valid());
+    EXPECT_EQ("http://google.com/?ccttl=300&", result.spec());
+  }
+  {
+    // 'ccttl' query param shouldn't be present if a zero cache duration is
+    // given.
+    TemplateURLRef::SearchTermsArgs search_terms_args;
+    search_terms_args.zero_suggest_cache_duration_sec = 0;
+    GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
+                                                 search_terms_data_));
+    ASSERT_TRUE(result.is_valid());
+    EXPECT_EQ("http://google.com/?", result.spec());
+  }
+  {
+    // 'ccttl' query param should not be present if the request is not a
+    // zero-prefix request.
+    TemplateURLRef::SearchTermsArgs search_terms_args(u"foo");
+    search_terms_args.zero_suggest_cache_duration_sec = 300;
+    GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args,
+                                                 search_terms_data_));
+    ASSERT_TRUE(result.is_valid());
+    EXPECT_EQ("http://google.com/?", result.spec());
+  }
+}
+
 TEST_F(TemplateURLTest, GetURLNoSuggestionsURL) {
   TemplateURLData data;
   data.SetURL("http://google.com/?q={searchTerms}");
diff --git a/components/services/app_service/public/cpp/instance_registry.cc b/components/services/app_service/public/cpp/instance_registry.cc
index 9ce438a..c4f41660 100644
--- a/components/services/app_service/public/cpp/instance_registry.cc
+++ b/components/services/app_service/public/cpp/instance_registry.cc
@@ -56,37 +56,43 @@
   observers_.RemoveObserver(observer);
 }
 
-void InstanceRegistry::OnInstance(InstancePtr delta) {
+void InstanceRegistry::OnInstances(Instances deltas) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
 
-  if (!delta || delta->InstanceId()) {
-    // TODO(crbug.com/1251501): Implement updating the instance registry using
-    // instance ID as a key.
-    return;
-  }
-  // If the instance state is not kDestroyed, adds to
-  // |app_id_to_app_instance_key_|, otherwise removes the instance key from
-  // |app_id_to_app_instance_key_|.
-  if (static_cast<InstanceState>(delta->State() & InstanceState::kDestroyed) ==
-      InstanceState::kUnknown) {
-    app_id_to_app_instance_key_[delta->AppId()].insert(delta->GetInstanceKey());
-  } else {
-    app_id_to_app_instance_key_[delta->AppId()].erase(
-        delta.get()->GetInstanceKey());
-    if (app_id_to_app_instance_key_[delta->AppId()].size() == 0) {
-      app_id_to_app_instance_key_.erase(delta->AppId());
+  for (auto& delta : deltas) {
+    if (delta->InstanceId()) {
+      // TODO(crbug.com/1251501): Implement updating the instance registry using
+      // instance ID as a key.
+      continue;
+    }
+    // If the instance state is not kDestroyed, adds to
+    // |app_id_to_app_instance_key_|, otherwise removes the instance key from
+    // |app_id_to_app_instance_key_|.
+    if (static_cast<InstanceState>(delta.get()->State() &
+                                   InstanceState::kDestroyed) ==
+        InstanceState::kUnknown) {
+      app_id_to_app_instance_key_[delta.get()->AppId()].insert(
+          delta.get()->GetInstanceKey());
+    } else {
+      app_id_to_app_instance_key_[delta.get()->AppId()].erase(
+          delta.get()->GetInstanceKey());
+      if (app_id_to_app_instance_key_[delta.get()->AppId()].size() == 0) {
+        app_id_to_app_instance_key_.erase(delta.get()->AppId());
+      }
     }
   }
 
   if (in_progress_) {
-    deltas_pending_.push_back(std::move(delta));
+    for (auto& delta : deltas) {
+      deltas_pending_.push_back(delta.get()->Clone());
+    }
     return;
   }
-  DoOnInstance(std::move(delta));
+  DoOnInstances(std::move(deltas));
   while (!deltas_pending_.empty()) {
-    InstancePtr instance = std::move(*deltas_pending_.begin());
-    DoOnInstance(std::move(instance));
-    deltas_pending_.pop_front();
+    Instances pending;
+    pending.swap(deltas_pending_);
+    DoOnInstances(std::move(pending));
   }
 }
 
@@ -134,43 +140,43 @@
   return base::Contains(app_id_to_app_instance_key_, app_id);
 }
 
-void InstanceRegistry::DoOnInstance(InstancePtr delta) {
+void InstanceRegistry::DoOnInstances(const Instances& deltas) {
   in_progress_ = true;
 
-  if (delta->InstanceId()) {
-    // TODO(crbug.com/1251501): Implement updating the instance registry using
-    // instance ID as a key.
-    in_progress_ = false;
-    return;
-  }
-  auto s_iter = instance_key_states_.find(delta->GetInstanceKey());
-  Instance* state =
-      (s_iter != instance_key_states_.end()) ? s_iter->second.get() : nullptr;
-  if (InstanceUpdate::Equals(state, delta.get())) {
-    in_progress_ = false;
-    return;
-  }
+  // The remaining for loops range over the deltas vector, so that
+  // OninstanceUpdate is called for each updates, and notify the observers for
+  // every de-duplicated delta. Also update the states for every delta.
+  for (const auto& d_iter : deltas) {
+    if (d_iter->InstanceId()) {
+      // TODO(crbug.com/1251501): Implement updating the instance registry using
+      // instance ID as a key.
+      continue;
+    }
+    auto s_iter = instance_key_states_.find(d_iter->GetInstanceKey());
+    Instance* state =
+        (s_iter != instance_key_states_.end()) ? s_iter->second.get() : nullptr;
+    if (InstanceUpdate::Equals(state, d_iter.get())) {
+      continue;
+    }
 
-  std::unique_ptr<Instance> old_state;
-  Instance* new_delta = delta.get();
-  if (state) {
-    old_state = state->Clone();
-    InstanceUpdate::Merge(state, delta.get());
-  } else {
-    // The content of `delta` is moved, however, `new_delta` is still valid,
-    // because `new_delta` is the pointer to the content of `delta`.
-    instance_key_states_.insert(
-        std::make_pair(delta->GetInstanceKey(), std::move(delta)));
-  }
+    std::unique_ptr<Instance> old_state;
+    if (state) {
+      old_state = state->Clone();
+      InstanceUpdate::Merge(state, d_iter.get());
+    } else {
+      instance_key_states_.insert(std::make_pair(d_iter.get()->GetInstanceKey(),
+                                                 (d_iter.get()->Clone())));
+    }
 
-  for (auto& obs : observers_) {
-    obs.OnInstanceUpdate(InstanceUpdate(old_state.get(), new_delta));
-  }
+    for (auto& obs : observers_) {
+      obs.OnInstanceUpdate(InstanceUpdate(old_state.get(), d_iter.get()));
+    }
 
-  if (static_cast<InstanceState>(new_delta->State() &
-                                 InstanceState::kDestroyed) !=
-      InstanceState::kUnknown) {
-    instance_key_states_.erase(new_delta->GetInstanceKey());
+    if (static_cast<InstanceState>(d_iter.get()->State() &
+                                   InstanceState::kDestroyed) !=
+        InstanceState::kUnknown) {
+      instance_key_states_.erase(d_iter.get()->GetInstanceKey());
+    }
   }
   in_progress_ = false;
 }
diff --git a/components/services/app_service/public/cpp/instance_registry.h b/components/services/app_service/public/cpp/instance_registry.h
index 67e91c0..b7567db 100644
--- a/components/services/app_service/public/cpp/instance_registry.h
+++ b/components/services/app_service/public/cpp/instance_registry.h
@@ -5,11 +5,11 @@
 #ifndef COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INSTANCE_REGISTRY_H_
 #define COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INSTANCE_REGISTRY_H_
 
-#include <list>
 #include <map>
 #include <memory>
 #include <set>
 #include <string>
+#include <vector>
 
 #include "ash/public/cpp/shelf_types.h"
 #include "base/observer_list.h"
@@ -75,20 +75,21 @@
   void RemoveObserver(Observer* observer);
 
   using InstancePtr = std::unique_ptr<Instance>;
+  using Instances = std::vector<InstancePtr>;
 
-  // Notification and merging might be delayed until after OnInstance returns.
+  // Notification and merging might be delayed until after OnInstances returns.
   // For example, suppose that the initial set of states is (a0, b0, c0) for
-  // three app_id's ("a", "b", "c"). Now suppose OnInstance is called with an
-  // update (b1), and when notified of b1, an observer calls OnInstance
-  // again with (b2). The b1 delta should be processed before the b2 delta,
-  // as it was sent first, and both b1 and b2 will be updated to the observer
-  // following the sequence. This means that processing b2 (scheduled by the
-  // second OnInstance call) should wait until the first OnInstance call has
-  // finished processing b1, and then b2, which means that processing b2 is
-  // delayed until after the second OnInstance call returns.
+  // three app_id's ("a", "b", "c"). Now suppose OnInstances is called with two
+  // updates (b1, c1), and when notified of b1, an observer calls OnInstances
+  // again with (c2, d2). The c1 delta should be processed before the c2 delta,
+  // as it was sent first, and both c1 and c2 will be updated to the observer
+  // following the sequence. This means that processing c2 (scheduled by the
+  // second OnInstances call) should wait until the first OnInstances call has
+  // finished processing b1, and then c1, which means that processing c2 is
+  // delayed until after the second OnInstances call returns.
   //
-  // The caller presumably calls OnInstance(std::move(delta)).
-  void OnInstance(InstancePtr delta);
+  // The caller presumably calls OnInstances(std::move(deltas)).
+  void OnInstances(Instances deltas);
 
   // Return enclosing app windows for the |app_id|. If the app is in a browser
   // tab, the window returned will be the window of the browser.
@@ -158,27 +159,27 @@
   }
 
  private:
-  void DoOnInstance(InstancePtr deltas);
+  void DoOnInstances(const Instances& deltas);
 
   base::ObserverList<Observer> observers_;
 
-  // OnInstance calls DoOnInstance zero or more times. If we're nested,
-  // in_progress is true, so that there's multiple OnInstance call to this
+  // OnInstances calls DoOnInstances zero or more times. If we're nested,
+  // in_progress is true, so that there's multiple OnInstances call to this
   // InstanceRegistry in the call stack, the deeper OnInstances call simply adds
-  // work to deltas_pending_ and returns without calling DoOnInstance. If we're
-  // not nested, in_progress is false, OnInstance calls DoOnInstance one or
-  // more times; "more times" happens if DoOnInstance notifying observers leads
-  // to more OnInstance calls that enqueue deltas_pending_ work.
+  // work to deltas_pending_ and returns without calling DoOnInstances. If we're
+  // not nested, in_progress is false, OnInstances calls DoOnInstances one or
+  // more times; "more times" happens if DoOnInstances notifying observers leads
+  // to more OnInstances calls that enqueue deltas_pending_ work.
   //
-  // Nested OnInstance calls are expected to be rare (but still dealt with
-  // sensibly). In the typical case, OnInstance should call DoOnInstance
+  // Nested OnInstances calls are expected to be rare (but still dealt with
+  // sensibly). In the typical case, OnInstances should call DoOnInstances
   // exactly once, and deltas_pending_ will stay empty.
   bool in_progress_ = false;
 
   // Maps from instance key to the latest state: the "sum" of all previous
   // deltas.
   std::map<const Instance::InstanceKey, InstancePtr> instance_key_states_;
-  std::list<InstancePtr> deltas_pending_;
+  Instances deltas_pending_;
 
   // Maps from app id to app instance key.
   std::map<const std::string, std::set<const Instance::InstanceKey>>
diff --git a/components/services/app_service/public/cpp/instance_registry_unittest.cc b/components/services/app_service/public/cpp/instance_registry_unittest.cc
index 9090d65..23c5dfb 100644
--- a/components/services/app_service/public/cpp/instance_registry_unittest.cc
+++ b/components/services/app_service/public/cpp/instance_registry_unittest.cc
@@ -83,11 +83,11 @@
   std::set<const aura::Window*> updated_enclosing_windows_;
 };
 
-// In the tests below, just "recursive" means that instance_registry.OnInstance
+// In the tests below, just "recursive" means that instance_registry.OnInstances
 // calls observer.OnInstanceUpdate which calls instance_registry.ForEachInstance
 // and instance_registry.ForOneInstance. "Super-recursive" means that
-// instance_registry.OnInstance calls observer.OnInstanceUpdate calls
-// instance_registry.OnInstance which calls observer.OnInstanceUpdate.
+// instance_registry.OnInstances calls observer.OnInstanceUpdate calls
+// instance_registry.OnInstances which calls observer.OnInstanceUpdate.
 class InstanceRecursiveObserver : public apps::InstanceRegistry::Observer {
  public:
   explicit InstanceRecursiveObserver(apps::InstanceRegistry* instance_registry)
@@ -133,6 +133,7 @@
       EXPECT_EQ(expected_num_instances_, num_instance);
     }
 
+    std::vector<std::unique_ptr<apps::Instance>> super_recursive;
     while (!super_recursive_instances_.empty()) {
       std::unique_ptr<apps::Instance> instance =
           std::move(super_recursive_instances_.back());
@@ -141,9 +142,12 @@
         super_recursive_instances_.pop_back();
         break;
       }
-      instance_registry_->OnInstance(std::move(instance));
+      super_recursive.push_back(std::move(instance));
       super_recursive_instances_.pop_back();
     }
+    if (!super_recursive.empty()) {
+      instance_registry_->OnInstances(std::move(super_recursive));
+    }
 
     num_instances_seen_on_instance_update_++;
   }
@@ -168,16 +172,17 @@
   int num_instances_seen_on_instance_update_;
 
   // Non-empty when this.OnInstanceUpdate should trigger more
-  // instance_registry_.OnInstance calls.
+  // instance_registry_.OnInstances calls.
   //
   // During OnInstanceUpdate, this vector (a stack) is popped from the back
   // until a nullptr 'punctuation' element (a group terminator) is seen. If that
   // group of popped elements (in LIFO order) is non-empty, that group forms the
-  // vector of App's passed to instance_registry_.OnInstance.
+  // vector of App's passed to instance_registry_.OnInstances.
   std::vector<std::unique_ptr<apps::Instance>> super_recursive_instances_;
 };
 
 TEST_F(InstanceRegistryTest, ForEachInstance) {
+  std::vector<std::unique_ptr<apps::Instance>> deltas;
   apps::InstanceRegistry instance_registry;
 
   updated_enclosing_windows_.clear();
@@ -188,15 +193,17 @@
   EXPECT_EQ(0u, updated_enclosing_windows_.size());
   EXPECT_EQ(0u, updated_ids_.size());
 
+  deltas.clear();
   aura::Window window1(nullptr);
   window1.Init(ui::LAYER_NOT_DRAWN);
   aura::Window window2(nullptr);
   window2.Init(ui::LAYER_NOT_DRAWN);
   aura::Window window3(nullptr);
   window3.Init(ui::LAYER_NOT_DRAWN);
-  instance_registry.OnInstance(MakeInstanceWithWindow("a", &window1));
-  instance_registry.OnInstance(MakeInstanceWithWindow("b", &window2));
-  instance_registry.OnInstance(MakeInstanceWithWindow("c", &window3));
+  deltas.push_back(MakeInstanceWithWindow("a", &window1));
+  deltas.push_back(MakeInstanceWithWindow("b", &window2));
+  deltas.push_back(MakeInstanceWithWindow("c", &window3));
+  instance_registry.OnInstances(std::move(deltas));
   EXPECT_TRUE(instance_registry.GetEnclosingAppWindows("a") ==
               std::set<aura::Window*>{&window1});
   EXPECT_TRUE(instance_registry.GetEnclosingAppWindows("b") ==
@@ -220,11 +227,13 @@
   EXPECT_NE(updated_ids_.end(), updated_ids_.find("b"));
   EXPECT_NE(updated_ids_.end(), updated_ids_.find("c"));
 
+  deltas.clear();
   aura::Window window4(nullptr);
   window4.Init(ui::LAYER_NOT_DRAWN);
-  instance_registry.OnInstance(
+  deltas.push_back(
       MakeInstanceWithWindow("a", &window1, apps::InstanceState::kRunning));
-  instance_registry.OnInstance(MakeInstanceWithWindow("c", &window4));
+  deltas.push_back(MakeInstanceWithWindow("c", &window4));
+  instance_registry.OnInstances(std::move(deltas));
   EXPECT_TRUE(instance_registry.GetEnclosingAppWindows("a") ==
               std::set<aura::Window*>{&window1});
   EXPECT_TRUE(instance_registry.GetEnclosingAppWindows("c") ==
@@ -288,9 +297,10 @@
   aura::Window window3(nullptr);
   window3.Init(ui::LAYER_NOT_DRAWN);
 
-  instance_registry.OnInstance(MakeInstanceWithWindow("a", &window1));
-  instance_registry.OnInstance(MakeInstanceWithWindow("c", &window2));
-  instance_registry.OnInstance(MakeInstanceWithWindow("a", &window3));
+  deltas.push_back(MakeInstanceWithWindow("a", &window1));
+  deltas.push_back(MakeInstanceWithWindow("c", &window2));
+  deltas.push_back(MakeInstanceWithWindow("a", &window3));
+  instance_registry.OnInstances(std::move(deltas));
 
   EXPECT_EQ(0, num_running_apps_);
   EXPECT_EQ(3u, updated_enclosing_windows_.size());
@@ -314,9 +324,7 @@
   deltas.push_back(MakeInstanceWithWindow("b", &window4));
   deltas.push_back(
       MakeInstanceWithWindow("c", &window2, apps::InstanceState::kRunning));
-  instance_registry.OnInstance(MakeInstanceWithWindow("b", &window4));
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("c", &window2, apps::InstanceState::kRunning));
+  instance_registry.OnInstances(std::move(deltas));
 
   EXPECT_EQ(1, num_running_apps_);
   EXPECT_EQ(2u, updated_ids_.size());
@@ -336,8 +344,9 @@
 
   aura::Window window5(nullptr);
   window5.Init(ui::LAYER_NOT_DRAWN);
-  instance_registry.OnInstance(
+  deltas.push_back(
       MakeInstanceWithWindow("f", &window5, apps::InstanceState::kRunning));
+  instance_registry.OnInstances(std::move(deltas));
 
   EXPECT_EQ(0, num_running_apps_);
   EXPECT_EQ(0u, updated_enclosing_windows_.size());
@@ -345,23 +354,26 @@
 }
 
 TEST_F(InstanceRegistryTest, WholeProcessForOneWindow) {
+  std::vector<std::unique_ptr<apps::Instance>> deltas;
   apps::InstanceRegistry instance_registry;
   InstanceRecursiveObserver observer(&instance_registry);
 
   apps::InstanceState instance_state = apps::InstanceState::kStarted;
+  deltas.clear();
   aura::Window window(nullptr);
   window.Init(ui::LAYER_NOT_DRAWN);
   observer.PrepareForOnInstances(1);
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("p", &window, instance_state));
+  deltas.push_back(MakeInstanceWithWindow("p", &window, instance_state));
+  instance_registry.OnInstances(std::move(deltas));
   EXPECT_EQ(1, observer.NumInstancesSeenOnInstanceUpdate());
 
   instance_state = static_cast<apps::InstanceState>(
       instance_state | apps::InstanceState::kRunning |
       apps::InstanceState::kActive | apps::InstanceState::kVisible);
   observer.PrepareForOnInstances(1);
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("p", &window, instance_state));
+  deltas.clear();
+  deltas.push_back(MakeInstanceWithWindow("p", &window, instance_state));
+  instance_registry.OnInstances(std::move(deltas));
   EXPECT_EQ(1, observer.NumInstancesSeenOnInstanceUpdate());
   EXPECT_TRUE(instance_registry.GetEnclosingAppWindows("p") ==
               std::set<aura::Window*>{&window});
@@ -380,13 +392,14 @@
       apps::InstanceState::kVisible);
   apps::InstanceState state6 = apps::InstanceState::kDestroyed;
   observer.PrepareForOnInstances(1);
-  instance_registry.OnInstance(MakeInstanceWithWindow("p", &window, state1));
-  instance_registry.OnInstance(MakeInstanceWithWindow("p", &window, state2));
-  instance_registry.OnInstance(MakeInstanceWithWindow("p", &window, state3));
-  instance_registry.OnInstance(MakeInstanceWithWindow("p", &window, state4));
-  instance_registry.OnInstance(MakeInstanceWithWindow("p", &window, state5));
-  instance_registry.OnInstance(MakeInstanceWithWindow("p", &window, state6));
-
+  deltas.clear();
+  deltas.push_back(MakeInstanceWithWindow("p", &window, state1));
+  deltas.push_back(MakeInstanceWithWindow("p", &window, state2));
+  deltas.push_back(MakeInstanceWithWindow("p", &window, state3));
+  deltas.push_back(MakeInstanceWithWindow("p", &window, state4));
+  deltas.push_back(MakeInstanceWithWindow("p", &window, state5));
+  deltas.push_back(MakeInstanceWithWindow("p", &window, state6));
+  instance_registry.OnInstances(std::move(deltas));
   // OnInstanceUpdate is called for state1, because state1 is different with
   // previous instance_state. state2 and state3 is not changed, so
   // OnInstanceUpdate is not called. OnInstanceUpdate is called for state4,
@@ -404,7 +417,9 @@
   EXPECT_FALSE(found_window);
 
   observer.PrepareForOnInstances(1);
-  instance_registry.OnInstance(MakeInstanceWithWindow("p", &window, state5));
+  deltas.clear();
+  deltas.push_back(MakeInstanceWithWindow("p", &window, state5));
+  instance_registry.OnInstances(std::move(deltas));
   EXPECT_EQ(1, observer.NumInstancesSeenOnInstanceUpdate());
   EXPECT_TRUE(instance_registry.GetEnclosingAppWindows("p") ==
               std::set<aura::Window*>{&window});
@@ -419,6 +434,7 @@
 }
 
 TEST_F(InstanceRegistryTest, Recursive) {
+  std::vector<std::unique_ptr<apps::Instance>> deltas;
   apps::InstanceRegistry instance_registry;
   InstanceRecursiveObserver observer(&instance_registry);
 
@@ -426,15 +442,15 @@
       apps::InstanceState::kStarted | apps::InstanceState::kRunning);
   apps::InstanceState instance_state2 = static_cast<apps::InstanceState>(
       apps::InstanceState::kStarted | apps::InstanceState::kRunning);
+  deltas.clear();
   aura::Window window1(nullptr);
   window1.Init(ui::LAYER_NOT_DRAWN);
   aura::Window window2(nullptr);
   window2.Init(ui::LAYER_NOT_DRAWN);
   observer.PrepareForOnInstances(-1);
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("o", &window1, instance_state1));
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("p", &window2, instance_state2));
+  deltas.push_back(MakeInstanceWithWindow("o", &window1, instance_state1));
+  deltas.push_back(MakeInstanceWithWindow("p", &window2, instance_state2));
+  instance_registry.OnInstances(std::move(deltas));
   EXPECT_EQ(2, observer.NumInstancesSeenOnInstanceUpdate());
   EXPECT_TRUE(instance_registry.GetEnclosingAppWindows("o") ==
               std::set<aura::Window*>{&window1});
@@ -448,17 +464,16 @@
   std::vector<apps::InstanceState> latest_state;
   latest_state.push_back(instance_state3);
   latest_state.push_back(instance_state3);
+  deltas.clear();
   aura::Window window3(nullptr);
   window3.Init(ui::LAYER_NOT_DRAWN);
   aura::Window window4(nullptr);
   window4.Init(ui::LAYER_NOT_DRAWN);
   observer.PrepareForOnInstances(-1);
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("p", &window2, instance_state3));
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("q", &window3, instance_state4));
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("p", &window4, instance_state3));
+  deltas.push_back(MakeInstanceWithWindow("p", &window2, instance_state3));
+  deltas.push_back(MakeInstanceWithWindow("q", &window3, instance_state4));
+  deltas.push_back(MakeInstanceWithWindow("p", &window4, instance_state3));
+  instance_registry.OnInstances(std::move(deltas));
   EXPECT_EQ(2, observer.NumInstancesSeenOnInstanceUpdate());
   EXPECT_TRUE(instance_registry.GetEnclosingAppWindows("p") ==
               (std::set<aura::Window*>{&window2, &window4}));
@@ -474,12 +489,11 @@
       apps::InstanceState::kActive);
 
   observer.PrepareForOnInstances(4);
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("p", &window2, instance_state5));
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("p", &window2, instance_state6));
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("p", &window2, instance_state7));
+  deltas.clear();
+  deltas.push_back(MakeInstanceWithWindow("p", &window2, instance_state5));
+  deltas.push_back(MakeInstanceWithWindow("p", &window2, instance_state6));
+  deltas.push_back(MakeInstanceWithWindow("p", &window2, instance_state7));
+  instance_registry.OnInstances(std::move(deltas));
   EXPECT_EQ(1, observer.NumInstancesSeenOnInstanceUpdate());
   EXPECT_TRUE(instance_registry.GetEnclosingAppWindows("p") ==
               (std::set<aura::Window*>{&window2, &window4}));
@@ -487,14 +501,12 @@
   apps::InstanceState instance_state8 =
       static_cast<apps::InstanceState>(apps::InstanceState::kDestroyed);
   observer.PrepareForOnInstances(-1);
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("p", &window2, instance_state8));
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("p", &window4, instance_state8));
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("q", &window3, instance_state8));
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("o", &window1, instance_state8));
+  deltas.clear();
+  deltas.push_back(MakeInstanceWithWindow("p", &window2, instance_state8));
+  deltas.push_back(MakeInstanceWithWindow("p", &window4, instance_state8));
+  deltas.push_back(MakeInstanceWithWindow("q", &window3, instance_state8));
+  deltas.push_back(MakeInstanceWithWindow("o", &window1, instance_state8));
+  instance_registry.OnInstances(std::move(deltas));
   EXPECT_EQ(4, observer.NumInstancesSeenOnInstanceUpdate());
   EXPECT_FALSE(instance_registry.ContainsAppId("o"));
   EXPECT_FALSE(instance_registry.ContainsAppId("p"));
@@ -533,8 +545,9 @@
   EXPECT_FALSE(found_window);
 
   observer.PrepareForOnInstances(1);
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("p", &window2, instance_state7));
+  deltas.clear();
+  deltas.push_back(MakeInstanceWithWindow("p", &window2, instance_state7));
+  instance_registry.OnInstances(std::move(deltas));
   EXPECT_EQ(1, observer.NumInstancesSeenOnInstanceUpdate());
   EXPECT_TRUE(instance_registry.GetEnclosingAppWindows("p") ==
               std::set<aura::Window*>{&window2});
@@ -549,10 +562,11 @@
 }
 
 TEST_F(InstanceRegistryTest, SuperRecursive) {
+  std::vector<std::unique_ptr<apps::Instance>> deltas;
   apps::InstanceRegistry instance_registry;
   InstanceRecursiveObserver observer(&instance_registry);
 
-  // Set up a series of OnInstance to be called during
+  // Set up a series of OnInstances to be called during
   // observer.OnInstanceUpdate:
   //  - the 1st update is {'a', &window2, kActive}.
   //  - the 2nd update is {'b', &window3, kActive}.
@@ -561,9 +575,7 @@
   //  - the 5th update is {'c', &window4, kVisible}.
   //  - the 6td update is {'b', &window3, kRunning}.
   //  - the 7th update is {'a', &window2, kRunning}.
-  //  - the 7th update is {'a', &window2, kDestroyed}.
-  //  - the 7th update is {'a', &window2, kUnknown}.
-  //  - the 7th update is {'a', &window1, kDestroyed}.
+  //  - the 8th update is {'b', &window1, kStarted}.
   //
   // The vector is processed in LIFO order with nullptr punctuation to
   // terminate each group. See the comment on the
@@ -600,14 +612,16 @@
   super_recursive_apps.push_back(
       MakeInstanceWithWindow("b", &window5, apps::InstanceState::kVisible));
 
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("a", &window2, apps::InstanceState::kActive));
-  instance_registry.OnInstance(
-      MakeInstanceWithWindow("b", &window3, apps::InstanceState::kActive));
   observer.PrepareForOnInstances(-1, &super_recursive_apps);
-  instance_registry.OnInstance(
+  deltas.clear();
+  deltas.push_back(
+      MakeInstanceWithWindow("a", &window2, apps::InstanceState::kActive));
+  deltas.push_back(
+      MakeInstanceWithWindow("b", &window3, apps::InstanceState::kActive));
+  deltas.push_back(
       MakeInstanceWithWindow("c", &window4, apps::InstanceState::kActive));
-  EXPECT_EQ(8, observer.NumInstancesSeenOnInstanceUpdate());
+  instance_registry.OnInstances(std::move(deltas));
+  EXPECT_EQ(10, observer.NumInstancesSeenOnInstanceUpdate());
   EXPECT_TRUE(instance_registry.GetEnclosingAppWindows("a") ==
               (std::set<aura::Window*>{&window1, &window2}));
   EXPECT_TRUE(instance_registry.GetEnclosingAppWindows("b") ==
@@ -629,6 +643,7 @@
 }
 
 TEST_F(InstanceRegistryTest, GetInstanceKeys) {
+  std::vector<std::unique_ptr<apps::Instance>> deltas1;
   apps::InstanceRegistry instance_registry;
 
   aura::Window window1(nullptr);
@@ -638,9 +653,10 @@
   aura::Window window3(nullptr);
   window3.Init(ui::LAYER_NOT_DRAWN);
 
-  instance_registry.OnInstance(MakeInstanceWithWindow("a", &window1));
-  instance_registry.OnInstance(MakeInstanceWithWindow("b", &window2));
-  instance_registry.OnInstance(MakeInstanceWithWindow("a", &window3));
+  deltas1.push_back(MakeInstanceWithWindow("a", &window1));
+  deltas1.push_back(MakeInstanceWithWindow("b", &window2));
+  deltas1.push_back(MakeInstanceWithWindow("a", &window3));
+  instance_registry.OnInstances(std::move(deltas1));
 
   EXPECT_TRUE(instance_registry.GetInstanceKeys("a") ==
               (std::set<const apps::Instance::InstanceKey>{
@@ -650,10 +666,12 @@
               (std::set<const apps::Instance::InstanceKey>{
                   MakeInstanceKeyNonWebApp(&window2)}));
 
-  instance_registry.OnInstance(
+  std::vector<std::unique_ptr<apps::Instance>> deltas2;
+  deltas2.push_back(
       MakeInstanceWithWindow("a", &window1, apps::InstanceState::kDestroyed));
-  instance_registry.OnInstance(
+  deltas2.push_back(
       MakeInstanceWithWindow("b", &window2, apps::InstanceState::kDestroyed));
+  instance_registry.OnInstances(std::move(deltas2));
 
   EXPECT_TRUE(instance_registry.GetInstanceKeys("a") ==
               (std::set<const apps::Instance::InstanceKey>{
@@ -663,6 +681,7 @@
 }
 
 TEST_F(InstanceRegistryTest, ContainsAppId) {
+  std::vector<std::unique_ptr<apps::Instance>> deltas1;
   apps::InstanceRegistry instance_registry;
 
   aura::Window window1(nullptr);
@@ -672,24 +691,28 @@
   aura::Window window3(nullptr);
   window3.Init(ui::LAYER_NOT_DRAWN);
 
-  instance_registry.OnInstance(MakeInstanceWithWindow("a", &window1));
-  instance_registry.OnInstance(MakeInstanceWithWindow("b", &window2));
-  instance_registry.OnInstance(MakeInstanceWithWindow("a", &window3));
+  deltas1.push_back(MakeInstanceWithWindow("a", &window1));
+  deltas1.push_back(MakeInstanceWithWindow("b", &window2));
+  deltas1.push_back(MakeInstanceWithWindow("a", &window3));
+  instance_registry.OnInstances(std::move(deltas1));
 
   EXPECT_TRUE(instance_registry.ContainsAppId("a"));
   EXPECT_TRUE(instance_registry.ContainsAppId("b"));
   EXPECT_FALSE(instance_registry.ContainsAppId("c"));
 
-  instance_registry.OnInstance(
+  std::vector<std::unique_ptr<apps::Instance>> deltas2;
+  deltas2.push_back(
       MakeInstanceWithWindow("a", &window1, apps::InstanceState::kDestroyed));
-  instance_registry.OnInstance(
+  deltas2.push_back(
       MakeInstanceWithWindow("b", &window2, apps::InstanceState::kDestroyed));
+  instance_registry.OnInstances(std::move(deltas2));
 
   EXPECT_TRUE(instance_registry.ContainsAppId("a"));
   EXPECT_FALSE(instance_registry.ContainsAppId("b"));
 }
 
 TEST_F(InstanceRegistryTest, GetEnclosingAppWindows) {
+  std::vector<std::unique_ptr<apps::Instance>> deltas;
   apps::InstanceRegistry instance_registry;
 
   aura::test::TestWindowDelegate window_delegate;
@@ -709,12 +732,10 @@
   aura::Window parent2(&window_delegate);
   parent2.Init(ui::LAYER_NOT_DRAWN);
 
-  instance_registry.OnInstance(
-      MakeInstance("a", MakeInstanceKeyWebApp(&child1)));
-  instance_registry.OnInstance(
-      MakeInstance("b", MakeInstanceKeyWebApp(&child2)));
-  instance_registry.OnInstance(
-      MakeInstance("c", MakeInstanceKeyWebApp(&parent2)));
+  deltas.push_back(MakeInstance("a", MakeInstanceKeyWebApp(&child1)));
+  deltas.push_back(MakeInstance("b", MakeInstanceKeyWebApp(&child2)));
+  deltas.push_back(MakeInstance("c", MakeInstanceKeyWebApp(&parent2)));
+  instance_registry.OnInstances(std::move(deltas));
 
   EXPECT_TRUE(instance_registry.GetInstanceKeys("a") ==
               (std::set<const apps::Instance::InstanceKey>{
@@ -732,4 +753,4 @@
               (std::set<aura::Window*>{&parent1}));
   EXPECT_TRUE(instance_registry.GetEnclosingAppWindows("c") ==
               std::set<aura::Window*>{&parent2});
-}
+}
\ No newline at end of file
diff --git a/components/services/app_service/public/cpp/intent_util.cc b/components/services/app_service/public/cpp/intent_util.cc
index 4bf8a3b..a3f01da 100644
--- a/components/services/app_service/public/cpp/intent_util.cc
+++ b/components/services/app_service/public/cpp/intent_util.cc
@@ -445,6 +445,11 @@
   return false;
 }
 
+bool IsShareIntent(const apps::mojom::IntentPtr& intent) {
+  return intent->action == kIntentActionSend ||
+         intent->action == kIntentActionSendMultiple;
+}
+
 // TODO(crbug.com/853604): For glob match, it is currently only for Android
 // intent filters, so we will use the ARC intent filter implementation that is
 // transcribed from Android codebase, to prevent divergence from Android code.
@@ -531,25 +536,17 @@
 }
 
 bool OnlyShareToDrive(const apps::mojom::IntentPtr& intent) {
-  if (intent->action == kIntentActionSend ||
-      intent->action == kIntentActionSendMultiple) {
-    if (intent->drive_share_url.has_value() &&
-        !intent->share_text.has_value() && !intent->files.has_value()) {
-      return true;
-    }
-  }
-  return false;
+  return IsShareIntent(intent) && intent->drive_share_url &&
+         !intent->share_text && !intent->files;
 }
 
 bool IsIntentValid(const apps::mojom::IntentPtr& intent) {
   // TODO(crbug.com/853604):Add more checks here to make this a general intent
-  // validity check. Check if this is a share intent with no file or text.
-  if (intent->action == kIntentActionSend ||
-      intent->action == kIntentActionSendMultiple) {
-    if (!intent->share_text.has_value() && !intent->files.has_value()) {
-      return false;
-    }
-  }
+  // validity check. Return false if this is a share intent with no file or
+  // text.
+  if (IsShareIntent(intent))
+    return intent->share_text || intent->files;
+
   return true;
 }
 
diff --git a/components/services/app_service/public/cpp/intent_util.h b/components/services/app_service/public/cpp/intent_util.h
index 451e6845..e7c7c7e 100644
--- a/components/services/app_service/public/cpp/intent_util.h
+++ b/components/services/app_service/public/cpp/intent_util.h
@@ -94,6 +94,9 @@
 bool IsGenericFileHandler(const apps::mojom::IntentPtr& intent,
                           const apps::mojom::IntentFilterPtr& filter);
 
+// Return true if `intent` corresponds to a share intent.
+bool IsShareIntent(const apps::mojom::IntentPtr& intent);
+
 // Return true if |value| matches |pattern| with simple glob syntax.
 // In this syntax, you can use the '*' character to match against zero or
 // more occurrences of the character immediately before. If the character
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service.cc
index 122e1a70..b554cd39 100644
--- a/components/signin/internal/identity_manager/profile_oauth2_token_service.cc
+++ b/components/signin/internal/identity_manager/profile_oauth2_token_service.cc
@@ -64,8 +64,8 @@
       return "MachineLogon::CredentialProvider";
     case SourceForRefreshTokenOperation::kTokenService_ExtractCredentials:
       return "TokenService::ExtractCredentials";
-    case SourceForRefreshTokenOperation::kLogoutTabHelper_DidFinishNavigation:
-      return "LogoutTabHelper::DidFinishNavigation";
+    case SourceForRefreshTokenOperation::kLogoutTabHelper_PrimaryPageChanged:
+      return "LogoutTabHelper::PrimaryPageChanged";
   }
 }
 }  // namespace
diff --git a/components/signin/public/base/signin_metrics.h b/components/signin/public/base/signin_metrics.h
index ab152a2..2ce1c42 100644
--- a/components/signin/public/base/signin_metrics.h
+++ b/components/signin/public/base/signin_metrics.h
@@ -398,9 +398,9 @@
   kTokenService_ExtractCredentials = 17,
   // DEPRECATED on 09/2021 (used for force migration to DICE)
   // kAccountReconcilor_RevokeTokensNotInCookies = 18,
-  kLogoutTabHelper_DidFinishNavigation = 19,
+  kLogoutTabHelper_PrimaryPageChanged = 19,
 
-  kMaxValue = kLogoutTabHelper_DidFinishNavigation,
+  kMaxValue = kLogoutTabHelper_PrimaryPageChanged,
 };
 
 // Different types of reporting. This is used as a histogram suffix.
diff --git a/components/subresource_filter/android/ads_blocked_dialog.cc b/components/subresource_filter/android/ads_blocked_dialog.cc
index c9205f76..d8dcfce 100644
--- a/components/subresource_filter/android/ads_blocked_dialog.cc
+++ b/components/subresource_filter/android/ads_blocked_dialog.cc
@@ -55,9 +55,9 @@
     Dismiss();
 }
 
-void AdsBlockedDialog::Show() {
+void AdsBlockedDialog::Show(bool should_post_dialog) {
   JNIEnv* env = base::android::AttachCurrentThread();
-  Java_AdsBlockedDialog_show(env, java_ads_blocked_dialog_);
+  Java_AdsBlockedDialog_show(env, java_ads_blocked_dialog_, should_post_dialog);
 }
 
 void AdsBlockedDialog::Dismiss() {
diff --git a/components/subresource_filter/android/ads_blocked_dialog.h b/components/subresource_filter/android/ads_blocked_dialog.h
index 25d9627..1a7175cf 100644
--- a/components/subresource_filter/android/ads_blocked_dialog.h
+++ b/components/subresource_filter/android/ads_blocked_dialog.h
@@ -51,7 +51,7 @@
   virtual ~AdsBlockedDialogBase();
 
   // Calls Java side of the dialog to display ads blocked modal dialog.
-  virtual void Show() = 0;
+  virtual void Show(bool should_post_dialog) = 0;
 
   // Dismisses displayed dialog. The owner of AdsBlockedDialog should
   // call this function to correctly dismiss and destroy the dialog. The object
@@ -77,7 +77,7 @@
   AdsBlockedDialog& operator=(const AdsBlockedDialog&) = delete;
 
   // Calls Java side of the dialog to display ads blocked modal dialog.
-  void Show() override;
+  void Show(bool should_post_dialog) override;
 
   // Dismisses displayed dialog. The owner of AdsBlockedDialog should
   // call this function to correctly dismiss and destroy the dialog. The object
diff --git a/components/subresource_filter/android/java/src/org/chromium/components/subresource_filter/AdsBlockedDialog.java b/components/subresource_filter/android/java/src/org/chromium/components/subresource_filter/AdsBlockedDialog.java
index 7b8f92f7..a6e54ea 100644
--- a/components/subresource_filter/android/java/src/org/chromium/components/subresource_filter/AdsBlockedDialog.java
+++ b/components/subresource_filter/android/java/src/org/chromium/components/subresource_filter/AdsBlockedDialog.java
@@ -6,6 +6,7 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.os.Handler;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.TextUtils;
@@ -15,6 +16,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.ui.base.WindowAndroid;
@@ -35,6 +37,7 @@
     private final ModalDialogManager mModalDialogManager;
     private PropertyModel mDialogModel;
     private ClickableSpan mClickableSpan;
+    private Handler mDialogHandler;
 
     @CalledByNative
     static AdsBlockedDialog create(long nativeDialog, @NonNull WindowAndroid windowAndroid) {
@@ -45,6 +48,7 @@
         mNativeDialog = nativeDialog;
         mContext = windowAndroid.getContext().get();
         mModalDialogManager = windowAndroid.getModalDialogManager();
+        mDialogHandler = new Handler(ThreadUtils.getUiThreadLooper());
     }
 
     /**
@@ -54,13 +58,15 @@
      * @param nativeDialog The pointer to the dialog instance created by native code.
      * @param context The context for accessing resources.
      * @param modalDialogManager The ModalDialogManager to display the dialog.
+     * @param dialogHandler The {@link Handler} used to post the call to show the dialog.
      */
     @VisibleForTesting
     AdsBlockedDialog(long nativeDialog, @NonNull Context context,
-            @NonNull ModalDialogManager modalDialogManager) {
+            @NonNull ModalDialogManager modalDialogManager, Handler dialogHandler) {
         mNativeDialog = nativeDialog;
         mContext = context;
         mModalDialogManager = modalDialogManager;
+        mDialogHandler = dialogHandler;
     }
 
     @VisibleForTesting
@@ -74,7 +80,7 @@
     }
 
     @CalledByNative
-    void show() {
+    void show(boolean shouldPostDialog) {
         Resources resources = mContext.getResources();
         mClickableSpan = new ClickableSpan() {
             @Override
@@ -93,7 +99,25 @@
                                        R.string.cancel)
                                .with(ModalDialogProperties.CANCEL_ON_TOUCH_OUTSIDE, true)
                                .build();
-        mModalDialogManager.showDialog(mDialogModel, ModalDialogType.TAB);
+
+        // shouldPostDialog determines if ModalDialogManager#showDialog should be invoked directly
+        // or using Handler#post.
+        // The dialog should be re-shown on the original tab on navigation back from the redirected
+        // support link tab. This redirection is observed by
+        // WebContentsObserver#OnWebContentsFocused and
+        // TabModelSelectorTabModelObserver#didSelectTab. The sequence of invocation of these
+        // methods is not consistent on phones and tablets. Using #post will delay the
+        // #showDialog request reliably to after both tab events are handled on the UI thread,
+        // guaranteeing that the dialog will be re-shown as expected. See crbug.com/1261967 for
+        // details.
+        // TODO (crbug.com/1272049): Investigate tab event observer ordering and tab modal
+        // suspension logic as a follow up.
+        if (shouldPostDialog) {
+            mDialogHandler.post(
+                    () -> mModalDialogManager.showDialog(mDialogModel, ModalDialogType.TAB));
+        } else {
+            mModalDialogManager.showDialog(mDialogModel, ModalDialogType.TAB);
+        }
     }
 
     @CalledByNative
@@ -127,6 +151,7 @@
 
     @Override
     public void onDismiss(PropertyModel model, @DialogDismissalCause int dismissalCause) {
+        mDialogHandler.removeCallbacksAndMessages(null);
         AdsBlockedDialogJni.get().onDismissed(mNativeDialog);
         mNativeDialog = 0;
     }
diff --git a/components/subresource_filter/android/java/src/org/chromium/components/subresource_filter/AdsBlockedDialogTest.java b/components/subresource_filter/android/java/src/org/chromium/components/subresource_filter/AdsBlockedDialogTest.java
index 42e7b510..56c90348 100644
--- a/components/subresource_filter/android/java/src/org/chromium/components/subresource_filter/AdsBlockedDialogTest.java
+++ b/components/subresource_filter/android/java/src/org/chromium/components/subresource_filter/AdsBlockedDialogTest.java
@@ -8,6 +8,7 @@
 import static org.mockito.Mockito.never;
 
 import android.content.res.Resources;
+import android.os.Handler;
 import android.text.style.ClickableSpan;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -17,6 +18,7 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.junit.MockitoJUnit;
@@ -47,6 +49,9 @@
     @Mock
     private AdsBlockedDialog.Natives mNativeMock;
 
+    @Mock
+    private Handler mDialogHandler;
+
     private long mNativeDialog;
     private AdsBlockedDialog mDialog;
     private PropertyModel mModalDialogModel;
@@ -63,7 +68,7 @@
      */
     @Test
     public void testDialogType() {
-        createAndShowDialog();
+        createAndShowDialog(false);
         Resources resources = ApplicationProvider.getApplicationContext().getResources();
 
         Assert.assertEquals("Dialog title should match.",
@@ -89,7 +94,7 @@
      */
     @Test
     public void testDialogDismissedWithPositiveButton() {
-        createAndShowDialog();
+        createAndShowDialog(false);
         ModalDialogProperties.Controller dialogController =
                 mModalDialogModel.get(ModalDialogProperties.CONTROLLER);
         dialogController.onClick(mModalDialogModel, ModalDialogProperties.ButtonType.POSITIVE);
@@ -104,7 +109,7 @@
      */
     @Test
     public void testDialogDismissedWithNegativeButton() {
-        createAndShowDialog();
+        createAndShowDialog(false);
         ModalDialogProperties.Controller dialogController =
                 mModalDialogModel.get(ModalDialogProperties.CONTROLLER);
         dialogController.onClick(mModalDialogModel, ModalDialogProperties.ButtonType.NEGATIVE);
@@ -119,11 +124,12 @@
      */
     @Test
     public void testDialogDismissedCallsNative() {
-        createAndShowDialog();
+        createAndShowDialog(false);
         ModalDialogProperties.Controller dialogController =
                 mModalDialogModel.get(ModalDialogProperties.CONTROLLER);
         dialogController.onDismiss(
                 mModalDialogModel, DialogDismissalCause.NAVIGATE_BACK_OR_TOUCH_OUTSIDE);
+        Mockito.verify(mDialogHandler).removeCallbacksAndMessages(null);
         Mockito.verify(mNativeMock).onDismissed(anyLong());
     }
 
@@ -132,20 +138,34 @@
      * text is clicked.
      */
     @Test
-    public void tesDialogMessageLinkCallback() {
-        createAndShowDialog();
+    public void testDialogMessageLinkCallback() {
+        createAndShowDialog(false);
         mClickableSpan.onClick(null);
         Mockito.verify(mNativeMock).onLearnMoreClicked(anyLong());
     }
 
     /**
+     * Tests that the dialog is shown using Handler#post when shouldPostDialog is true.
+     */
+    @Test
+    public void testPostDialog() {
+        createAndShowDialog(true);
+        ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
+        Mockito.verify(mDialogHandler).post(captor.capture());
+        captor.getValue().run();
+        Mockito.verify(mModalDialogManagerMock)
+                .showDialog(mModalDialogModel, ModalDialogManager.ModalDialogType.TAB);
+    }
+
+    /**
      * Helper function that creates AdsBlockedDialog, calls show() and captures the
      * property model for modal dialog view.
      */
-    private void createAndShowDialog() {
+    private void createAndShowDialog(boolean shouldPostDialog) {
         // Set nativeDialog to a non-zero value to pass assertion check
-        mDialog = new AdsBlockedDialog(1, RuntimeEnvironment.application, mModalDialogManagerMock);
-        mDialog.show();
+        mDialog = new AdsBlockedDialog(
+                1, RuntimeEnvironment.application, mModalDialogManagerMock, mDialogHandler);
+        mDialog.show(shouldPostDialog);
         mModalDialogModel = mDialog.getDialogModelForTesting();
         mClickableSpan = mDialog.getMessageClickableSpanForTesting();
     }
diff --git a/components/subresource_filter/content/browser/ads_blocked_message_delegate.cc b/components/subresource_filter/content/browser/ads_blocked_message_delegate.cc
index ad959c6..52f6cef 100644
--- a/components/subresource_filter/content/browser/ads_blocked_message_delegate.cc
+++ b/components/subresource_filter/content/browser/ads_blocked_message_delegate.cc
@@ -34,7 +34,7 @@
     // Upon returning to the original tab from the redirected tab,
     // the dialog will be restored.
     reprompt_required_ = false;
-    ShowDialog();
+    ShowDialog(/*should_post_dialog=*/true);
   }
 }
 
@@ -102,7 +102,7 @@
 
 void AdsBlockedMessageDelegate::HandleMessageManageClicked() {
   DismissMessage(messages::DismissReason::SECONDARY_ACTION);
-  ShowDialog();
+  ShowDialog(/*should_post_dialog=*/false);
   subresource_filter::ContentSubresourceFilterThrottleManager::LogAction(
       subresource_filter::SubresourceFilterAction::kDetailsShown);
 }
@@ -140,7 +140,7 @@
   ads_blocked_dialog_.reset();
 }
 
-void AdsBlockedMessageDelegate::ShowDialog() {
+void AdsBlockedMessageDelegate::ShowDialog(bool should_post_dialog) {
   DCHECK(!reprompt_required_);
   // Binding with base::Unretained(this) is safe here because
   // AdsBlockedMessageDelegate owns ads_blocked_dialog_. Callbacks won't be
@@ -158,7 +158,7 @@
   // is not attached to a window. See crbug.com/1049090 for details.
   if (!ads_blocked_dialog_)
     return;
-  ads_blocked_dialog_->Show();
+  ads_blocked_dialog_->Show(should_post_dialog);
 }
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(AdsBlockedMessageDelegate);
diff --git a/components/subresource_filter/content/browser/ads_blocked_message_delegate.h b/components/subresource_filter/content/browser/ads_blocked_message_delegate.h
index 9c68c71..3c51675 100644
--- a/components/subresource_filter/content/browser/ads_blocked_message_delegate.h
+++ b/components/subresource_filter/content/browser/ads_blocked_message_delegate.h
@@ -82,7 +82,7 @@
   // explicitly in the code or automatically.
   void HandleDialogDismissed();
 
-  void ShowDialog();
+  void ShowDialog(bool should_post_dialog);
 
   std::unique_ptr<messages::MessageWrapper> message_;
 
diff --git a/components/subresource_filter/content/browser/ads_blocked_message_delegate_unittest.cc b/components/subresource_filter/content/browser/ads_blocked_message_delegate_unittest.cc
index 7303ec7d..ca8964a 100644
--- a/components/subresource_filter/content/browser/ads_blocked_message_delegate_unittest.cc
+++ b/components/subresource_filter/content/browser/ads_blocked_message_delegate_unittest.cc
@@ -25,7 +25,7 @@
 
 class MockAdsBlockedDialog : public AdsBlockedDialogBase {
  public:
-  MOCK_METHOD(void, Show, (), (override));
+  MOCK_METHOD(void, Show, (bool should_post_dialog), (override));
   MOCK_METHOD(void, Dismiss, (), (override));
   MOCK_METHOD(void, Destroy, ());
   ~MockAdsBlockedDialog() override { Destroy(); }
@@ -154,6 +154,9 @@
   allow_ads_clicked_callback_ = std::move(allow_ads_clicked_callback);
   learn_more_clicked_callback_ = std::move(learn_more_clicked_callback);
   dialog_dismissed_callback_ = std::move(dialog_dismissed_callback);
+  // PrepareAdsBlockedDialog() should always be invoked before the dialog is
+  // constructed.
+  EXPECT_TRUE(mock_ads_blocked_dialog_);
   return std::move(mock_ads_blocked_dialog_);
 }
 
@@ -209,7 +212,7 @@
 
   ExpectDismissMessageCall();
   MockAdsBlockedDialog* mock_dialog = PrepareAdsBlockedDialog();
-  EXPECT_CALL(*mock_dialog, Show);
+  EXPECT_CALL(*mock_dialog, Show(false));
   TriggerMessageManageClicked();
   EXPECT_EQ(GetMessageWrapper(), nullptr);
 
@@ -226,7 +229,7 @@
 
   ExpectDismissMessageCall();
   MockAdsBlockedDialog* mock_dialog = PrepareAdsBlockedDialog();
-  EXPECT_CALL(*mock_dialog, Show);
+  EXPECT_CALL(*mock_dialog, Show(false));
   TriggerMessageManageClicked();
   EXPECT_EQ(GetMessageWrapper(), nullptr);
 
@@ -246,7 +249,7 @@
 
   ExpectDismissMessageCall();
   MockAdsBlockedDialog* mock_dialog = PrepareAdsBlockedDialog();
-  EXPECT_CALL(*mock_dialog, Show);
+  EXPECT_CALL(*mock_dialog, Show(false));
   TriggerMessageManageClicked();
   EXPECT_EQ(GetMessageWrapper(), nullptr);
   EXPECT_FALSE(GetDelegate()->reprompt_required_flag_for_testing());
@@ -256,6 +259,9 @@
   TriggerDialogDismissedCallback();
   EXPECT_TRUE(GetDelegate()->reprompt_required_flag_for_testing());
 
+  // Prepare the dialog to be re-shown on navigation back to the original tab.
+  mock_dialog = PrepareAdsBlockedDialog();
+  EXPECT_CALL(*mock_dialog, Show(true));
   OnWebContentsFocused();
   EXPECT_FALSE(GetDelegate()->reprompt_required_flag_for_testing());
 }
@@ -267,7 +273,7 @@
 
   ExpectDismissMessageCall();
   MockAdsBlockedDialog* mock_dialog = PrepareAdsBlockedDialog();
-  EXPECT_CALL(*mock_dialog, Show);
+  EXPECT_CALL(*mock_dialog, Show(false));
   TriggerMessageManageClicked();
 
   // Verify that the AdsBlockedDialog destructor is invoked when the
diff --git a/components/sync/engine/model_type_worker.cc b/components/sync/engine/model_type_worker.cc
index d961f49..93ff9d5 100644
--- a/components/sync/engine/model_type_worker.cc
+++ b/components/sync/engine/model_type_worker.cc
@@ -353,6 +353,11 @@
           break;
         }
         // Copy the sync entity for later decryption.
+        // TODO(crbug.com/1270734): Any write to |entries_pending_decryption_|
+        // should do like DeduplicatePendingUpdatesBasedOnServerId() and honor
+        // entity version. Additionally, it should look up the same server id
+        // in |pending_updates_| and compare versions. In fact, the 2 containers
+        // should probably be moved to a separate class with unit tests.
         entries_pending_decryption_[server_id] = *update_entity;
         break;
       }
@@ -732,10 +737,15 @@
       // New server id, append at the end. Note that we already inserted
       // the correct index (|pending_updates_.size()|) above.
       pending_updates_.push_back(std::move(candidate));
-    } else {
-      // Duplicate! Overwrite the existing item.
-      size_t existing_index = it_and_success.first->second;
-      pending_updates_[existing_index] = std::move(candidate);
+      continue;
+    }
+
+    // Duplicate! Overwrite the existing update if |candidate| has a more recent
+    // version.
+    const size_t existing_index = it_and_success.first->second;
+    UpdateResponseData& existing_update = pending_updates_[existing_index];
+    if (candidate.response_version >= existing_update.response_version) {
+      existing_update = std::move(candidate);
     }
   }
 }
@@ -760,10 +770,15 @@
       // New client tag hash, append at the end. Note that we already inserted
       // the correct index (|pending_updates_.size()|) above.
       pending_updates_.push_back(std::move(candidate));
-    } else {
-      // Duplicate! Overwrite the existing item.
-      size_t existing_index = it_and_success.first->second;
-      pending_updates_[existing_index] = std::move(candidate);
+      continue;
+    }
+
+    // Duplicate! Overwrite the existing update if |candidate| has a more recent
+    // version.
+    const size_t existing_index = it_and_success.first->second;
+    UpdateResponseData& existing_update = pending_updates_[existing_index];
+    if (candidate.response_version >= existing_update.response_version) {
+      existing_update = std::move(candidate);
     }
   }
 }
@@ -792,10 +807,15 @@
       // New item ID, append at the end. Note that we already inserted the
       // correct index (|pending_updates_.size()|) above.
       pending_updates_.push_back(std::move(candidate));
-    } else {
-      // Duplicate! Overwrite the existing item.
-      size_t existing_index = it_and_success.first->second;
-      pending_updates_[existing_index] = std::move(candidate);
+      continue;
+    }
+
+    // Duplicate! Overwrite the existing update if |candidate| has a more recent
+    // version.
+    const size_t existing_index = it_and_success.first->second;
+    UpdateResponseData& existing_update = pending_updates_[existing_index];
+    if (candidate.response_version >= existing_update.response_version) {
+      existing_update = std::move(candidate);
     }
   }
 }
diff --git a/components/sync/engine/model_type_worker.h b/components/sync/engine/model_type_worker.h
index c297497..c76f8f4 100644
--- a/components/sync/engine/model_type_worker.h
+++ b/components/sync/engine/model_type_worker.h
@@ -281,7 +281,10 @@
       unknown_encryption_keys_by_name_;
 
   // Accumulates all the updates from a single GetUpdates cycle in memory so
-  // they can all be sent to the processor at once.
+  // they can all be sent to the processor at once. Some updates may be
+  // deduplicated, e.g. in DeduplicatePendingUpdatesBasedOnServerId(). The
+  // ordering here is NOT guaranteed to stick to the download ordering or any
+  // other.
   UpdateResponseDataList pending_updates_;
 
   // Indicates if processor has local changes. Processor only nudges worker once
diff --git a/components/sync/engine/model_type_worker_unittest.cc b/components/sync/engine/model_type_worker_unittest.cc
index 3a1a9fe..40ab51a 100644
--- a/components/sync/engine/model_type_worker_unittest.cc
+++ b/components/sync/engine/model_type_worker_unittest.cc
@@ -809,39 +809,49 @@
   EXPECT_EQ(kValue3, result[2]->entity.specifics.preference().value());
 }
 
-// Covers the scenario where two updates have the same client tag hash but
+// Covers the scenario where updates have the same client tag hash but
 // different server IDs. This scenario is considered a bug on the server.
 TEST_F(ModelTypeWorkerTest,
        ReceiveUpdates_DuplicateClientTagHashesForDistinctServerIds) {
   NormalInitialize();
 
-  // First create two entities with different tags, so they get assigned
+  // First create three entities with different tags, so they get assigned
   // different server ids.
-  SyncEntity entity1 = server()->UpdateFromServer(
+  SyncEntity oldest_entity = server()->UpdateFromServer(
       /*version_offset=*/10, GenerateTagHash(kTag1),
       GenerateSpecifics("key1", "value1"));
-  SyncEntity entity2 = server()->UpdateFromServer(
-      /*version_offset=*/10, GenerateTagHash(kTag2),
+  SyncEntity second_newest_entity = server()->UpdateFromServer(
+      /*version_offset=*/11, GenerateTagHash(kTag2),
       GenerateSpecifics("key2", "value2"));
-  // Mimic a bug on the server by modifying the second entity to have the same
-  // tag as the first one.
-  entity2.set_client_defined_unique_tag(GenerateTagHash(kTag1).value());
+  SyncEntity newest_entity = server()->UpdateFromServer(
+      /*version_offset=*/12, GenerateTagHash(kTag3),
+      GenerateSpecifics("key3", "value3"));
+
+  // Mimic a bug on the server by modifying all entities to have the same tag.
+  second_newest_entity.set_client_defined_unique_tag(
+      oldest_entity.client_defined_unique_tag());
+  newest_entity.set_client_defined_unique_tag(
+      oldest_entity.client_defined_unique_tag());
+
+  // Send |newest_entity| in the middle position, to rule out the worker is
+  // keeping the first or last received update.
   worker()->ProcessGetUpdatesResponse(
-      server()->GetProgress(), server()->GetContext(), {&entity1, &entity2},
+      server()->GetProgress(), server()->GetContext(),
+      {&oldest_entity, &newest_entity, &second_newest_entity},
       status_controller());
 
   ApplyUpdates();
 
-  // Make sure the first update has been discarded.
+  // Make sure the update with latest version was kept.
   ASSERT_EQ(1u, processor()->GetNumUpdateResponses());
   std::vector<const UpdateResponseData*> result =
       processor()->GetNthUpdateResponse(0);
   ASSERT_EQ(1u, result.size());
   ASSERT_TRUE(result[0]);
-  EXPECT_EQ(entity2.id_string(), result[0]->entity.id);
+  EXPECT_EQ(newest_entity.id_string(), result[0]->entity.id);
 }
 
-// Covers the scenario where two updates have the same GUID as originator client
+// Covers the scenario where updates have the same GUID as originator client
 // item ID but different server IDs. This scenario is considered a bug on the
 // server.
 TEST_F(ModelTypeWorkerTest,
@@ -849,35 +859,48 @@
   const std::string kOriginatorClientItemId = base::GenerateGUID();
   const std::string kURL1 = "http://url1";
   const std::string kURL2 = "http://url2";
+  const std::string kURL3 = "http://url3";
   const std::string kServerId1 = "serverid1";
   const std::string kServerId2 = "serverid2";
+  const std::string kServerId3 = "serverid3";
 
   NormalInitialize();
 
-  sync_pb::SyncEntity entity1;
-  sync_pb::SyncEntity entity2;
+  sync_pb::SyncEntity oldest_entity;
+  sync_pb::SyncEntity second_newest_entity;
+  sync_pb::SyncEntity newest_entity;
 
-  // Generate two entities with the same originator client item ID.
-  entity1.set_id_string(kServerId1);
-  entity2.set_id_string(kServerId2);
-  entity1.mutable_specifics()->mutable_bookmark()->set_url(kURL1);
-  entity2.mutable_specifics()->mutable_bookmark()->set_url(kURL2);
-  entity1.set_originator_client_item_id(kOriginatorClientItemId);
-  entity2.set_originator_client_item_id(kOriginatorClientItemId);
+  oldest_entity.set_version(1000);
+  second_newest_entity.set_version(1001);
+  newest_entity.set_version(1002);
 
+  // Generate entities with the same originator client item ID.
+  oldest_entity.set_id_string(kServerId1);
+  second_newest_entity.set_id_string(kServerId2);
+  newest_entity.set_id_string(kServerId3);
+  oldest_entity.mutable_specifics()->mutable_bookmark()->set_url(kURL1);
+  second_newest_entity.mutable_specifics()->mutable_bookmark()->set_url(kURL2);
+  newest_entity.mutable_specifics()->mutable_bookmark()->set_url(kURL3);
+  oldest_entity.set_originator_client_item_id(kOriginatorClientItemId);
+  second_newest_entity.set_originator_client_item_id(kOriginatorClientItemId);
+  newest_entity.set_originator_client_item_id(kOriginatorClientItemId);
+
+  // Send |newest_entity| in the middle position, to rule out the worker is
+  // keeping the first or last received update.
   worker()->ProcessGetUpdatesResponse(
-      server()->GetProgress(), server()->GetContext(), {&entity1, &entity2},
+      server()->GetProgress(), server()->GetContext(),
+      {&oldest_entity, &newest_entity, &second_newest_entity},
       status_controller());
 
   ApplyUpdates();
 
-  // Make sure the first update has been discarded.
+  // Make sure the update with latest version was kept.
   ASSERT_EQ(1u, processor()->GetNumUpdateResponses());
   std::vector<const UpdateResponseData*> result =
       processor()->GetNthUpdateResponse(0);
   ASSERT_EQ(1u, result.size());
   ASSERT_TRUE(result[0]);
-  EXPECT_EQ(kURL2, result[0]->entity.specifics.bookmark().url());
+  EXPECT_EQ(newest_entity.id_string(), result[0]->entity.id);
 }
 
 // Covers the scenario where two updates have the same originator client item ID
diff --git a/components/sync/protocol/local_trusted_vault.proto b/components/sync/protocol/local_trusted_vault.proto
index 4f09e6b..cb1d23b 100644
--- a/components/sync/protocol/local_trusted_vault.proto
+++ b/components/sync/protocol/local_trusted_vault.proto
@@ -53,4 +53,7 @@
 
 message LocalTrustedVault {
   repeated LocalTrustedVaultPerUser user = 1;
+
+  // Version of the stored data, used to perform data migrations.
+  optional int32 data_version = 2;
 }
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_backend.cc b/components/sync/trusted_vault/standalone_trusted_vault_backend.cc
index 38e0370..204ab53 100644
--- a/components/sync/trusted_vault/standalone_trusted_vault_backend.cc
+++ b/components/sync/trusted_vault/standalone_trusted_vault_backend.cc
@@ -34,6 +34,8 @@
 
 namespace {
 
+const int kCurrentLocalTrustedVaultVersion = 1;
+
 sync_pb::LocalTrustedVault ReadEncryptedFile(const base::FilePath& file_path) {
   sync_pb::LocalTrustedVault proto;
   std::string ciphertext;
@@ -97,6 +99,32 @@
   return result;
 }
 
+// Version 0 may contain corrupted data: missing constant key if the client
+// was affected by crbug.com/1267391, this function injects constant key if it's
+// not stored and there is exactly one non-constant key. |local_trusted_vault|
+// must not be null and must have |version| set to 0.
+void UpgradeToVersion1(sync_pb::LocalTrustedVault* local_trusted_vault) {
+  DCHECK(local_trusted_vault);
+  DCHECK_EQ(local_trusted_vault->data_version(), 0);
+
+  std::string constant_key_as_proto_string;
+  AssignBytesToProtoString(GetConstantTrustedVaultKey(),
+                           &constant_key_as_proto_string);
+
+  for (sync_pb::LocalTrustedVaultPerUser& per_user_vault :
+       *local_trusted_vault->mutable_user()) {
+    if (per_user_vault.vault_key_size() == 1 &&
+        per_user_vault.vault_key(0).key_material() !=
+            constant_key_as_proto_string) {
+      // Add constant key in the beginning.
+      *per_user_vault.add_vault_key() = per_user_vault.vault_key(0);
+      per_user_vault.mutable_vault_key(0)->set_key_material(
+          constant_key_as_proto_string);
+    }
+  }
+  local_trusted_vault->set_data_version(1);
+}
+
 }  // namespace
 
 StandaloneTrustedVaultBackend::PendingTrustedRecoveryMethod::
@@ -125,8 +153,17 @@
 
 void StandaloneTrustedVaultBackend::ReadDataFromDisk() {
   data_ = ReadEncryptedFile(file_path_);
-  // TODO(crbug.com/1269325): restore the constant key if it was removed due to
-  // the bug when following key rotation.
+  if (data_.user_size() == 0) {
+    // No data, set the current version and omit writing the file.
+    data_.set_data_version(kCurrentLocalTrustedVaultVersion);
+  }
+
+  if (data_.data_version() == 0) {
+    UpgradeToVersion1(&data_);
+    WriteToDisk(data_, file_path_);
+  }
+
+  DCHECK_EQ(data_.data_version(), kCurrentLocalTrustedVaultVersion);
 }
 
 void StandaloneTrustedVaultBackend::FetchKeys(
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc b/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc
index 4de4e1ba..323045d 100644
--- a/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc
+++ b/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc
@@ -21,6 +21,7 @@
 #include "components/os_crypt/os_crypt_mocker.h"
 #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
 #include "components/sync/driver/sync_driver_switches.h"
+#include "components/sync/trusted_vault/proto_string_bytes_conversion.h"
 #include "components/sync/trusted_vault/securebox.h"
 #include "components/sync/trusted_vault/trusted_vault_connection.h"
 #include "components/sync/trusted_vault/trusted_vault_server_constants.h"
@@ -333,6 +334,64 @@
   EXPECT_THAT(proto.user(1).last_vault_key_version(), Eq(9));
 }
 
+TEST_F(StandaloneTrustedVaultBackendTest,
+       ShouldUpgradeToVersion1AndFixMissingConstantKey) {
+  const CoreAccountInfo account_info_1 = MakeAccountInfoWithGaiaId("user1");
+  const CoreAccountInfo account_info_2 = MakeAccountInfoWithGaiaId("user2");
+
+  const std::vector<uint8_t> kKey1 = {0, 1, 2, 3, 4};
+  const std::vector<uint8_t> kKey2 = {1, 2, 3, 4};
+
+  sync_pb::LocalTrustedVault initial_data;
+  sync_pb::LocalTrustedVaultPerUser* user_data1 = initial_data.add_user();
+  sync_pb::LocalTrustedVaultPerUser* user_data2 = initial_data.add_user();
+  user_data1->set_gaia_id(account_info_1.gaia);
+  user_data2->set_gaia_id(account_info_2.gaia);
+  // Mimic |user_data1| to be affected by crbug.com/1267391 and |user_data2| to
+  // be not affected.
+  AssignBytesToProtoString(kKey1,
+                           user_data1->add_vault_key()->mutable_key_material());
+  AssignBytesToProtoString(GetConstantTrustedVaultKey(),
+                           user_data2->add_vault_key()->mutable_key_material());
+  AssignBytesToProtoString(kKey2,
+                           user_data2->add_vault_key()->mutable_key_material());
+
+  std::string encrypted_data;
+  ASSERT_TRUE(OSCrypt::EncryptString(initial_data.SerializeAsString(),
+                                     &encrypted_data));
+  ASSERT_NE(-1, base::WriteFile(file_path(), encrypted_data.c_str(),
+                                encrypted_data.size()));
+
+  // Backend should fix corrupted data and write new state.
+  backend()->ReadDataFromDisk();
+
+  // Read the file from disk.
+  std::string ciphertext;
+  std::string decrypted_content;
+  sync_pb::LocalTrustedVault proto;
+  ASSERT_TRUE(base::ReadFileToString(file_path(), &ciphertext));
+  ASSERT_THAT(ciphertext, Ne(""));
+  ASSERT_TRUE(OSCrypt::DecryptString(ciphertext, &decrypted_content));
+  ASSERT_TRUE(proto.ParseFromString(decrypted_content));
+  ASSERT_THAT(proto.user_size(), Eq(2));
+  // Constant key should be added for the first user.
+  EXPECT_THAT(proto.user(0).vault_key(),
+              ElementsAre(KeyMaterialEq(GetConstantTrustedVaultKey()),
+                          KeyMaterialEq(kKey1)));
+  // Sanity check that state for the second user isn't changed.
+  EXPECT_THAT(proto.user(1).vault_key(),
+              ElementsAre(KeyMaterialEq(GetConstantTrustedVaultKey()),
+                          KeyMaterialEq(kKey2)));
+  EXPECT_THAT(proto.data_version(), Eq(1));
+}
+
+// This test ensures that migration logic in ReadDataFromDisk() doesn't create
+// new file if there wasn't any.
+TEST_F(StandaloneTrustedVaultBackendTest, ShouldNotWriteEmptyData) {
+  backend()->ReadDataFromDisk();
+  EXPECT_FALSE(base::PathExists(file_path()));
+}
+
 TEST_F(StandaloneTrustedVaultBackendTest, ShouldFetchPreviouslyStoredKeys) {
   const CoreAccountInfo account_info_1 = MakeAccountInfoWithGaiaId("user1");
   const CoreAccountInfo account_info_2 = MakeAccountInfoWithGaiaId("user2");
diff --git a/components/test/data/fenced_frames/title1.html b/components/test/data/fenced_frames/title1.html
new file mode 100644
index 0000000..2526072
--- /dev/null
+++ b/components/test/data/fenced_frames/title1.html
@@ -0,0 +1,4 @@
+<html>
+<head></head>
+<body>This page has no title.</body>
+</html>
diff --git a/components/test/data/fenced_frames/title1.html.mock-http-headers b/components/test/data/fenced_frames/title1.html.mock-http-headers
new file mode 100644
index 0000000..263e89c4
--- /dev/null
+++ b/components/test/data/fenced_frames/title1.html.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Supports-Loading-Mode: fenced-frame
\ No newline at end of file
diff --git a/components/translate/content/browser/content_translate_driver.cc b/components/translate/content/browser/content_translate_driver.cc
index 08ef55a..ffd09d8 100644
--- a/components/translate/content/browser/content_translate_driver.cc
+++ b/components/translate/content/browser/content_translate_driver.cc
@@ -58,18 +58,14 @@
 
 ContentTranslateDriver::ContentTranslateDriver(
     content::WebContents& web_contents,
-    content::NavigationController* nav_controller,
     language::UrlLanguageHistogram* url_language_histogram,
     translate::TranslateModelService* translate_model_service)
     : content::WebContentsObserver(&web_contents),
-      navigation_controller_(nav_controller),
       translate_manager_(nullptr),
       max_reload_check_attempts_(kMaxTranslateLoadCheckAttempts),
       next_page_seq_no_(0),
       language_histogram_(url_language_histogram),
-      translate_model_service_(translate_model_service) {
-  DCHECK(navigation_controller_);
-}
+      translate_model_service_(translate_model_service) {}
 
 ContentTranslateDriver::~ContentTranslateDriver() = default;
 
@@ -110,12 +106,12 @@
 // TranslateDriver methods
 
 bool ContentTranslateDriver::IsLinkNavigation() {
-  return navigation_controller_ &&
-         navigation_controller_->GetLastCommittedEntry() &&
-         ui::PageTransitionCoreTypeIs(
-             navigation_controller_->GetLastCommittedEntry()
-                 ->GetTransitionType(),
-             ui::PAGE_TRANSITION_LINK);
+  return web_contents()->GetController().GetLastCommittedEntry() &&
+         ui::PageTransitionCoreTypeIs(web_contents()
+                                          ->GetController()
+                                          .GetLastCommittedEntry()
+                                          ->GetTransitionType(),
+                                      ui::PAGE_TRANSITION_LINK);
 }
 
 void ContentTranslateDriver::OnTranslateEnabledChanged() {
@@ -151,7 +147,7 @@
 }
 
 bool ContentTranslateDriver::IsIncognito() {
-  return navigation_controller_->GetBrowserContext()->IsOffTheRecord();
+  return web_contents()->GetBrowserContext()->IsOffTheRecord();
 }
 
 const std::string& ContentTranslateDriver::GetContentsMimeType() {
@@ -171,7 +167,7 @@
 }
 
 bool ContentTranslateDriver::HasCurrentPage() {
-  return (navigation_controller_->GetLastCommittedEntry() != nullptr);
+  return (web_contents()->GetController().GetLastCommittedEntry() != nullptr);
 }
 
 void ContentTranslateDriver::OpenUrlInNewTab(const GURL& url) {
diff --git a/components/translate/content/browser/content_translate_driver.h b/components/translate/content/browser/content_translate_driver.h
index 5ecf7fd7a..2c4464a 100644
--- a/components/translate/content/browser/content_translate_driver.h
+++ b/components/translate/content/browser/content_translate_driver.h
@@ -21,7 +21,6 @@
 #include "services/metrics/public/cpp/ukm_source_id.h"
 
 namespace content {
-class NavigationController;
 class WebContents;
 }  // namespace content
 
@@ -56,7 +55,6 @@
   };
 
   ContentTranslateDriver(content::WebContents& web_contents,
-                         content::NavigationController* nav_controller,
                          language::UrlLanguageHistogram* url_language_histogram,
                          TranslateModelService* translate_model_service);
 
@@ -151,9 +149,6 @@
       GetLanguageDetectionModelCallback callback,
       bool is_available);
 
-  // The navigation controller of the tab we are associated with.
-  content::NavigationController* navigation_controller_;
-
   TranslateManager* translate_manager_;
 
   base::ObserverList<TranslationObserver, true> translation_observers_;
diff --git a/components/translate/content/browser/per_frame_content_translate_driver.cc b/components/translate/content/browser/per_frame_content_translate_driver.cc
index 6185e8bc..9830860 100644
--- a/components/translate/content/browser/per_frame_content_translate_driver.cc
+++ b/components/translate/content/browser/per_frame_content_translate_driver.cc
@@ -129,10 +129,8 @@
 
 PerFrameContentTranslateDriver::PerFrameContentTranslateDriver(
     content::WebContents& web_contents,
-    content::NavigationController* nav_controller,
     language::UrlLanguageHistogram* url_language_histogram)
     : ContentTranslateDriver(web_contents,
-                             nav_controller,
                              url_language_histogram,
                              /*translate_model_service=*/nullptr) {}
 
diff --git a/components/translate/content/browser/per_frame_content_translate_driver.h b/components/translate/content/browser/per_frame_content_translate_driver.h
index 2a39e9d2..00a6f46 100644
--- a/components/translate/content/browser/per_frame_content_translate_driver.h
+++ b/components/translate/content/browser/per_frame_content_translate_driver.h
@@ -22,7 +22,6 @@
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 
 namespace content {
-class NavigationController;
 class WebContents;
 }  // namespace content
 
@@ -40,7 +39,6 @@
  public:
   PerFrameContentTranslateDriver(
       content::WebContents& web_contents,
-      content::NavigationController* nav_controller,
       language::UrlLanguageHistogram* url_language_histogram);
 
   PerFrameContentTranslateDriver(const PerFrameContentTranslateDriver&) =
diff --git a/components/translate/content/browser/per_frame_content_translate_driver_unittest.cc b/components/translate/content/browser/per_frame_content_translate_driver_unittest.cc
index 0fe4350..e64f80a52 100644
--- a/components/translate/content/browser/per_frame_content_translate_driver_unittest.cc
+++ b/components/translate/content/browser/per_frame_content_translate_driver_unittest.cc
@@ -34,8 +34,7 @@
   void SetUp() override {
     content::RenderViewHostTestHarness::SetUp();
     driver_ = std::make_unique<PerFrameContentTranslateDriver>(
-        *web_contents(), &(web_contents()->GetController()),
-        nullptr /* url_language_histogram */);
+        *web_contents(), nullptr /* url_language_histogram */);
     driver_->AddLanguageDetectionObserver(&observer_);
   }
 
diff --git a/components/update_client/update_client.h b/components/update_client/update_client.h
index 8b409aba..f4bb18a 100644
--- a/components/update_client/update_client.h
+++ b/components/update_client/update_client.h
@@ -348,6 +348,10 @@
   // An indicator sent to the server to advise whether it may perform a version
   // downgrade of this item.
   bool rollback_allowed = false;
+
+  // An indicator sent to the server to advise whether it may perform an
+  // over-install on this item.
+  bool same_version_update_allowed = false;
 };
 
 // Called when a non-blocking call of UpdateClient completes.
diff --git a/components/variations/service/variations_safe_mode_constants.cc b/components/variations/service/variations_safe_mode_constants.cc
index 61a8cef..8b73a77 100644
--- a/components/variations/service/variations_safe_mode_constants.cc
+++ b/components/variations/service/variations_safe_mode_constants.cc
@@ -9,9 +9,9 @@
 const base::FilePath::CharType kVariationsFilename[] =
     FILE_PATH_LITERAL("Variations");
 
-const char kExtendedSafeModeTrial[] = "ExtendedVariationsSafeMode3";
-const char kControlGroup[] = "Control3";
-const char kDefaultGroup[] = "Default3";
-const char kSignalAndWriteViaFileUtilGroup[] = "SignalAndWriteViaFileUtil3";
+const char kExtendedSafeModeTrial[] = "ExtendedVariationsSafeMode4";
+const char kControlGroup[] = "Control4";
+const char kDefaultGroup[] = "Default4";
+const char kSignalAndWriteViaFileUtilGroup[] = "SignalAndWriteViaFileUtil4";
 
 }  // namespace variations
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index bd2aea4..b4d1db8 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -2331,8 +2331,6 @@
   # ChromeOS also defines linux but their memory-monitors conflict.
   if (is_chromeos_ash) {
     sources += [
-      "media/keyboard_mic_registration.cc",
-      "media/keyboard_mic_registration.h",
       "tracing/cros_tracing_agent.cc",
       "tracing/cros_tracing_agent.h",
     ]
@@ -2428,6 +2426,15 @@
       "//components/vector_icons",
       "//content/browser/tracing:resources",
     ]
+    sources += [
+      # Non-Android platforms that don't presently support
+      # enable_screen_capture, like Fuchsia, nevertheless compile
+      # these files. This follows the pattern of #ifdef-ing around Android
+      # to restrict APK-size, but not introducing the additional complexity
+      # this produces for other feature/platform pairs.
+      "media/capture/crop_id_web_contents_helper.cc",
+      "media/capture/crop_id_web_contents_helper.h",
+    ]
   }
 
   # Desktop/Window/WebContents screen capture implementations, conditionally
diff --git a/content/browser/accessibility/accessibility_tools_utils_mac.mm b/content/browser/accessibility/accessibility_tools_utils_mac.mm
index d325f5a..96fdbd5 100644
--- a/content/browser/accessibility/accessibility_tools_utils_mac.mm
+++ b/content/browser/accessibility/accessibility_tools_utils_mac.mm
@@ -57,6 +57,7 @@
        NSAccessibilityMathOverAttribute,
        NSAccessibilityMathPostscriptsAttribute,
        NSAccessibilityMathPrescriptsAttribute,
+       NSAccessibilityRequiredAttributeChrome,
        NSAccessibilityRoleDescriptionAttribute},
       NSStringComparator());
 
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index a78b3f1..4f02ac6 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -930,10 +930,6 @@
   return text;
 }
 
-std::vector<int> BrowserAccessibility::GetLineStartOffsets() const {
-  return node()->GetOrComputeLineStartOffsets();
-}
-
 BrowserAccessibility::AXPosition BrowserAccessibility::CreatePositionAt(
     int offset,
     ax::mojom::TextAffinity affinity) const {
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index e8f851c6..ed3edd11 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -380,9 +380,6 @@
   // non-leaf node.
   AXPosition CreatePositionForSelectionAt(int offset) const;
 
-  // Gets the text offsets where new lines start.
-  std::vector<int> GetLineStartOffsets() const;
-
   std::u16string GetNameAsString16() const;
 
   // `AXPlatformNodeDelegate` implementation.
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.h b/content/browser/accessibility/browser_accessibility_cocoa.h
index 17b3f0b..95c6aed 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.h
+++ b/content/browser/accessibility/browser_accessibility_cocoa.h
@@ -172,7 +172,6 @@
 @property(nonatomic, readonly) NSString* orientation;
 @property(nonatomic, readonly) id parent;
 @property(nonatomic, readonly) NSValue* position;
-@property(nonatomic, readonly) NSNumber* required;
 // A string indicating the role of this object as far as accessibility
 // is concerned.
 @property(nonatomic, readonly) NSString* role;
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index d6e678a..9484f612 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -715,21 +715,6 @@
 
 }  // namespace content
 
-#if defined(MAC_OS_X_VERSION_10_12) && \
-    (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12)
-#warning NSAccessibilityRequiredAttributeChrome \
-  should be removed since the deployment target is >= 10.12
-#endif
-
-// The following private WebKit accessibility attribute became public in 10.12,
-// but it can't be used on all OS because it has availability of 10.12. Instead,
-// define a similarly named constant with the "Chrome" suffix, and the same
-// string. This is used as the key to a dictionary, so string-comparison will
-// work.
-extern "C" {
-NSString* const NSAccessibilityRequiredAttributeChrome = @"AXRequired";
-}
-
 // Not defined in current versions of library, but may be in the future:
 #ifndef NSAccessibilityLanguageAttribute
 #define NSAccessibilityLanguageAttribute @"AXLanguage"
@@ -841,7 +826,6 @@
       {NSAccessibilityOwnsAttribute, @"owns"},
       {NSAccessibilityParentAttribute, @"parent"},
       {NSAccessibilityPositionAttribute, @"position"},
-      {NSAccessibilityRequiredAttributeChrome, @"required"},
       {NSAccessibilityRoleAttribute, @"role"},
       {NSAccessibilityRowHeaderUIElementsAttribute, @"rowHeaders"},
       {NSAccessibilityRowIndexRangeAttribute, @"rowIndexRange"},
@@ -1489,11 +1473,12 @@
   DCHECK(!caretPosition->IsNullPosition())
       << "Calling HasVisibleCaretOrSelection() should have ensured that there "
          "is a valid selection focus inside the current object.";
-  const std::vector<int> lineBreaks = _owner->GetLineStartOffsets();
+  const std::vector<int> lineStarts =
+      _owner->GetIntListAttribute(ax::mojom::IntListAttribute::kLineStarts);
   auto iterator =
-      std::upper_bound(lineBreaks.begin(), lineBreaks.end(),
+      std::lower_bound(lineStarts.begin(), lineStarts.end(),
                        caretPosition->AsTextPosition()->text_offset());
-  return @(std::distance(lineBreaks.begin(), iterator));
+  return @(std::distance(lineStarts.begin(), iterator));
 }
 
 // Returns whether or not this node should be ignored in the
@@ -1682,12 +1667,6 @@
   return [NSValue valueWithPoint:pointInScreen];
 }
 
-- (NSNumber*)required {
-  if (![self instanceActive])
-    return nil;
-  return @(GetState(_owner, ax::mojom::State::kRequired));
-}
-
 // Returns an enum indicating the role from owner_.
 // internal
 - (ax::mojom::Role)internalRole {
@@ -2498,10 +2477,11 @@
 - (id)AXLineForIndex:(id)parameter {
   DCHECK([parameter isKindOfClass:[NSNumber class]]);
   int lineIndex = [(NSNumber*)parameter intValue];
-  const std::vector<int> lineBreaks = _owner->GetLineStartOffsets();
+  const std::vector<int> lineStarts =
+      _owner->GetIntListAttribute(ax::mojom::IntListAttribute::kLineStarts);
   auto iterator =
-      std::upper_bound(lineBreaks.begin(), lineBreaks.end(), lineIndex);
-  return @(std::distance(lineBreaks.begin(), iterator));
+      std::lower_bound(lineStarts.begin(), lineStarts.end(), lineIndex);
+  return @(std::distance(lineStarts.begin(), iterator));
 }
 
 - (id)AXRangeForLine:(id)parameter {
@@ -2510,15 +2490,17 @@
     return nil;
 
   int lineIndex = [(NSNumber*)parameter intValue];
-  const std::vector<int> lineBreaks = _owner->GetLineStartOffsets();
+  const std::vector<int> lineStarts =
+      _owner->GetIntListAttribute(ax::mojom::IntListAttribute::kLineStarts);
   std::u16string value = _owner->GetValueForControl();
   int valueLength = static_cast<int>(value.size());
 
-  int lineCount = static_cast<int>(lineBreaks.size()) + 1;
+  int lineCount = static_cast<int>(lineStarts.size());
   if (lineIndex < 0 || lineIndex >= lineCount)
     return nil;
-  int start = (lineIndex > 0) ? lineBreaks[lineIndex - 1] : 0;
-  int end = (lineIndex < (lineCount - 1)) ? lineBreaks[lineIndex] : valueLength;
+  int start = lineStarts[lineIndex];
+  int end =
+      (lineIndex < (lineCount - 1)) ? lineStarts[lineIndex + 1] : valueLength;
   return [NSValue valueWithRange:NSMakeRange(start, end - start)];
 }
 
@@ -2720,22 +2702,24 @@
       return nil;
 
     int textOffset = position->AsTextPosition()->text_offset();
-    const std::vector<int> lineBreaks = _owner->GetLineStartOffsets();
+    const std::vector<int> lineStarts =
+        _owner->GetIntListAttribute(ax::mojom::IntListAttribute::kLineStarts);
     const auto iterator =
-        std::upper_bound(lineBreaks.begin(), lineBreaks.end(), textOffset);
-    return @(std::distance(lineBreaks.begin(), iterator));
+        std::lower_bound(lineStarts.begin(), lineStarts.end(), textOffset);
+    return @(std::distance(lineStarts.begin(), iterator));
   }
 
   if ([attribute
           isEqualToString:
               NSAccessibilityTextMarkerRangeForLineParameterizedAttribute]) {
     int lineIndex = [(NSNumber*)parameter intValue];
-    const std::vector<int> lineBreaks = _owner->GetLineStartOffsets();
-    int lineCount = static_cast<int>(lineBreaks.size()) + 1;
+    const std::vector<int> lineStarts =
+        _owner->GetIntListAttribute(ax::mojom::IntListAttribute::kLineStarts);
+    int lineCount = static_cast<int>(lineStarts.size());
     if (lineIndex < 0 || lineIndex >= lineCount)
       return nil;
 
-    int lineStartOffset = (lineIndex > 0) ? lineBreaks[lineIndex - 1] : 0;
+    int lineStartOffset = lineStarts[lineIndex];
     BrowserAccessibility::AXPosition lineStartPosition = CreateTextPosition(
         *_owner, lineStartOffset, ax::mojom::TextAffinity::kDownstream);
     if (lineStartPosition->IsNullPosition())
@@ -3361,13 +3345,6 @@
     [ret addObject:NSAccessibilityOrientationAttribute];
   }
 
-  // Anything focusable or any control:
-  if (_owner->HasIntAttribute(ax::mojom::IntAttribute::kRestriction) ||
-      _owner->HasIntAttribute(ax::mojom::IntAttribute::kInvalidState) ||
-      _owner->HasState(ax::mojom::State::kFocusable)) {
-    [ret addObject:@"AXRequired"];
-  }
-
   // TODO(accessibility) What nodes should language be exposed on given new
   // auto detection features?
   //
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index c250872..44a0d22 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/scoped_observation.h"
 #include "build/build_config.h"
diff --git a/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc b/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
index 94c413f0..3089653 100644
--- a/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
@@ -229,6 +229,10 @@
   RunTypedTest<kMacAttributes>("ax-math-under.html");
 }
 
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest, AXRequired) {
+  RunTypedTest<kMacAttributes>("ax-required.html");
+}
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest, SelectAllTextarea) {
   RunTypedTest<kMacSelection>("selectall-textarea.html");
 }
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 5f227388..5b849f96 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -166,6 +166,26 @@
   }
 };
 
+class DumpAccessibilityTreeWithLayoutNGBlockFragmentationTest
+    : public DumpAccessibilityTreeTest {
+ public:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    DumpAccessibilityTreeTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
+                                    "LayoutNGBlockFragmentation");
+  }
+};
+
+class DumpAccessibilityTreeWithoutLayoutNGBlockFragmentationTest
+    : public DumpAccessibilityTreeTest {
+ public:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    DumpAccessibilityTreeTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitchASCII(switches::kDisableBlinkFeatures,
+                                    "LayoutNGBlockFragmentation");
+  }
+};
+
 // Parameterize the tests so that each test-pass is run independently.
 struct DumpAccessibilityTreeTestPassToString {
   std::string operator()(
@@ -192,6 +212,18 @@
     ::testing::ValuesIn(DumpAccessibilityTestHelper::TreeTestPasses()),
     DumpAccessibilityTreeTestPassToString());
 
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    DumpAccessibilityTreeWithLayoutNGBlockFragmentationTest,
+    ::testing::ValuesIn(DumpAccessibilityTestHelper::TreeTestPasses()),
+    DumpAccessibilityTreeTestPassToString());
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    DumpAccessibilityTreeWithoutLayoutNGBlockFragmentationTest,
+    ::testing::ValuesIn(DumpAccessibilityTestHelper::TreeTestPasses()),
+    DumpAccessibilityTreeTestPassToString());
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityCSSAltText) {
   RunCSSTest(FILE_PATH_LITERAL("alt-text.html"));
 }
@@ -291,10 +323,18 @@
   RunCSSTest(FILE_PATH_LITERAL("marker-hyphens.html"));
 }
 
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityCSSMarkerCrash) {
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeWithLayoutNGBlockFragmentationTest,
+                       AccessibilityCSSMarkerCrash) {
   RunCSSTest(FILE_PATH_LITERAL("marker-crash.html"));
 }
 
+IN_PROC_BROWSER_TEST_P(
+    DumpAccessibilityTreeWithoutLayoutNGBlockFragmentationTest,
+    AccessibilityCSSMarkerCrash) {
+  RunCSSTest(
+      FILE_PATH_LITERAL("marker-crash-without-layout-ng-block-frag.html"));
+}
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
                        AccessibilityCSSTextOverflowEllipsis) {
   RunCSSTest(FILE_PATH_LITERAL("text-overflow-ellipsis.html"));
diff --git a/content/browser/android/nfc_host_browsertest.cc b/content/browser/android/nfc_host_browsertest.cc
index 3faedd0..ca05edf 100644
--- a/content/browser/android/nfc_host_browsertest.cc
+++ b/content/browser/android/nfc_host_browsertest.cc
@@ -57,7 +57,7 @@
   )"));
 
   // Ensure that fenced frame insertion cannot close the NFC connection.
-  GURL inner_url(https_server_.GetURL("/title2.html"));
+  GURL inner_url(https_server_.GetURL("/fenced_frames/title1.html"));
   RenderFrameHost* fenced_frame_host = fenced_frame_helper_.CreateFencedFrame(
       web_contents()->GetMainFrame(), inner_url);
   EXPECT_NE(nullptr, fenced_frame_host);
diff --git a/content/browser/attribution_reporting/attribution_host_utils.h b/content/browser/attribution_reporting/attribution_host_utils.h
index 52cb52f..e90105f 100644
--- a/content/browser/attribution_reporting/attribution_host_utils.h
+++ b/content/browser/attribution_reporting/attribution_host_utils.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_HOST_UTILS_H_
 #define CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_HOST_UTILS_H_
 
+#include "base/compiler_specific.h"
 #include "content/browser/attribution_reporting/storable_source.h"
 #include "content/common/content_export.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/content/browser/attribution_reporting/attribution_test_utils.h b/content/browser/attribution_reporting/attribution_test_utils.h
index abee7c2..9640cba 100644
--- a/content/browser/attribution_reporting/attribution_test_utils.h
+++ b/content/browser/attribution_reporting/attribution_test_utils.h
@@ -10,6 +10,7 @@
 #include <iosfwd>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/guid.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/observer_list.h"
diff --git a/content/browser/back_forward_cache_basics_browsertest.cc b/content/browser/back_forward_cache_basics_browsertest.cc
new file mode 100644
index 0000000..431b0570
--- /dev/null
+++ b/content/browser/back_forward_cache_basics_browsertest.cc
@@ -0,0 +1,1645 @@
+// 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 "content/browser/back_forward_cache_browsertest.h"
+
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/site_isolation_policy.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/navigation_handle_observer.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "content/public/test/url_loader_interceptor.h"
+#include "content/shell/browser/shell.h"
+#include "net/test/embedded_test_server/controllable_http_response.h"
+#include "third_party/blink/public/common/frame/event_page_show_persisted.h"
+
+// This file contains back/forward-cache tests that test basic functionality,
+// e.g. navigation, different responses and document structures.
+// Almost everything in here could have been written as a JS-only WPT.
+//
+// When adding tests here consider adding a WPT intead. See
+// third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/README.md
+
+using testing::_;
+using testing::Each;
+using testing::ElementsAre;
+using testing::Not;
+using testing::UnorderedElementsAreArray;
+
+namespace content {
+
+// Navigate from A to B and go back.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Basic) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+  url::Origin origin_a = url::Origin::Create(url_a);
+  url::Origin origin_b = url::Origin::Create(url_b);
+
+  // 1) Navigate to A.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+
+  // 2) Navigate to B.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  RenderFrameHostImpl* rfh_b = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  EXPECT_EQ(rfh_a->GetVisibilityState(), PageVisibilityState::kHidden);
+  EXPECT_EQ(origin_a, rfh_a->GetLastCommittedOrigin());
+  EXPECT_EQ(origin_b, rfh_b->GetLastCommittedOrigin());
+  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
+  EXPECT_EQ(rfh_b->GetVisibilityState(), PageVisibilityState::kVisible);
+
+  // 3) Go back to A.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_FALSE(delete_observer_rfh_b.deleted());
+  EXPECT_EQ(origin_a, rfh_a->GetLastCommittedOrigin());
+  EXPECT_EQ(origin_b, rfh_b->GetLastCommittedOrigin());
+  EXPECT_EQ(rfh_a, current_frame_host());
+  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
+  EXPECT_EQ(rfh_a->GetVisibilityState(), PageVisibilityState::kVisible);
+  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
+  EXPECT_EQ(rfh_b->GetVisibilityState(), PageVisibilityState::kHidden);
+
+  ExpectRestored(FROM_HERE);
+}
+
+// Navigate from A to B and go back.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, BasicDocumentInitiated) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // 1) Navigate to A.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+
+  // 2) Navigate to B.
+  ASSERT_TRUE(NavigateToURLFromRenderer(shell(), url_b));
+  RenderFrameHostImpl* rfh_b = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
+
+  // The two pages are using different BrowsingInstances.
+  EXPECT_FALSE(rfh_a->GetSiteInstance()->IsRelatedSiteInstance(
+      rfh_b->GetSiteInstance()));
+
+  // 3) Go back to A.
+  EXPECT_TRUE(ExecJs(shell(), "history.back();"));
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_FALSE(delete_observer_rfh_b.deleted());
+  EXPECT_EQ(rfh_a, current_frame_host());
+  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
+
+  ExpectRestored(FROM_HERE);
+}
+
+// Navigate from back and forward repeatedly.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       NavigateBackForwardRepeatedly) {
+  // Do not check for unexpected messages because the input task queue is not
+  // currently frozen, causing flakes in this test: crbug.com/1099395.
+  DoNotFailForUnexpectedMessagesWhileCached();
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // 1) Navigate to A.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+
+  // 2) Navigate to B.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  RenderFrameHostImpl* rfh_b = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
+
+  // 3) Go back to A.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+
+  EXPECT_EQ(rfh_a, current_frame_host());
+  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
+
+  ExpectRestored(FROM_HERE);
+
+  // 4) Go forward to B.
+  ASSERT_TRUE(HistoryGoForward(web_contents()));
+
+  EXPECT_EQ(rfh_b, current_frame_host());
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
+
+  ExpectRestored(FROM_HERE);
+
+  // 5) Go back to A.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+
+  EXPECT_EQ(rfh_a, current_frame_host());
+  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
+
+  ExpectRestored(FROM_HERE);
+
+  // 6) Go forward to B.
+  ASSERT_TRUE(HistoryGoForward(web_contents()));
+
+  EXPECT_EQ(rfh_b, current_frame_host());
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
+
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_FALSE(delete_observer_rfh_b.deleted());
+
+  ExpectRestored(FROM_HERE);
+}
+
+// The current page can't enter the BackForwardCache if another page can script
+// it. This can happen when one document opens a popup using window.open() for
+// instance. It prevents the BackForwardCache from being used.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WindowOpen) {
+  // This test assumes cross-site navigation staying in the same
+  // BrowsingInstance to use a different SiteInstance. Otherwise, it will
+  // timeout at step 2).
+  if (!SiteIsolationPolicy::UseDedicatedProcessesForAllSites())
+    return;
+
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // 1) Navigate to A and open a popup.
+  ASSERT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+  EXPECT_EQ(1u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
+  Shell* popup = OpenPopup(rfh_a.get(), url_a, "");
+  EXPECT_EQ(2u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
+
+  // 2) Navigate to B. The previous document can't enter the BackForwardCache,
+  // because of the popup.
+  ASSERT_TRUE(NavigateToURLFromRenderer(rfh_a.get(), url_b));
+  ASSERT_TRUE(rfh_a.WaitUntilRenderFrameDeleted());
+  RenderFrameHostImplWrapper rfh_b(current_frame_host());
+  EXPECT_EQ(2u, rfh_b->GetSiteInstance()->GetRelatedActiveContentsCount());
+
+  // 3) Go back to A. The previous document can't enter the BackForwardCache,
+  // because of the popup.
+  ASSERT_TRUE(ExecJs(rfh_b.get(), "history.back();"));
+  ASSERT_TRUE(rfh_b.WaitUntilRenderFrameDeleted());
+
+  ExpectNotRestored(
+      {BackForwardCacheMetrics::NotRestoredReason::kRelatedActiveContentsExist,
+       BackForwardCacheMetrics::NotRestoredReason::kBrowsingInstanceNotSwapped},
+      {}, {ShouldSwapBrowsingInstance::kNo_HasRelatedActiveContents}, {}, {},
+      FROM_HERE);
+
+  // 4) Make the popup drop the window.opener connection. It happens when the
+  //    user does an omnibox-initiated navigation, which happens in a new
+  //    BrowsingInstance.
+  RenderFrameHostImplWrapper rfh_a_new(current_frame_host());
+  EXPECT_EQ(2u, rfh_a_new->GetSiteInstance()->GetRelatedActiveContentsCount());
+  ASSERT_TRUE(NavigateToURL(popup, url_b));
+  EXPECT_EQ(1u, rfh_a_new->GetSiteInstance()->GetRelatedActiveContentsCount());
+
+  // 5) Navigate to B again. As the scripting relationship with the popup is
+  // now severed, the current page (|rfh_a_new|) can enter back-forward cache.
+  ASSERT_TRUE(NavigateToURLFromRenderer(rfh_a_new.get(), url_b));
+  EXPECT_FALSE(rfh_a_new.IsRenderFrameDeleted());
+  EXPECT_TRUE(rfh_a_new->IsInBackForwardCache());
+
+  // 6) Go back to A. The current document can finally enter the
+  // BackForwardCache, because it is alone in its BrowsingInstance and has never
+  // been related to any other document.
+  RenderFrameHostImplWrapper rfh_b_new(current_frame_host());
+  ASSERT_TRUE(ExecJs(rfh_b_new.get(), "history.back();"));
+  ASSERT_TRUE(WaitForLoadStop(web_contents()));
+  EXPECT_FALSE(rfh_b_new.IsRenderFrameDeleted());
+  EXPECT_TRUE(rfh_b_new->IsInBackForwardCache());
+}
+
+// A popup will prevent a page from entering BFCache. Test that after closing a
+// popup, the page is not stopped from entering. This tries to close the popup
+// at the last moment.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WindowOpenThenClose) {
+  net::test_server::ControllableHttpResponse response(embedded_test_server(),
+                                                      "/title2.html");
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL("a.test", "/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.test", "/title2.html"));
+
+  // Navigate to A.
+  ASSERT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+  EXPECT_EQ(1u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
+
+  // Open a popup.
+  Shell* popup = OpenPopup(rfh_a.get(), url_a, "");
+  EXPECT_EQ(2u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
+
+  // Start navigating to B, the response will be delayed.
+  TestNavigationObserver observer(web_contents());
+  shell()->LoadURL(url_b);
+
+  // When the request is received, close the popup.
+  response.WaitForRequest();
+  RenderFrameHostImplWrapper rfh_popup(popup->web_contents()->GetMainFrame());
+  ASSERT_TRUE(ExecJs(rfh_popup.get(), "window.close();"));
+  ASSERT_TRUE(rfh_popup.WaitUntilRenderFrameDeleted());
+
+  EXPECT_EQ(1u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
+
+  // Send the response.
+  response.Send(net::HTTP_OK, "text/html", "foo");
+  response.Done();
+  observer.Wait();
+
+  // A is in BFCache.
+  EXPECT_EQ(0u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
+  ASSERT_TRUE(rfh_a->IsInBackForwardCache());
+
+  // Go back.
+  web_contents()->GetController().GoBack();
+  ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+  // A is restored from BFCache.
+  EXPECT_FALSE(rfh_a.IsRenderFrameDeleted());
+  ExpectRestored(FROM_HERE);
+}
+
+// Navigate from A(B) to C and go back.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, BasicIframe) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
+
+  // 1) Navigate to A(B).
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
+
+  // 2) Navigate to C.
+  EXPECT_TRUE(NavigateToURL(shell(), url_c));
+  RenderFrameHostImpl* rfh_c = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_FALSE(delete_observer_rfh_b.deleted());
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
+  EXPECT_FALSE(rfh_c->IsInBackForwardCache());
+
+  // 3) Go back to A(B).
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_FALSE(delete_observer_rfh_b.deleted());
+  EXPECT_FALSE(delete_observer_rfh_c.deleted());
+  EXPECT_EQ(rfh_a, current_frame_host());
+  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
+  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_c->IsInBackForwardCache());
+
+  ExpectRestored(FROM_HERE);
+}
+
+// Similar to BackForwardCacheBrowserTest.SubframeSurviveCache*
+// Test case: a1(b2) -> c3 -> a1(b2)
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeSurviveCache1) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
+
+  std::vector<RenderFrameDeletedObserver*> rfh_observer;
+
+  // 1) Navigate to a1(b2).
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* a1 = current_frame_host();
+  RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
+  RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
+  rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
+  EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
+
+  // 2) Navigate to c3.
+  EXPECT_TRUE(NavigateToURL(shell(), url_c));
+  RenderFrameHostImpl* c3 = current_frame_host();
+  RenderFrameDeletedObserver c3_observer(c3);
+  rfh_observer.push_back(&c3_observer);
+  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
+  EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
+  EXPECT_THAT(c3, Not(InBackForwardCache()));
+
+  // 3) Go back to a1(b2).
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
+  EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
+  EXPECT_THAT(c3, InBackForwardCache());
+
+  // Even after a new IPC round trip with the renderer, b2 must still be alive.
+  EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
+  EXPECT_FALSE(b2_observer.deleted());
+
+  ExpectRestored(FROM_HERE);
+}
+
+// Similar to BackForwardCacheBrowserTest.SubframeSurviveCache*
+// Test case: a1(b2) -> b3 -> a1(b2).
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeSurviveCache2) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  std::vector<RenderFrameDeletedObserver*> rfh_observer;
+
+  // 1) Navigate to a1(b2).
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* a1 = current_frame_host();
+  RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
+  RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
+  rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
+  EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
+
+  // 2) Navigate to b3.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  RenderFrameHostImpl* b3 = current_frame_host();
+  RenderFrameDeletedObserver b3_observer(b3);
+  rfh_observer.push_back(&b3_observer);
+  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
+  EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
+  EXPECT_THAT(b3, Not(InBackForwardCache()));
+
+  // 3) Go back to a1(b2).
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
+  EXPECT_EQ(a1, current_frame_host());
+  EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
+  EXPECT_THAT(b3, InBackForwardCache());
+
+  // Even after a new IPC round trip with the renderer, b2 must still be alive.
+  EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
+  EXPECT_FALSE(b2_observer.deleted());
+
+  ExpectRestored(FROM_HERE);
+}
+
+// Similar to BackForwardCacheBrowserTest.tSubframeSurviveCache*
+// Test case: a1(b2) -> b3(a4) -> a1(b2) -> b3(a4)
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeSurviveCache3) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  GURL url_b(embedded_test_server()->GetURL(
+      "b.com", "/cross_site_iframe_factory.html?b(a)"));
+
+  std::vector<RenderFrameDeletedObserver*> rfh_observer;
+
+  // 1) Navigate to a1(b2).
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* a1 = current_frame_host();
+  RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
+  RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
+  rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
+  EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
+
+  // 2) Navigate to b3(a4)
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  RenderFrameHostImpl* b3 = current_frame_host();
+  RenderFrameHostImpl* a4 = b3->child_at(0)->current_frame_host();
+  RenderFrameDeletedObserver b3_observer(b3), a4_observer(a4);
+  rfh_observer.insert(rfh_observer.end(), {&b3_observer, &a4_observer});
+  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
+  EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
+  EXPECT_THAT(Elements({b3, a4}), Each(Not(InBackForwardCache())));
+  EXPECT_TRUE(ExecJs(a4, "window.alive = 'I am alive';"));
+
+  // 3) Go back to a1(b2).
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
+  EXPECT_EQ(a1, current_frame_host());
+  EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
+  EXPECT_THAT(Elements({b3, a4}), Each(InBackForwardCache()));
+
+  // Even after a new IPC round trip with the renderer, b2 must still be alive.
+  EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
+  EXPECT_FALSE(b2_observer.deleted());
+
+  ExpectRestored(FROM_HERE);
+
+  // 4) Go forward to b3(a4).
+  ASSERT_TRUE(HistoryGoForward(web_contents()));
+  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
+  EXPECT_EQ(b3, current_frame_host());
+  EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
+  EXPECT_THAT(Elements({b3, a4}), Each(Not(InBackForwardCache())));
+
+  // Even after a new IPC round trip with the renderer, a4 must still be alive.
+  EXPECT_EQ("I am alive", EvalJs(a4, "window.alive"));
+  EXPECT_FALSE(a4_observer.deleted());
+
+  ExpectRestored(FROM_HERE);
+}
+
+// Similar to BackForwardCacheBrowserTest.SubframeSurviveCache*
+// Test case: a1(b2) -> b3 -> a4 -> b5 -> a1(b2).
+IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,
+                       SubframeSurviveCache4) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_ab(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  std::vector<RenderFrameDeletedObserver*> rfh_observer;
+
+  // 1) Navigate to a1(b2).
+  EXPECT_TRUE(NavigateToURL(shell(), url_ab));
+  RenderFrameHostImpl* a1 = current_frame_host();
+  RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
+  RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
+  rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
+  EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
+
+  // 2) Navigate to b3.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  RenderFrameHostImpl* b3 = current_frame_host();
+  RenderFrameDeletedObserver b3_observer(b3);
+  rfh_observer.push_back(&b3_observer);
+  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
+  EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
+  EXPECT_THAT(b3, Not(InBackForwardCache()));
+
+  // 3) Navigate to a4.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* a4 = current_frame_host();
+  RenderFrameDeletedObserver a4_observer(a4);
+  rfh_observer.push_back(&a4_observer);
+  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
+
+  // 4) Navigate to b5
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  RenderFrameHostImpl* b5 = current_frame_host();
+  RenderFrameDeletedObserver b5_observer(b5);
+  rfh_observer.push_back(&b5_observer);
+  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
+  EXPECT_THAT(Elements({a1, b2, b3, a4}), Each(InBackForwardCache()));
+  EXPECT_THAT(b5, Not(InBackForwardCache()));
+
+  // 3) Go back to a1(b2).
+  ASSERT_TRUE(HistoryGoToOffset(web_contents(), -3));
+  EXPECT_EQ(a1, current_frame_host());
+  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
+  EXPECT_THAT(Elements({b3, a4, b5}), Each(InBackForwardCache()));
+  EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
+
+  // Even after a new IPC round trip with the renderer, b2 must still be alive.
+  EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
+  EXPECT_FALSE(b2_observer.deleted());
+}
+
+// Check that unload event handlers are not dispatched when the page goes
+// into BackForwardCache.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       ConfirmUnloadEventNotFired) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // 1) Navigate to A.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+
+  // 2) Set unload handler and check the title.
+  EXPECT_TRUE(ExecJs(rfh_a,
+                     "document.title = 'loaded!';"
+                     "window.addEventListener('unload', () => {"
+                     "  document.title = 'unloaded!';"
+                     "});"));
+  {
+    std::u16string title_when_loaded = u"loaded!";
+    TitleWatcher title_watcher(web_contents(), title_when_loaded);
+    EXPECT_EQ(title_watcher.WaitAndGetTitle(), title_when_loaded);
+  }
+
+  // 3) Navigate to B.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  RenderFrameHostImpl* rfh_b = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
+
+  // 4) Go back to A and check the title again.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_FALSE(delete_observer_rfh_b.deleted());
+  EXPECT_EQ(rfh_a, current_frame_host());
+  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
+  {
+    std::u16string title_when_loaded = u"loaded!";
+    TitleWatcher title_watcher(web_contents(), title_when_loaded);
+    EXPECT_EQ(title_watcher.WaitAndGetTitle(), title_when_loaded);
+  }
+}
+
+// TODO(https://crbug.com/1075936) disabled due to flakiness
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       DISABLED_DoesNotCacheIfMainFrameStillLoading) {
+  net::test_server::ControllableHttpResponse response(embedded_test_server(),
+                                                      "/main_document");
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to a page that doesn't finish loading.
+  GURL url(embedded_test_server()->GetURL("a.com", "/main_document"));
+  TestNavigationManager navigation_manager(shell()->web_contents(), url);
+  shell()->LoadURL(url);
+
+  // The navigation starts.
+  EXPECT_TRUE(navigation_manager.WaitForRequestStart());
+  navigation_manager.ResumeNavigation();
+
+  // The server sends the first part of the response and waits.
+  response.WaitForRequest();
+  response.Send(
+      "HTTP/1.1 200 OK\r\n"
+      "Content-Type: text/html; charset=utf-8\r\n"
+      "\r\n"
+      "<html><body> ... ");
+
+  // The navigation finishes while the body is still loading.
+  navigation_manager.WaitForNavigationFinished();
+  RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
+
+  // 2) Navigate away.
+  shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // The page was still loading when we navigated away, so it shouldn't have
+  // been cached.
+  delete_observer_rfh_a.WaitUntilDeleted();
+
+  // 3) Go back.
+  web_contents()->GetController().GoBack();
+  EXPECT_FALSE(WaitForLoadStop(shell()->web_contents()));
+  ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::kLoading}, {},
+                    {}, {}, {}, FROM_HERE);
+}
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       DoesNotCacheLoadingSubframe) {
+  net::test_server::ControllableHttpResponse response(embedded_test_server(),
+                                                      "/controlled");
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to a page with an iframe that loads forever.
+  GURL url(embedded_test_server()->GetURL(
+      "a.com", "/back_forward_cache/controllable_subframe.html"));
+  TestNavigationManager navigation_manager(shell()->web_contents(), url);
+  shell()->LoadURL(url);
+
+  // The navigation finishes while the iframe is still loading.
+  navigation_manager.WaitForNavigationFinished();
+
+  // Wait for the iframe request to arrive, and leave it hanging with no
+  // response.
+  response.WaitForRequest();
+
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+
+  // 2) Navigate away.
+  shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+  // The page should not have been added to cache, since it had a subframe that
+  // was still loading at the time it was navigated away from.
+  delete_observer_rfh_a.WaitUntilDeleted();
+
+  // 3) Go back.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  ExpectNotRestored(
+      {
+          BackForwardCacheMetrics::NotRestoredReason::kLoading,
+          BackForwardCacheMetrics::NotRestoredReason::kSubframeIsNavigating,
+      },
+      {}, {}, {}, {}, FROM_HERE);
+}
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       DoesNotCacheLoadingSubframeOfSubframe) {
+  net::test_server::ControllableHttpResponse response(embedded_test_server(),
+                                                      "/controlled");
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to a page with an iframe that contains yet another iframe, that
+  // hangs while loading.
+  GURL url(embedded_test_server()->GetURL(
+      "a.com", "/back_forward_cache/controllable_subframe_of_subframe.html"));
+  TestNavigationManager navigation_manager(shell()->web_contents(), url);
+  shell()->LoadURL(url);
+
+  // The navigation finishes while the iframe within an iframe is still loading.
+  navigation_manager.WaitForNavigationFinished();
+
+  // Wait for the innermost iframe request to arrive, and leave it hanging with
+  // no response.
+  response.WaitForRequest();
+
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  RenderFrameDeletedObserver delete_rfh_a(rfh_a);
+
+  // 2) Navigate away.
+  shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+  // The page should not have been added to the cache, since it had an iframe
+  // that was still loading at the time it was navigated away from.
+  delete_rfh_a.WaitUntilDeleted();
+
+  // 3) Go back.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  ExpectNotRestored(
+      {
+          BackForwardCacheMetrics::NotRestoredReason::kLoading,
+          BackForwardCacheMetrics::NotRestoredReason::kSubframeIsNavigating,
+      },
+      {}, {}, {}, {}, FROM_HERE);
+}
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIfHttpError) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL error_url(embedded_test_server()->GetURL("a.com", "/page404.html"));
+  GURL url(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // Navigate to an error page.
+  EXPECT_TRUE(NavigateToURL(shell(), error_url));
+  EXPECT_EQ(net::HTTP_NOT_FOUND, current_frame_host()->last_http_status_code());
+  RenderFrameDeletedObserver delete_rfh_a(current_frame_host());
+
+  // Navigate away.
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+
+  // The page did not return 200 (OK), so it shouldn't have been cached.
+  delete_rfh_a.WaitUntilDeleted();
+
+  // Go back.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  ExpectNotRestored(
+      {BackForwardCacheMetrics::NotRestoredReason::kHTTPStatusNotOK}, {}, {},
+      {}, {}, FROM_HERE);
+}
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       DoesNotCacheIfPageUnreachable) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL error_url(embedded_test_server()->GetURL("a.com", "/empty.html"));
+  GURL url(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  std::unique_ptr<URLLoaderInterceptor> url_interceptor =
+      URLLoaderInterceptor::SetupRequestFailForURL(error_url,
+                                                   net::ERR_DNS_TIMED_OUT);
+
+  // Start with a successful navigation to a document.
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+  EXPECT_EQ(net::HTTP_OK, current_frame_host()->last_http_status_code());
+
+  // Navigate to an error page.
+  NavigationHandleObserver observer(shell()->web_contents(), error_url);
+  EXPECT_FALSE(NavigateToURL(shell(), error_url));
+  EXPECT_TRUE(observer.is_error());
+  EXPECT_EQ(net::ERR_DNS_TIMED_OUT, observer.net_error_code());
+  EXPECT_EQ(
+      GURL(kUnreachableWebDataURL),
+      shell()->web_contents()->GetMainFrame()->GetSiteInstance()->GetSiteURL());
+  EXPECT_EQ(net::OK, current_frame_host()->last_http_status_code());
+
+  RenderFrameDeletedObserver delete_rfh_a(current_frame_host());
+
+  // Navigate away.
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+
+  // The page had a networking error, so it shouldn't have been cached.
+  delete_rfh_a.WaitUntilDeleted();
+
+  // Go back.
+  web_contents()->GetController().GoBack();
+  EXPECT_FALSE(WaitForLoadStop(shell()->web_contents()));
+  ExpectNotRestored(
+      {BackForwardCacheMetrics::NotRestoredReason::kHTTPStatusNotOK,
+       BackForwardCacheMetrics::NotRestoredReason::kNoResponseHead},
+      {}, {}, {}, {}, FROM_HERE);
+}
+
+// Tests the events are fired when going back from the cache.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Events) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL(
+      "a.com", "/back_forward_cache/record_events.html"));
+  GURL url_b(embedded_test_server()->GetURL(
+      "b.com", "/back_forward_cache/record_events.html"));
+
+  // 1) Navigate to A.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+
+  // At A, a page-show event is recorded for the first loading.
+  MatchEventList(rfh_a.get(), ListValueOf("window.pageshow"));
+
+  constexpr char kEventPageShowPersisted[] = "Event.PageShow.Persisted";
+
+  content::FetchHistogramsFromChildProcesses();
+  EXPECT_THAT(
+      histogram_tester_.GetAllSamples(kEventPageShowPersisted),
+      testing::UnorderedElementsAre(base::Bucket(
+          static_cast<int>(blink::EventPageShowPersisted::kNoInRenderer), 1)));
+
+  // 2) Navigate to B.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  RenderFrameHostImplWrapper rfh_b(current_frame_host());
+
+  EXPECT_FALSE(rfh_a.IsRenderFrameDeleted());
+  EXPECT_FALSE(rfh_b.IsRenderFrameDeleted());
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
+  // TODO(yuzus): Post message to the frozen page, and make sure that the
+  // messages arrive after the page visibility events, not before them.
+
+  // As |rfh_a| is in back-forward cache, we cannot get the event list of A.
+  // At B, a page-show event is recorded for the first loading.
+  MatchEventList(rfh_b.get(), ListValueOf("window.pageshow"));
+  content::FetchHistogramsFromChildProcesses();
+  EXPECT_THAT(
+      histogram_tester_.GetAllSamples(kEventPageShowPersisted),
+      testing::UnorderedElementsAre(base::Bucket(
+          static_cast<int>(blink::EventPageShowPersisted::kNoInRenderer), 2)));
+
+  // 3) Go back to A. Confirm that expected events are fired.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  EXPECT_FALSE(rfh_a.IsRenderFrameDeleted());
+  EXPECT_FALSE(rfh_b.IsRenderFrameDeleted());
+  EXPECT_EQ(rfh_a.get(), current_frame_host());
+  // visibilitychange events are added twice per each because it is fired for
+  // both window and document.
+  MatchEventList(
+      rfh_a.get(),
+      ListValueOf("window.pageshow", "window.pagehide.persisted",
+                  "document.visibilitychange", "window.visibilitychange",
+                  "document.freeze", "document.resume",
+                  "document.visibilitychange", "window.visibilitychange",
+                  "window.pageshow.persisted"));
+
+  content::FetchHistogramsFromChildProcesses();
+  EXPECT_THAT(
+      histogram_tester_.GetAllSamples(kEventPageShowPersisted),
+      testing::UnorderedElementsAre(
+          base::Bucket(
+              static_cast<int>(blink::EventPageShowPersisted::kNoInRenderer),
+              2),
+          base::Bucket(
+              static_cast<int>(blink::EventPageShowPersisted::kYesInBrowser),
+              1),
+          base::Bucket(
+              static_cast<int>(blink::EventPageShowPersisted::kYesInRenderer),
+              1),
+          base::Bucket(
+              static_cast<int>(
+                  blink::EventPageShowPersisted::kBrowserYesInRenderer),
+              1),
+          base::Bucket(
+              static_cast<int>(
+                  blink::EventPageShowPersisted::kBrowserYesInRendererWithPage),
+              1),
+          base::Bucket(
+              static_cast<int>(
+                  blink::EventPageShowPersisted::
+                      kYesInBrowser_BackForwardCache_WillCommitNavigationToCachedEntry),
+              1),
+          base::Bucket(
+              static_cast<int>(
+                  blink::EventPageShowPersisted::
+                      kYesInBrowser_BackForwardCache_RestoreEntry_Attempt),
+              1),
+          base::Bucket(
+              static_cast<int>(
+                  blink::EventPageShowPersisted::
+                      kYesInBrowser_BackForwardCache_RestoreEntry_Succeed),
+              1),
+          base::Bucket(
+              static_cast<int>(
+                  blink::EventPageShowPersisted::
+                      kYesInBrowser_RenderFrameHostManager_CommitPending),
+              1)));
+}
+
+// Tests the events are fired for subframes when going back from the cache.
+// Test case: a(b) -> c -> a(b)
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, EventsForSubframes) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
+
+  // 1) Navigate to A(B).
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
+  StartRecordingEvents(rfh_a);
+  StartRecordingEvents(rfh_b);
+
+  // 2) Navigate to C.
+  EXPECT_TRUE(NavigateToURL(shell(), url_c));
+  RenderFrameHostImpl* rfh_c = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_FALSE(delete_observer_rfh_b.deleted());
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
+  EXPECT_FALSE(rfh_c->IsInBackForwardCache());
+  // TODO(yuzus): Post message to the frozen page, and make sure that the
+  // messages arrive after the page visibility events, not before them.
+
+  // 3) Go back to A(B). Confirm that expected events are fired on the subframe.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_FALSE(delete_observer_rfh_b.deleted());
+  EXPECT_FALSE(delete_observer_rfh_c.deleted());
+  EXPECT_EQ(rfh_a, current_frame_host());
+  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
+  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_c->IsInBackForwardCache());
+  // visibilitychange events are added twice per each because it is fired for
+  // both window and document.
+  MatchEventList(
+      rfh_a,
+      ListValueOf("window.pagehide.persisted", "document.visibilitychange",
+                  "window.visibilitychange", "document.freeze",
+                  "document.resume", "document.visibilitychange",
+                  "window.visibilitychange", "window.pageshow.persisted"));
+  MatchEventList(
+      rfh_b,
+      ListValueOf("window.pagehide.persisted", "document.visibilitychange",
+                  "window.visibilitychange", "document.freeze",
+                  "document.resume", "document.visibilitychange",
+                  "window.visibilitychange", "window.pageshow.persisted"));
+}
+
+// Tests the events are fired when going back from the cache.
+// Same as: BackForwardCacheBrowserTest.Events, but with a document-initiated
+// navigation. This is a regression test for https://crbug.com/1000324
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       EventsAfterDocumentInitiatedNavigation) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // 1) Navigate to A.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+  StartRecordingEvents(rfh_a);
+
+  // 2) Navigate to B.
+  ASSERT_TRUE(NavigateToURLFromRenderer(shell(), url_b));
+  RenderFrameHostImpl* rfh_b = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
+
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_FALSE(delete_observer_rfh_b.deleted());
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
+  // TODO(yuzus): Post message to the frozen page, and make sure that the
+  // messages arrive after the page visibility events, not before them.
+
+  // 3) Go back to A. Confirm that expected events are fired.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_FALSE(delete_observer_rfh_b.deleted());
+  EXPECT_EQ(rfh_a, current_frame_host());
+  // visibilitychange events are added twice per each because it is fired for
+  // both window and document.
+  MatchEventList(
+      rfh_a,
+      ListValueOf("window.pagehide.persisted", "document.visibilitychange",
+                  "window.visibilitychange", "document.freeze",
+                  "document.resume", "document.visibilitychange",
+                  "window.visibilitychange", "window.pageshow.persisted"));
+}
+
+// Track the events dispatched when a page is deemed ineligible for back-forward
+// cache after we've dispatched the 'pagehide' event with persisted set to true.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       EventsForPageIneligibleAfterPagehidePersisted) {
+  ASSERT_TRUE(CreateHttpsServer()->Start());
+  GURL url_1(https_server()->GetURL("a.com", "/title1.html"));
+  GURL url_2(https_server()->GetURL("a.com", "/title2.html"));
+
+  // 1) Navigate to |url_1|.
+  EXPECT_TRUE(NavigateToURL(shell(), url_1));
+  RenderFrameHostImpl* rfh_1 = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_1(rfh_1);
+  // 2) Use BroadcastChannel (a non-sticky blocklisted feature), so that we
+  // would still do a RFH swap on same-site navigation and fire the 'pagehide'
+  // event during commit of the new page with 'persisted' set to true, but the
+  // page will not be eligible for back-forward cache after commit.
+  EXPECT_TRUE(ExecJs(rfh_1, "window.foo = new BroadcastChannel('foo');"));
+
+  EXPECT_TRUE(ExecJs(rfh_1, R"(
+    window.onpagehide = (e) => {
+      if (e.persisted) {
+        window.domAutomationController.send('pagehide.persisted');
+      }
+    }
+    document.onvisibilitychange = () => {
+      if (document.visibilityState == 'hidden') {
+        window.domAutomationController.send('visibilitychange.hidden');
+      }
+    }
+    window.onunload = () => {
+      window.domAutomationController.send('unload');
+    }
+  )"));
+
+  DOMMessageQueue dom_message_queue(shell()->web_contents());
+  // 3) Navigate to |url_2|.
+  EXPECT_TRUE(NavigateToURL(shell(), url_2));
+  // |rfh_1| will not get into the back-forward cache and eventually get deleted
+  // because it uses a blocklisted feature.
+  delete_observer_rfh_1.WaitUntilDeleted();
+
+  // Only the pagehide and visibilitychange events will be dispatched.
+  int num_messages_received = 0;
+  std::string expected_messages[] = {"\"pagehide.persisted\"",
+                                     "\"visibilitychange.hidden\""};
+  std::string message;
+  while (dom_message_queue.PopMessage(&message)) {
+    EXPECT_EQ(expected_messages[num_messages_received], message);
+    num_messages_received++;
+  }
+  EXPECT_EQ(num_messages_received, 2);
+}
+
+// Track the events dispatched when a page is deemed ineligible for back-forward
+// cache before we've dispatched the pagehide event on it.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       EventsForPageIneligibleBeforePagehide) {
+  ASSERT_TRUE(CreateHttpsServer()->Start());
+  GURL url_1(https_server()->GetURL("a.com", "/title1.html"));
+  GURL url_2(https_server()->GetURL("b.com", "/title2.html"));
+
+  // 1) Navigate to |url_1|.
+  EXPECT_TRUE(NavigateToURL(shell(), url_1));
+  RenderFrameHostImpl* rfh_1 = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_1(rfh_1);
+  // 2) Use a dummy sticky blocklisted feature, so that the page is known to be
+  // ineligible for bfcache at commit time, before we dispatch pagehide event.
+  rfh_1->UseDummyStickyBackForwardCacheDisablingFeatureForTesting();
+
+  EXPECT_TRUE(ExecJs(rfh_1, R"(
+    window.onpagehide = (e) => {
+      if (!e.persisted) {
+        window.domAutomationController.send('pagehide.not_persisted');
+      }
+    }
+    document.onvisibilitychange = () => {
+      if (document.visibilityState == 'hidden') {
+        window.domAutomationController.send('visibilitychange.hidden');
+      }
+    }
+    window.onunload = () => {
+      window.domAutomationController.send('unload');
+    }
+  )"));
+
+  DOMMessageQueue dom_message_queue(shell()->web_contents());
+  // 3) Navigate to |url_2|.
+  EXPECT_TRUE(NavigateToURL(shell(), url_2));
+  // |rfh_1| will not get into the back-forward cache and eventually get deleted
+  // because it uses a blocklisted feature.
+  delete_observer_rfh_1.WaitUntilDeleted();
+
+  // "pagehide", "visibilitychange", and "unload" events will be dispatched.
+  int num_messages_received = 0;
+  std::string expected_messages[] = {"\"pagehide.not_persisted\"",
+                                     "\"visibilitychange.hidden\"",
+                                     "\"unload\""};
+  std::string message;
+  while (dom_message_queue.PopMessage(&message)) {
+    EXPECT_EQ(expected_messages[num_messages_received], message);
+    num_messages_received++;
+  }
+  EXPECT_EQ(num_messages_received, 3);
+}
+
+IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,
+                       CanCacheMultiplesPagesOnSameDomain) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_b2(embedded_test_server()->GetURL("b.com", "/title1.html"));
+  GURL url_a3(embedded_test_server()->GetURL("a.com", "/title2.html"));
+  GURL url_b4(embedded_test_server()->GetURL("b.com", "/title2.html"));
+
+  // 1) Navigate to A1.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a1));
+  RenderFrameHostImpl* rfh_a1 = current_frame_host();
+
+  // 2) Navigate to B2.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b2));
+  RenderFrameHostImpl* rfh_b2 = current_frame_host();
+  EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
+
+  // 3) Navigate to A3.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a3));
+  RenderFrameHostImpl* rfh_a3 = current_frame_host();
+  EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
+  // A1 and A3 shouldn't be treated as the same site instance.
+  EXPECT_NE(rfh_a1->GetSiteInstance(), rfh_a3->GetSiteInstance());
+
+  // 4) Navigate to B4.
+  // Make sure we can store A1 and A3 in the cache at the same time.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b4));
+  RenderFrameHostImpl* rfh_b4 = current_frame_host();
+  EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_a3->IsInBackForwardCache());
+
+  // 5) Go back to A3.
+  // Make sure we can restore A3, while A1 remains in the cache.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_b4->IsInBackForwardCache());
+  EXPECT_EQ(rfh_a3, current_frame_host());
+  // B2 and B4 shouldn't be treated as the same site instance.
+  EXPECT_NE(rfh_b2->GetSiteInstance(), rfh_b4->GetSiteInstance());
+
+  // 6) Do a history navigation back to A1.
+  // Make sure we can restore A1, while coming from A3.
+  ASSERT_TRUE(HistoryGoToIndex(web_contents(), 0));
+  EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_b4->IsInBackForwardCache());
+  EXPECT_TRUE(rfh_a3->IsInBackForwardCache());
+  EXPECT_EQ(rfh_a1, current_frame_host());
+}
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Encoding) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL(
+      "a.com", "/back_forward_cache/charset_windows-1250.html"));
+  GURL url_b(embedded_test_server()->GetURL(
+      "b.com", "/back_forward_cache/charset_utf-8.html"));
+  url::Origin origin_a = url::Origin::Create(url_a);
+  url::Origin origin_b = url::Origin::Create(url_b);
+
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  EXPECT_EQ(web_contents()->GetEncoding(), "windows-1250");
+
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  EXPECT_EQ(web_contents()->GetEncoding(), "UTF-8");
+
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  EXPECT_EQ(web_contents()->GetEncoding(), "windows-1250");
+}
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       DoesNotCacheCrossSiteHttpPost) {
+  SetupCrossSiteRedirector(embedded_test_server());
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // Note we do a cross-site post because same-site navigations of any kind
+  // aren't cached currently.
+  GURL form_url(embedded_test_server()->GetURL(
+      "a.com", "/form_that_posts_cross_site.html"));
+  GURL redirect_target_url(embedded_test_server()->GetURL("x.com", "/echoall"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // Navigate to the page with form that posts via 307 redirection to
+  // |redirect_target_url| (cross-site from |form_url|).
+  EXPECT_TRUE(NavigateToURL(shell(), form_url));
+
+  // Submit the form.
+  TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
+  EXPECT_TRUE(ExecJs(shell(), "document.getElementById('text-form').submit()"));
+  form_post_observer.Wait();
+
+  // Verify that we arrived at the expected, redirected location.
+  EXPECT_EQ(redirect_target_url,
+            shell()->web_contents()->GetLastCommittedURL());
+  RenderFrameDeletedObserver delete_observer_rfh(current_frame_host());
+
+  // Navigate away. |redirect_target_url|'s page should not be cached.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  delete_observer_rfh.WaitUntilDeleted();
+}
+
+// On windows, the expected value is off by ~20ms. In order to get the
+// feature out to canary, the test is disabled for WIN.
+// TODO(crbug.com/1022191): Fix this for Win.
+// TODO(crbug.com/1211428): Flaky on other platforms.
+// Make sure we are exposing the duration between back navigation's
+// navigationStart and the page's original navigationStart through pageshow
+// event's timeStamp, and that we aren't modifying
+// performance.timing.navigationStart.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DISABLED_NavigationStart) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL(
+      "a.com", "/back_forward_cache/record_navigation_start_time_stamp.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // 1) Navigate to A.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+
+  double initial_page_show_time_stamp =
+      EvalJs(shell(), "window.initialPageShowTimeStamp").ExtractDouble();
+  EXPECT_DOUBLE_EQ(
+      initial_page_show_time_stamp,
+      EvalJs(shell(), "window.latestPageShowTimeStamp").ExtractDouble());
+  double initial_navigation_start =
+      EvalJs(shell(), "window.initialNavigationStart").ExtractDouble();
+
+  // 2) Navigate to B. A should be in the back forward cache.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+
+  // 3) Navigate back and expect everything to be restored.
+  NavigationHandleObserver observer(web_contents(), url_a);
+  base::TimeTicks time_before_navigation = base::TimeTicks::Now();
+  double js_time_before_navigation =
+      EvalJs(shell(), "performance.now()").ExtractDouble();
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  base::TimeTicks time_after_navigation = base::TimeTicks::Now();
+  double js_time_after_navigation =
+      EvalJs(shell(), "performance.now()").ExtractDouble();
+
+  // The navigation start time should be between the time we saved just before
+  // calling GoBack() and the time we saved just after calling GoBack().
+  base::TimeTicks back_navigation_start = observer.navigation_start();
+  EXPECT_LT(time_before_navigation, back_navigation_start);
+  EXPECT_GT(time_after_navigation, back_navigation_start);
+
+  // Check JS values. window.initialNavigationStart should not change.
+  EXPECT_DOUBLE_EQ(
+      initial_navigation_start,
+      EvalJs(shell(), "window.initialNavigationStart").ExtractDouble());
+  // performance.timing.navigationStart should not change.
+  EXPECT_DOUBLE_EQ(
+      initial_navigation_start,
+      EvalJs(shell(), "performance.timing.navigationStart").ExtractDouble());
+  // window.initialPageShowTimeStamp should not change.
+  EXPECT_DOUBLE_EQ(
+      initial_page_show_time_stamp,
+      EvalJs(shell(), "window.initialPageShowTimeStamp").ExtractDouble());
+  // window.latestPageShowTimeStamp should be updated with the timestamp of the
+  // last pageshow event, which occurs after the page is restored. This should
+  // be greater than the initial pageshow event's timestamp.
+  double latest_page_show_time_stamp =
+      EvalJs(shell(), "window.latestPageShowTimeStamp").ExtractDouble();
+  EXPECT_LT(initial_page_show_time_stamp, latest_page_show_time_stamp);
+
+  // |latest_page_show_time_stamp| should be the duration between initial
+  // navigation start and |back_navigation_start|. Note that since
+  // performance.timing.navigationStart returns a 64-bit integer instead of
+  // double, we might be losing somewhere between 0 to 1 milliseconds of
+  // precision, hence the usage of EXPECT_NEAR.
+  EXPECT_NEAR(
+      (back_navigation_start - base::TimeTicks::UnixEpoch()).InMillisecondsF(),
+      latest_page_show_time_stamp + initial_navigation_start, 1.0);
+  // Expect that the back navigation start value calculated from the JS results
+  // are between time taken before & after navigation, just like
+  // |before_navigation_start|.
+  EXPECT_LT(js_time_before_navigation, latest_page_show_time_stamp);
+  EXPECT_GT(js_time_after_navigation, latest_page_show_time_stamp);
+}
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       CanUseCacheWhenNavigatingAwayToErrorPage) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL error_url(embedded_test_server()->GetURL("b.com", "/empty.html"));
+  auto url_interceptor = URLLoaderInterceptor::SetupRequestFailForURL(
+      error_url, net::ERR_DNS_TIMED_OUT);
+
+  // 1) Navigate to A.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+
+  // 2) Navigate to an error page and expect the old page to be stored in
+  // bfcache.
+  EXPECT_FALSE(NavigateToURL(shell(), error_url));
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+
+  // 3) Navigate back and expect the page to be restored from bfcache.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+}
+
+// RenderFrameHostImpl::coep_reporter() must be preserved when doing a back
+// navigation using the BackForwardCache.
+// Regression test for https://crbug.com/1102285.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CoepReporter) {
+  ASSERT_TRUE(CreateHttpsServer()->Start());
+  GURL url_a(https_server()->GetURL("a.com",
+                                    "/set-header?"
+                                    "Cross-Origin-Embedder-Policy-Report-Only: "
+                                    "require-corp; report-to%3d\"a\""));
+  GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
+
+  // Navigate to a document that set RenderFrameHostImpl::coep_reporter().
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  EXPECT_TRUE(rfh_a->coep_reporter());
+
+  // Navigate away and back using the BackForwardCache. The
+  // RenderFrameHostImpl::coep_reporter() must still be there.
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_EQ(rfh_a, current_frame_host());
+
+  EXPECT_TRUE(rfh_a->coep_reporter());
+}
+
+// RenderFrameHostImpl::coop_reporter() must be preserved when doing a back
+// navigation using the BackForwardCache.
+// Regression test for https://crbug.com/1102285.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CoopReporter) {
+  ASSERT_TRUE(CreateHttpsServer()->Start());
+  GURL url_a(https_server()->GetURL("a.com",
+                                    "/set-header?"
+                                    "Cross-Origin-Opener-Policy-Report-Only: "
+                                    "same-origin; report-to%3d\"a\""));
+  GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
+
+  // Navigate to a document that set RenderFrameHostImpl::coop_reporter().
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  EXPECT_TRUE(rfh_a->coop_access_report_manager()->coop_reporter());
+
+  // Navigate away and back using the BackForwardCache. The
+  // RenderFrameHostImpl::coop_reporter() must still be there.
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_EQ(rfh_a, current_frame_host());
+
+  EXPECT_TRUE(rfh_a->coop_access_report_manager()->coop_reporter());
+}
+
+// RenderFrameHostImpl::cross_origin_embedder_policy() must be preserved when
+// doing a back navigation using the BackForwardCache.
+// Regression test for https://crbug.com/1021846.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Coep) {
+  ASSERT_TRUE(CreateHttpsServer()->Start());
+  GURL url_a(https_server()->GetURL(
+      "a.com", "/set-header?Cross-Origin-Embedder-Policy: require-corp"));
+  GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
+
+  // Navigate to a document that sets COEP.
+  network::CrossOriginEmbedderPolicy coep;
+  coep.value = network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  EXPECT_EQ(coep, rfh_a->cross_origin_embedder_policy());
+
+  // Navigate away and back using the BackForwardCache.
+  // RenderFrameHostImpl::cross_origin_embedder_policy() should return the same
+  // result.
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  EXPECT_FALSE(delete_observer_rfh_a.deleted());
+  EXPECT_EQ(rfh_a, current_frame_host());
+
+  EXPECT_EQ(coep, rfh_a->cross_origin_embedder_policy());
+}
+
+// Tests that pagehide and visibilitychange handlers of the old RFH are run for
+// bfcached pages.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       PagehideAndVisibilitychangeRuns) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
+  GURL url_3(embedded_test_server()->GetURL("a.com", "/title2.html"));
+  WebContentsImpl* web_contents =
+      static_cast<WebContentsImpl*>(shell()->web_contents());
+
+  // 1) Navigate to |url_1|.
+  EXPECT_TRUE(NavigateToURL(shell(), url_1));
+  RenderFrameHostImpl* main_frame_1 = web_contents->GetMainFrame();
+
+  // Create a pagehide handler that sets item "pagehide_storage" and a
+  // visibilitychange handler that sets item "visibilitychange_storage" in
+  // localStorage.
+  EXPECT_TRUE(ExecJs(main_frame_1,
+                     R"(
+    localStorage.setItem('pagehide_storage', 'not_dispatched');
+    var dispatched_pagehide = false;
+    window.onpagehide = function(e) {
+      if (dispatched_pagehide) {
+        // We shouldn't dispatch pagehide more than once.
+        localStorage.setItem('pagehide_storage', 'dispatched_more_than_once');
+      } else if (!e.persisted) {
+        localStorage.setItem('pagehide_storage', 'wrong_persisted');
+      } else {
+        localStorage.setItem('pagehide_storage', 'dispatched_once');
+      }
+      dispatched_pagehide = true;
+    }
+    localStorage.setItem('visibilitychange_storage', 'not_dispatched');
+    var dispatched_visibilitychange = false;
+    document.onvisibilitychange = function(e) {
+      if (dispatched_visibilitychange) {
+        // We shouldn't dispatch visibilitychange more than once.
+        localStorage.setItem('visibilitychange_storage',
+          'dispatched_more_than_once');
+      } else if (document.visibilityState != 'hidden') {
+        // We should dispatch the event when the visibilityState is 'hidden'.
+        localStorage.setItem('visibilitychange_storage', 'not_hidden');
+      } else {
+        localStorage.setItem('visibilitychange_storage', 'dispatched_once');
+      }
+      dispatched_visibilitychange = true;
+    }
+  )"));
+
+  // 2) Navigate cross-site to |url_2|. We need to navigate cross-site to make
+  // sure we won't run pagehide and visibilitychange during new page's commit,
+  // which is tested in ProactivelySwapBrowsingInstancesSameSiteTest.
+  EXPECT_TRUE(NavigateToURL(shell(), url_2));
+
+  // |main_frame_1| should be in the back-forward cache.
+  EXPECT_TRUE(main_frame_1->IsInBackForwardCache());
+
+  // 3) Navigate to |url_3| which is same-origin with |url_1|, so we can check
+  // the localStorage values.
+  EXPECT_TRUE(NavigateToURL(shell(), url_3));
+  RenderFrameHostImpl* main_frame_3 = web_contents->GetMainFrame();
+
+  // Check that the value for 'pagehide_storage' and 'visibilitychange_storage'
+  // are set correctly.
+  EXPECT_EQ("dispatched_once",
+            EvalJs(main_frame_3, "localStorage.getItem('pagehide_storage')"));
+  EXPECT_EQ(
+      "dispatched_once",
+      EvalJs(main_frame_3, "localStorage.getItem('visibilitychange_storage')"));
+}
+
+// Tests that the history value saved in the renderer is updated correctly when
+// a page gets restored from the back-forward cache through browser-initiated
+// navigation.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       RendererHistory_BrowserInitiated) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url1(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  GURL url2(embedded_test_server()->GetURL("a.com", "/title1.html"));
+
+  // 1) Go to |url1|, then |url2|. Both pages should have script to save the
+  // history.length value when getting restored from the back-forward cache.
+  EXPECT_TRUE(NavigateToURL(shell(), url1));
+  FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
+  FrameTreeNode* subframe = root->child_at(0);
+
+  std::string restore_time_length_saver_script =
+      "var resumeLength = -1;"
+      "var pageshowLength = -1;"
+      "document.onresume = () => {"
+      "  resumeLength = history.length;"
+      "};"
+      "window.onpageshow  = () => {"
+      "  pageshowLength = history.length;"
+      "};";
+  EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
+  EXPECT_TRUE(ExecJs(subframe, restore_time_length_saver_script));
+  // We should have one history entry.
+  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 1);
+  EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 1);
+
+  EXPECT_TRUE(NavigateToURL(shell(), url2));
+  EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
+  // We should have two history entries.
+  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
+
+  // 2) Go back to |url1|, browser-initiated.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  EXPECT_EQ(web_contents()->GetLastCommittedURL(), url1);
+
+  // We should still have two history entries, and recorded the correct length
+  // when the 'resume' and 'pageshow' events were dispatched.
+  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(subframe, "resumeLength").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(subframe, "pageshowLength").ExtractInt(), 2);
+
+  // 3) Go forward to |url2|, browser-initiated.
+  ASSERT_TRUE(HistoryGoForward(web_contents()));
+  EXPECT_EQ(web_contents()->GetLastCommittedURL(), url2);
+
+  // We should still have two history entries, and recorded the correct length
+  // when the 'resume' and 'pageshow' events were dispatched.
+  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
+}
+
+// Tests that the history value saved in the renderer is updated correctly when
+// a page gets restored from the back-forward cache through renderer-initiated
+// navigation.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       RendererHistory_RendererInitiated) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL url1(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  GURL url2(embedded_test_server()->GetURL("a.com", "/title1.html"));
+
+  // 1) Go to |url1|, then |url2|. Both pages should have script to save the
+  // history.length value when getting restored from the back-forward cache.
+  EXPECT_TRUE(NavigateToURL(shell(), url1));
+  FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
+  FrameTreeNode* subframe = root->child_at(0);
+
+  std::string restore_time_length_saver_script =
+      "var resumeLength = -1;"
+      "var pageshowLength = -1;"
+      "document.onresume = () => {"
+      "  resumeLength = history.length;"
+      "};"
+      "window.onpageshow  = () => {"
+      "  pageshowLength = history.length;"
+      "};";
+  EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
+  EXPECT_TRUE(ExecJs(subframe, restore_time_length_saver_script));
+  // We should have one history entry.
+  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 1);
+  EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 1);
+
+  EXPECT_TRUE(NavigateToURL(shell(), url2));
+  EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
+  // We should have two history entries.
+  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
+
+  // 2) Go back to |url1|, renderer-initiated.
+  EXPECT_TRUE(ExecJs(root, "history.back()"));
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  EXPECT_EQ(web_contents()->GetLastCommittedURL(), url1);
+
+  // We should still have two history entries, and recorded the correct length
+  // when the 'resume' and 'pageshow' events were dispatched.
+  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(subframe, "resumeLength").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(subframe, "pageshowLength").ExtractInt(), 2);
+
+  // 3) Go forward to |url2|, renderer-initiated.
+  EXPECT_TRUE(ExecJs(root, "history.forward()"));
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+  EXPECT_EQ(web_contents()->GetLastCommittedURL(), url2);
+
+  // We should still have two history entries, and recorded the correct length
+  // when the 'resume' and 'pageshow' events were dispatched.
+  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
+  EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
+}
+
+// Check that an eligible page is cached when navigating to about:blank.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       NavigatingToAboutBlankDoesNotPreventCaching) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to a.com,
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+
+  // 2) Navigate to about:blank.
+  GURL blank_url(url::kAboutBlankURL);
+  EXPECT_TRUE(NavigateToURL(shell(), blank_url));
+
+  // 3) Navigate back to a.com.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+
+  ExpectRestored(FROM_HERE);
+}
+
+// Check that the response 204 No Content doesn't affect back-forward cache.
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, NoContent) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  NavigationControllerImpl& controller = web_contents()->GetController();
+
+  // 1) Navigate to a.com.
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  EXPECT_EQ(1, controller.GetEntryCount());
+  EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL());
+
+  // 2) Navigate to b.com
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/empty.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  EXPECT_EQ(2, controller.GetEntryCount());
+  EXPECT_EQ(url_b, controller.GetLastCommittedEntry()->GetURL());
+
+  // 3) Navigate to c.com with 204 No Content, then the URL will still be b.com.
+  GURL url_c(embedded_test_server()->GetURL("c.com", "/echo?status=204"));
+  EXPECT_TRUE(NavigateToURL(shell(), url_c, url_b));
+  EXPECT_EQ(2, controller.GetEntryCount());
+  EXPECT_EQ(url_b, controller.GetLastCommittedEntry()->GetURL());
+
+  // 4) Navigate back to a.com.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  EXPECT_EQ(2, controller.GetEntryCount());
+  EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL());
+
+  ExpectRestored(FROM_HERE);
+}
+
+// A testing subclass that limits the cache size to 1 for ease of testing
+// evictions.
+class CacheSizeOneBackForwardCacheBrowserTest
+    : public BackForwardCacheBrowserTest {
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    EnableFeatureAndSetParams(features::kBackForwardCache, "cache_size",
+                              base::NumberToString(1));
+    BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(CacheSizeOneBackForwardCacheBrowserTest,
+                       ReplacedNavigationEntry) {
+  // Set the bfcache value to 1 to ensure that the test fails if a page
+  // that replaces the current history entry is stored in back-forward cache.
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL("a.test", "/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.test", "/title1.html"));
+  GURL url_c(embedded_test_server()->GetURL("c.test", "/title1.html"));
+
+  // 1) Navigate to A.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+
+  // 2) Navigate to B.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  RenderFrameHostImplWrapper rfh_b(current_frame_host());
+  EXPECT_FALSE(rfh_a.IsRenderFrameDeleted());
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
+
+  // 3) Navigate to a new page by replacing the location. The old page can't
+  // be navigated back to and we should not store it in the back-forward
+  // cache.
+  EXPECT_TRUE(
+      ExecJs(shell(), JsReplace("window.location.replace($1);", url_c)));
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  RenderFrameHostImplWrapper rfh_c(current_frame_host());
+
+  // 4) Confirm A is still in BackForwardCache and it wasn't evicted due to the
+  // cache size limit, which would happen if we tried to store a new page in the
+  // cache in the previous step.
+  EXPECT_FALSE(rfh_a.IsRenderFrameDeleted());
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+
+  // 5) Confirm that navigating backwards goes back to A.
+  ASSERT_TRUE(HistoryGoBack(shell()->web_contents()));
+  EXPECT_EQ(rfh_a.get(), current_frame_host());
+  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
+  EXPECT_EQ(rfh_a->GetVisibilityState(), PageVisibilityState::kVisible);
+
+  // Go forward again, should return to C
+  ASSERT_TRUE(HistoryGoForward(shell()->web_contents()));
+  EXPECT_EQ(rfh_c.get(), current_frame_host());
+  EXPECT_EQ(rfh_c->GetVisibilityState(), PageVisibilityState::kVisible);
+}
+
+}  // namespace content
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index e92d8e22..48111c48 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -35,7 +35,6 @@
 #include "content/public/browser/back_forward_cache.h"
 #include "content/public/browser/document_service.h"
 #include "content/public/browser/global_routing_id.h"
-#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
@@ -52,7 +51,6 @@
 #include "content/public/test/test_navigation_throttle_inserter.h"
 #include "content/public/test/test_utils.h"
 #include "content/public/test/text_input_test_utils.h"
-#include "content/public/test/url_loader_interceptor.h"
 #include "content/shell/browser/shell.h"
 #include "content/shell/browser/shell_javascript_dialog_manager.h"
 #include "content/test/web_contents_observer_test_utils.h"
@@ -68,7 +66,6 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/device_memory/approximated_device_memory.h"
 #include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/common/frame/event_page_show_persisted.h"
 #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
 #include "third_party/blink/public/common/switches.h"
 
@@ -737,292 +734,6 @@
   bool observed_ = false;
 };
 
-// Navigate from A to B and go back.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Basic) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
-  url::Origin origin_a = url::Origin::Create(url_a);
-  url::Origin origin_b = url::Origin::Create(url_b);
-
-  // 1) Navigate to A.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
-
-  // 2) Navigate to B.
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  RenderFrameHostImpl* rfh_b = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-  EXPECT_EQ(rfh_a->GetVisibilityState(), PageVisibilityState::kHidden);
-  EXPECT_EQ(origin_a, rfh_a->GetLastCommittedOrigin());
-  EXPECT_EQ(origin_b, rfh_b->GetLastCommittedOrigin());
-  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
-  EXPECT_EQ(rfh_b->GetVisibilityState(), PageVisibilityState::kVisible);
-
-  // 3) Go back to A.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_FALSE(delete_observer_rfh_b.deleted());
-  EXPECT_EQ(origin_a, rfh_a->GetLastCommittedOrigin());
-  EXPECT_EQ(origin_b, rfh_b->GetLastCommittedOrigin());
-  EXPECT_EQ(rfh_a, current_frame_host());
-  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
-  EXPECT_EQ(rfh_a->GetVisibilityState(), PageVisibilityState::kVisible);
-  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
-  EXPECT_EQ(rfh_b->GetVisibilityState(), PageVisibilityState::kHidden);
-
-  ExpectRestored(FROM_HERE);
-}
-
-// Navigate from A to B and go back.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, BasicDocumentInitiated) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
-
-  // 1) Navigate to A.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
-
-  // 2) Navigate to B.
-  ASSERT_TRUE(NavigateToURLFromRenderer(shell(), url_b));
-  RenderFrameHostImpl* rfh_b = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
-
-  // The two pages are using different BrowsingInstances.
-  EXPECT_FALSE(rfh_a->GetSiteInstance()->IsRelatedSiteInstance(
-      rfh_b->GetSiteInstance()));
-
-  // 3) Go back to A.
-  EXPECT_TRUE(ExecJs(shell(), "history.back();"));
-  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_FALSE(delete_observer_rfh_b.deleted());
-  EXPECT_EQ(rfh_a, current_frame_host());
-  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
-
-  ExpectRestored(FROM_HERE);
-}
-
-// Navigate from back and forward repeatedly.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       NavigateBackForwardRepeatedly) {
-  // Do not check for unexpected messages because the input task queue is not
-  // currently frozen, causing flakes in this test: crbug.com/1099395.
-  DoNotFailForUnexpectedMessagesWhileCached();
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
-
-  // 1) Navigate to A.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
-
-  // 2) Navigate to B.
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  RenderFrameHostImpl* rfh_b = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
-
-  // 3) Go back to A.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-
-  EXPECT_EQ(rfh_a, current_frame_host());
-  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
-
-  ExpectRestored(FROM_HERE);
-
-  // 4) Go forward to B.
-  ASSERT_TRUE(HistoryGoForward(web_contents()));
-
-  EXPECT_EQ(rfh_b, current_frame_host());
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
-
-  ExpectRestored(FROM_HERE);
-
-  // 5) Go back to A.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-
-  EXPECT_EQ(rfh_a, current_frame_host());
-  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
-
-  ExpectRestored(FROM_HERE);
-
-  // 6) Go forward to B.
-  ASSERT_TRUE(HistoryGoForward(web_contents()));
-
-  EXPECT_EQ(rfh_b, current_frame_host());
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
-
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_FALSE(delete_observer_rfh_b.deleted());
-
-  ExpectRestored(FROM_HERE);
-}
-
-// The current page can't enter the BackForwardCache if another page can script
-// it. This can happen when one document opens a popup using window.open() for
-// instance. It prevents the BackForwardCache from being used.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WindowOpen) {
-  // This test assumes cross-site navigation staying in the same
-  // BrowsingInstance to use a different SiteInstance. Otherwise, it will
-  // timeout at step 2).
-  if (!SiteIsolationPolicy::UseDedicatedProcessesForAllSites())
-    return;
-
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
-
-  // 1) Navigate to A and open a popup.
-  ASSERT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImplWrapper rfh_a(current_frame_host());
-  EXPECT_EQ(1u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
-  Shell* popup = OpenPopup(rfh_a.get(), url_a, "");
-  EXPECT_EQ(2u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
-
-  // 2) Navigate to B. The previous document can't enter the BackForwardCache,
-  // because of the popup.
-  ASSERT_TRUE(NavigateToURLFromRenderer(rfh_a.get(), url_b));
-  ASSERT_TRUE(rfh_a.WaitUntilRenderFrameDeleted());
-  RenderFrameHostImplWrapper rfh_b(current_frame_host());
-  EXPECT_EQ(2u, rfh_b->GetSiteInstance()->GetRelatedActiveContentsCount());
-
-  // 3) Go back to A. The previous document can't enter the BackForwardCache,
-  // because of the popup.
-  ASSERT_TRUE(ExecJs(rfh_b.get(), "history.back();"));
-  ASSERT_TRUE(rfh_b.WaitUntilRenderFrameDeleted());
-
-  ExpectNotRestored(
-      {BackForwardCacheMetrics::NotRestoredReason::kRelatedActiveContentsExist,
-       BackForwardCacheMetrics::NotRestoredReason::kBrowsingInstanceNotSwapped},
-      {}, {ShouldSwapBrowsingInstance::kNo_HasRelatedActiveContents}, {}, {},
-      FROM_HERE);
-
-  // 4) Make the popup drop the window.opener connection. It happens when the
-  //    user does an omnibox-initiated navigation, which happens in a new
-  //    BrowsingInstance.
-  RenderFrameHostImplWrapper rfh_a_new(current_frame_host());
-  EXPECT_EQ(2u, rfh_a_new->GetSiteInstance()->GetRelatedActiveContentsCount());
-  ASSERT_TRUE(NavigateToURL(popup, url_b));
-  EXPECT_EQ(1u, rfh_a_new->GetSiteInstance()->GetRelatedActiveContentsCount());
-
-  // 5) Navigate to B again. As the scripting relationship with the popup is
-  // now severed, the current page (|rfh_a_new|) can enter back-forward cache.
-  ASSERT_TRUE(NavigateToURLFromRenderer(rfh_a_new.get(), url_b));
-  EXPECT_FALSE(rfh_a_new.IsRenderFrameDeleted());
-  EXPECT_TRUE(rfh_a_new->IsInBackForwardCache());
-
-  // 6) Go back to A. The current document can finally enter the
-  // BackForwardCache, because it is alone in its BrowsingInstance and has never
-  // been related to any other document.
-  RenderFrameHostImplWrapper rfh_b_new(current_frame_host());
-  ASSERT_TRUE(ExecJs(rfh_b_new.get(), "history.back();"));
-  ASSERT_TRUE(WaitForLoadStop(web_contents()));
-  EXPECT_FALSE(rfh_b_new.IsRenderFrameDeleted());
-  EXPECT_TRUE(rfh_b_new->IsInBackForwardCache());
-}
-
-// A popup will prevent a page from entering BFCache. Test that after closing a
-// popup, the page is not stopped from entering. This tries to close the popup
-// at the last moment.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WindowOpenThenClose) {
-  net::test_server::ControllableHttpResponse response(embedded_test_server(),
-                                                      "/title2.html");
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL("a.test", "/title1.html"));
-  GURL url_b(embedded_test_server()->GetURL("b.test", "/title2.html"));
-
-  // Navigate to A.
-  ASSERT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImplWrapper rfh_a(current_frame_host());
-  EXPECT_EQ(1u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
-
-  // Open a popup.
-  Shell* popup = OpenPopup(rfh_a.get(), url_a, "");
-  EXPECT_EQ(2u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
-
-  // Start navigating to B, the response will be delayed.
-  TestNavigationObserver observer(web_contents());
-  shell()->LoadURL(url_b);
-
-  // When the request is received, close the popup.
-  response.WaitForRequest();
-  RenderFrameHostImplWrapper rfh_popup(popup->web_contents()->GetMainFrame());
-  ASSERT_TRUE(ExecJs(rfh_popup.get(), "window.close();"));
-  ASSERT_TRUE(rfh_popup.WaitUntilRenderFrameDeleted());
-
-  EXPECT_EQ(1u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
-
-  // Send the response.
-  response.Send(net::HTTP_OK, "text/html", "foo");
-  response.Done();
-  observer.Wait();
-
-  // A is in BFCache.
-  EXPECT_EQ(0u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
-  ASSERT_TRUE(rfh_a->IsInBackForwardCache());
-
-  // Go back.
-  web_contents()->GetController().GoBack();
-  ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
-
-  // A is restored from BFCache.
-  EXPECT_FALSE(rfh_a.IsRenderFrameDeleted());
-  ExpectRestored(FROM_HERE);
-}
-
-// Navigate from A(B) to C and go back.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, BasicIframe) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(b)"));
-  GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
-
-  // 1) Navigate to A(B).
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
-  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
-
-  // 2) Navigate to C.
-  EXPECT_TRUE(NavigateToURL(shell(), url_c));
-  RenderFrameHostImpl* rfh_c = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_FALSE(delete_observer_rfh_b.deleted());
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
-  EXPECT_FALSE(rfh_c->IsInBackForwardCache());
-
-  // 3) Go back to A(B).
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_FALSE(delete_observer_rfh_b.deleted());
-  EXPECT_FALSE(delete_observer_rfh_c.deleted());
-  EXPECT_EQ(rfh_a, current_frame_host());
-  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
-  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_c->IsInBackForwardCache());
-
-  ExpectRestored(FROM_HERE);
-}
-
 // Check the visible URL in the omnibox is properly updated when restoring a
 // document from the BackForwardCache.
 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, VisibleURL) {
@@ -1228,201 +939,6 @@
                     FROM_HERE);
 }
 
-// Similar to BackForwardCacheBrowserTest.SubframeSurviveCache*
-// Test case: a1(b2) -> c3 -> a1(b2)
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeSurviveCache1) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(b)"));
-  GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
-
-  std::vector<RenderFrameDeletedObserver*> rfh_observer;
-
-  // 1) Navigate to a1(b2).
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* a1 = current_frame_host();
-  RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
-  RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
-  rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
-  EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
-
-  // 2) Navigate to c3.
-  EXPECT_TRUE(NavigateToURL(shell(), url_c));
-  RenderFrameHostImpl* c3 = current_frame_host();
-  RenderFrameDeletedObserver c3_observer(c3);
-  rfh_observer.push_back(&c3_observer);
-  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
-  EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
-  EXPECT_THAT(c3, Not(InBackForwardCache()));
-
-  // 3) Go back to a1(b2).
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
-  EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
-  EXPECT_THAT(c3, InBackForwardCache());
-
-  // Even after a new IPC round trip with the renderer, b2 must still be alive.
-  EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
-  EXPECT_FALSE(b2_observer.deleted());
-
-  ExpectRestored(FROM_HERE);
-}
-
-// Similar to BackForwardCacheBrowserTest.SubframeSurviveCache*
-// Test case: a1(b2) -> b3 -> a1(b2).
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeSurviveCache2) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(b)"));
-  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
-
-  std::vector<RenderFrameDeletedObserver*> rfh_observer;
-
-  // 1) Navigate to a1(b2).
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* a1 = current_frame_host();
-  RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
-  RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
-  rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
-  EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
-
-  // 2) Navigate to b3.
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  RenderFrameHostImpl* b3 = current_frame_host();
-  RenderFrameDeletedObserver b3_observer(b3);
-  rfh_observer.push_back(&b3_observer);
-  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
-  EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
-  EXPECT_THAT(b3, Not(InBackForwardCache()));
-
-  // 3) Go back to a1(b2).
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
-  EXPECT_EQ(a1, current_frame_host());
-  EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
-  EXPECT_THAT(b3, InBackForwardCache());
-
-  // Even after a new IPC round trip with the renderer, b2 must still be alive.
-  EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
-  EXPECT_FALSE(b2_observer.deleted());
-
-  ExpectRestored(FROM_HERE);
-}
-
-// Similar to BackForwardCacheBrowserTest.tSubframeSurviveCache*
-// Test case: a1(b2) -> b3(a4) -> a1(b2) -> b3(a4)
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeSurviveCache3) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(b)"));
-  GURL url_b(embedded_test_server()->GetURL(
-      "b.com", "/cross_site_iframe_factory.html?b(a)"));
-
-  std::vector<RenderFrameDeletedObserver*> rfh_observer;
-
-  // 1) Navigate to a1(b2).
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* a1 = current_frame_host();
-  RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
-  RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
-  rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
-  EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
-
-  // 2) Navigate to b3(a4)
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  RenderFrameHostImpl* b3 = current_frame_host();
-  RenderFrameHostImpl* a4 = b3->child_at(0)->current_frame_host();
-  RenderFrameDeletedObserver b3_observer(b3), a4_observer(a4);
-  rfh_observer.insert(rfh_observer.end(), {&b3_observer, &a4_observer});
-  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
-  EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
-  EXPECT_THAT(Elements({b3, a4}), Each(Not(InBackForwardCache())));
-  EXPECT_TRUE(ExecJs(a4, "window.alive = 'I am alive';"));
-
-  // 3) Go back to a1(b2).
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
-  EXPECT_EQ(a1, current_frame_host());
-  EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
-  EXPECT_THAT(Elements({b3, a4}), Each(InBackForwardCache()));
-
-  // Even after a new IPC round trip with the renderer, b2 must still be alive.
-  EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
-  EXPECT_FALSE(b2_observer.deleted());
-
-  ExpectRestored(FROM_HERE);
-
-  // 4) Go forward to b3(a4).
-  ASSERT_TRUE(HistoryGoForward(web_contents()));
-  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
-  EXPECT_EQ(b3, current_frame_host());
-  EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
-  EXPECT_THAT(Elements({b3, a4}), Each(Not(InBackForwardCache())));
-
-  // Even after a new IPC round trip with the renderer, a4 must still be alive.
-  EXPECT_EQ("I am alive", EvalJs(a4, "window.alive"));
-  EXPECT_FALSE(a4_observer.deleted());
-
-  ExpectRestored(FROM_HERE);
-}
-
-// Similar to BackForwardCacheBrowserTest.SubframeSurviveCache*
-// Test case: a1(b2) -> b3 -> a4 -> b5 -> a1(b2).
-IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,
-                       SubframeSurviveCache4) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_ab(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(b)"));
-  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
-
-  std::vector<RenderFrameDeletedObserver*> rfh_observer;
-
-  // 1) Navigate to a1(b2).
-  EXPECT_TRUE(NavigateToURL(shell(), url_ab));
-  RenderFrameHostImpl* a1 = current_frame_host();
-  RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
-  RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
-  rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
-  EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
-
-  // 2) Navigate to b3.
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  RenderFrameHostImpl* b3 = current_frame_host();
-  RenderFrameDeletedObserver b3_observer(b3);
-  rfh_observer.push_back(&b3_observer);
-  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
-  EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
-  EXPECT_THAT(b3, Not(InBackForwardCache()));
-
-  // 3) Navigate to a4.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* a4 = current_frame_host();
-  RenderFrameDeletedObserver a4_observer(a4);
-  rfh_observer.push_back(&a4_observer);
-  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
-
-  // 4) Navigate to b5
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  RenderFrameHostImpl* b5 = current_frame_host();
-  RenderFrameDeletedObserver b5_observer(b5);
-  rfh_observer.push_back(&b5_observer);
-  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
-  EXPECT_THAT(Elements({a1, b2, b3, a4}), Each(InBackForwardCache()));
-  EXPECT_THAT(b5, Not(InBackForwardCache()));
-
-  // 3) Go back to a1(b2).
-  ASSERT_TRUE(HistoryGoToOffset(web_contents(), -3));
-  EXPECT_EQ(a1, current_frame_host());
-  ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
-  EXPECT_THAT(Elements({b3, a4, b5}), Each(InBackForwardCache()));
-  EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
-
-  // Even after a new IPC round trip with the renderer, b2 must still be alive.
-  EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
-  EXPECT_FALSE(b2_observer.deleted());
-}
-
 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
                        SubframeWithOngoingNavigationNotCached) {
   net::test_server::ControllableHttpResponse response(embedded_test_server(),
@@ -1449,543 +965,6 @@
   frame_deleted_observer.WaitUntilDeleted();
 }
 
-// Check that unload event handlers are not dispatched when the page goes
-// into BackForwardCache.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       ConfirmUnloadEventNotFired) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
-
-  // 1) Navigate to A.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
-
-  // 2) Set unload handler and check the title.
-  EXPECT_TRUE(ExecJs(rfh_a,
-                     "document.title = 'loaded!';"
-                     "window.addEventListener('unload', () => {"
-                     "  document.title = 'unloaded!';"
-                     "});"));
-  {
-    std::u16string title_when_loaded = u"loaded!";
-    TitleWatcher title_watcher(web_contents(), title_when_loaded);
-    EXPECT_EQ(title_watcher.WaitAndGetTitle(), title_when_loaded);
-  }
-
-  // 3) Navigate to B.
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  RenderFrameHostImpl* rfh_b = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
-
-  // 4) Go back to A and check the title again.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_FALSE(delete_observer_rfh_b.deleted());
-  EXPECT_EQ(rfh_a, current_frame_host());
-  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
-  {
-    std::u16string title_when_loaded = u"loaded!";
-    TitleWatcher title_watcher(web_contents(), title_when_loaded);
-    EXPECT_EQ(title_watcher.WaitAndGetTitle(), title_when_loaded);
-  }
-}
-
-// TODO(https://crbug.com/1075936) disabled due to flakiness
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       DISABLED_DoesNotCacheIfMainFrameStillLoading) {
-  net::test_server::ControllableHttpResponse response(embedded_test_server(),
-                                                      "/main_document");
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  // 1) Navigate to a page that doesn't finish loading.
-  GURL url(embedded_test_server()->GetURL("a.com", "/main_document"));
-  TestNavigationManager navigation_manager(shell()->web_contents(), url);
-  shell()->LoadURL(url);
-
-  // The navigation starts.
-  EXPECT_TRUE(navigation_manager.WaitForRequestStart());
-  navigation_manager.ResumeNavigation();
-
-  // The server sends the first part of the response and waits.
-  response.WaitForRequest();
-  response.Send(
-      "HTTP/1.1 200 OK\r\n"
-      "Content-Type: text/html; charset=utf-8\r\n"
-      "\r\n"
-      "<html><body> ... ");
-
-  // The navigation finishes while the body is still loading.
-  navigation_manager.WaitForNavigationFinished();
-  RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
-
-  // 2) Navigate away.
-  shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
-
-  // The page was still loading when we navigated away, so it shouldn't have
-  // been cached.
-  delete_observer_rfh_a.WaitUntilDeleted();
-
-  // 3) Go back.
-  web_contents()->GetController().GoBack();
-  EXPECT_FALSE(WaitForLoadStop(shell()->web_contents()));
-  ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::kLoading}, {},
-                    {}, {}, {}, FROM_HERE);
-}
-
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       DoesNotCacheLoadingSubframe) {
-  net::test_server::ControllableHttpResponse response(embedded_test_server(),
-                                                      "/controlled");
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  // 1) Navigate to a page with an iframe that loads forever.
-  GURL url(embedded_test_server()->GetURL(
-      "a.com", "/back_forward_cache/controllable_subframe.html"));
-  TestNavigationManager navigation_manager(shell()->web_contents(), url);
-  shell()->LoadURL(url);
-
-  // The navigation finishes while the iframe is still loading.
-  navigation_manager.WaitForNavigationFinished();
-
-  // Wait for the iframe request to arrive, and leave it hanging with no
-  // response.
-  response.WaitForRequest();
-
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
-
-  // 2) Navigate away.
-  shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
-  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
-
-  // The page should not have been added to cache, since it had a subframe that
-  // was still loading at the time it was navigated away from.
-  delete_observer_rfh_a.WaitUntilDeleted();
-
-  // 3) Go back.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  ExpectNotRestored(
-      {
-          BackForwardCacheMetrics::NotRestoredReason::kLoading,
-          BackForwardCacheMetrics::NotRestoredReason::kSubframeIsNavigating,
-      },
-      {}, {}, {}, {}, FROM_HERE);
-}
-
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       DoesNotCacheLoadingSubframeOfSubframe) {
-  net::test_server::ControllableHttpResponse response(embedded_test_server(),
-                                                      "/controlled");
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  // 1) Navigate to a page with an iframe that contains yet another iframe, that
-  // hangs while loading.
-  GURL url(embedded_test_server()->GetURL(
-      "a.com", "/back_forward_cache/controllable_subframe_of_subframe.html"));
-  TestNavigationManager navigation_manager(shell()->web_contents(), url);
-  shell()->LoadURL(url);
-
-  // The navigation finishes while the iframe within an iframe is still loading.
-  navigation_manager.WaitForNavigationFinished();
-
-  // Wait for the innermost iframe request to arrive, and leave it hanging with
-  // no response.
-  response.WaitForRequest();
-
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  RenderFrameDeletedObserver delete_rfh_a(rfh_a);
-
-  // 2) Navigate away.
-  shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
-  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
-
-  // The page should not have been added to the cache, since it had an iframe
-  // that was still loading at the time it was navigated away from.
-  delete_rfh_a.WaitUntilDeleted();
-
-  // 3) Go back.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  ExpectNotRestored(
-      {
-          BackForwardCacheMetrics::NotRestoredReason::kLoading,
-          BackForwardCacheMetrics::NotRestoredReason::kSubframeIsNavigating,
-      },
-      {}, {}, {}, {}, FROM_HERE);
-}
-
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIfHttpError) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  GURL error_url(embedded_test_server()->GetURL("a.com", "/page404.html"));
-  GURL url(embedded_test_server()->GetURL("b.com", "/title1.html"));
-
-  // Navigate to an error page.
-  EXPECT_TRUE(NavigateToURL(shell(), error_url));
-  EXPECT_EQ(net::HTTP_NOT_FOUND, current_frame_host()->last_http_status_code());
-  RenderFrameDeletedObserver delete_rfh_a(current_frame_host());
-
-  // Navigate away.
-  EXPECT_TRUE(NavigateToURL(shell(), url));
-
-  // The page did not return 200 (OK), so it shouldn't have been cached.
-  delete_rfh_a.WaitUntilDeleted();
-
-  // Go back.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  ExpectNotRestored(
-      {BackForwardCacheMetrics::NotRestoredReason::kHTTPStatusNotOK}, {}, {},
-      {}, {}, FROM_HERE);
-}
-
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       DoesNotCacheIfPageUnreachable) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  GURL error_url(embedded_test_server()->GetURL("a.com", "/empty.html"));
-  GURL url(embedded_test_server()->GetURL("b.com", "/title1.html"));
-
-  std::unique_ptr<URLLoaderInterceptor> url_interceptor =
-      URLLoaderInterceptor::SetupRequestFailForURL(error_url,
-                                                   net::ERR_DNS_TIMED_OUT);
-
-  // Start with a successful navigation to a document.
-  EXPECT_TRUE(NavigateToURL(shell(), url));
-  EXPECT_EQ(net::HTTP_OK, current_frame_host()->last_http_status_code());
-
-  // Navigate to an error page.
-  NavigationHandleObserver observer(shell()->web_contents(), error_url);
-  EXPECT_FALSE(NavigateToURL(shell(), error_url));
-  EXPECT_TRUE(observer.is_error());
-  EXPECT_EQ(net::ERR_DNS_TIMED_OUT, observer.net_error_code());
-  EXPECT_EQ(
-      GURL(kUnreachableWebDataURL),
-      shell()->web_contents()->GetMainFrame()->GetSiteInstance()->GetSiteURL());
-  EXPECT_EQ(net::OK, current_frame_host()->last_http_status_code());
-
-  RenderFrameDeletedObserver delete_rfh_a(current_frame_host());
-
-  // Navigate away.
-  EXPECT_TRUE(NavigateToURL(shell(), url));
-
-  // The page had a networking error, so it shouldn't have been cached.
-  delete_rfh_a.WaitUntilDeleted();
-
-  // Go back.
-  web_contents()->GetController().GoBack();
-  EXPECT_FALSE(WaitForLoadStop(shell()->web_contents()));
-  ExpectNotRestored(
-      {BackForwardCacheMetrics::NotRestoredReason::kHTTPStatusNotOK,
-       BackForwardCacheMetrics::NotRestoredReason::kNoResponseHead},
-      {}, {}, {}, {}, FROM_HERE);
-}
-
-// Tests the events are fired when going back from the cache.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Events) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL(
-      "a.com", "/back_forward_cache/record_events.html"));
-  GURL url_b(embedded_test_server()->GetURL(
-      "b.com", "/back_forward_cache/record_events.html"));
-
-  // 1) Navigate to A.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImplWrapper rfh_a(current_frame_host());
-
-  // At A, a page-show event is recorded for the first loading.
-  MatchEventList(rfh_a.get(), ListValueOf("window.pageshow"));
-
-  constexpr char kEventPageShowPersisted[] = "Event.PageShow.Persisted";
-
-  content::FetchHistogramsFromChildProcesses();
-  EXPECT_THAT(
-      histogram_tester_.GetAllSamples(kEventPageShowPersisted),
-      testing::UnorderedElementsAre(base::Bucket(
-          static_cast<int>(blink::EventPageShowPersisted::kNoInRenderer), 1)));
-
-  // 2) Navigate to B.
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  RenderFrameHostImplWrapper rfh_b(current_frame_host());
-
-  EXPECT_FALSE(rfh_a.IsRenderFrameDeleted());
-  EXPECT_FALSE(rfh_b.IsRenderFrameDeleted());
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
-  // TODO(yuzus): Post message to the frozen page, and make sure that the
-  // messages arrive after the page visibility events, not before them.
-
-  // As |rfh_a| is in back-forward cache, we cannot get the event list of A.
-  // At B, a page-show event is recorded for the first loading.
-  MatchEventList(rfh_b.get(), ListValueOf("window.pageshow"));
-  content::FetchHistogramsFromChildProcesses();
-  EXPECT_THAT(
-      histogram_tester_.GetAllSamples(kEventPageShowPersisted),
-      testing::UnorderedElementsAre(base::Bucket(
-          static_cast<int>(blink::EventPageShowPersisted::kNoInRenderer), 2)));
-
-  // 3) Go back to A. Confirm that expected events are fired.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  EXPECT_FALSE(rfh_a.IsRenderFrameDeleted());
-  EXPECT_FALSE(rfh_b.IsRenderFrameDeleted());
-  EXPECT_EQ(rfh_a.get(), current_frame_host());
-  // visibilitychange events are added twice per each because it is fired for
-  // both window and document.
-  MatchEventList(
-      rfh_a.get(),
-      ListValueOf("window.pageshow", "window.pagehide.persisted",
-                  "document.visibilitychange", "window.visibilitychange",
-                  "document.freeze", "document.resume",
-                  "document.visibilitychange", "window.visibilitychange",
-                  "window.pageshow.persisted"));
-
-  content::FetchHistogramsFromChildProcesses();
-  EXPECT_THAT(
-      histogram_tester_.GetAllSamples(kEventPageShowPersisted),
-      testing::UnorderedElementsAre(
-          base::Bucket(
-              static_cast<int>(blink::EventPageShowPersisted::kNoInRenderer),
-              2),
-          base::Bucket(
-              static_cast<int>(blink::EventPageShowPersisted::kYesInBrowser),
-              1),
-          base::Bucket(
-              static_cast<int>(blink::EventPageShowPersisted::kYesInRenderer),
-              1),
-          base::Bucket(
-              static_cast<int>(
-                  blink::EventPageShowPersisted::kBrowserYesInRenderer),
-              1),
-          base::Bucket(
-              static_cast<int>(
-                  blink::EventPageShowPersisted::kBrowserYesInRendererWithPage),
-              1),
-          base::Bucket(
-              static_cast<int>(
-                  blink::EventPageShowPersisted::
-                      kYesInBrowser_BackForwardCache_WillCommitNavigationToCachedEntry),
-              1),
-          base::Bucket(
-              static_cast<int>(
-                  blink::EventPageShowPersisted::
-                      kYesInBrowser_BackForwardCache_RestoreEntry_Attempt),
-              1),
-          base::Bucket(
-              static_cast<int>(
-                  blink::EventPageShowPersisted::
-                      kYesInBrowser_BackForwardCache_RestoreEntry_Succeed),
-              1),
-          base::Bucket(
-              static_cast<int>(
-                  blink::EventPageShowPersisted::
-                      kYesInBrowser_RenderFrameHostManager_CommitPending),
-              1)));
-}
-
-// Tests the events are fired for subframes when going back from the cache.
-// Test case: a(b) -> c -> a(b)
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, EventsForSubframes) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(b)"));
-  GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
-
-  // 1) Navigate to A(B).
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
-  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
-  StartRecordingEvents(rfh_a);
-  StartRecordingEvents(rfh_b);
-
-  // 2) Navigate to C.
-  EXPECT_TRUE(NavigateToURL(shell(), url_c));
-  RenderFrameHostImpl* rfh_c = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_FALSE(delete_observer_rfh_b.deleted());
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_b->IsInBackForwardCache());
-  EXPECT_FALSE(rfh_c->IsInBackForwardCache());
-  // TODO(yuzus): Post message to the frozen page, and make sure that the
-  // messages arrive after the page visibility events, not before them.
-
-  // 3) Go back to A(B). Confirm that expected events are fired on the subframe.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_FALSE(delete_observer_rfh_b.deleted());
-  EXPECT_FALSE(delete_observer_rfh_c.deleted());
-  EXPECT_EQ(rfh_a, current_frame_host());
-  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
-  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_c->IsInBackForwardCache());
-  // visibilitychange events are added twice per each because it is fired for
-  // both window and document.
-  MatchEventList(
-      rfh_a,
-      ListValueOf("window.pagehide.persisted", "document.visibilitychange",
-                  "window.visibilitychange", "document.freeze",
-                  "document.resume", "document.visibilitychange",
-                  "window.visibilitychange", "window.pageshow.persisted"));
-  MatchEventList(
-      rfh_b,
-      ListValueOf("window.pagehide.persisted", "document.visibilitychange",
-                  "window.visibilitychange", "document.freeze",
-                  "document.resume", "document.visibilitychange",
-                  "window.visibilitychange", "window.pageshow.persisted"));
-}
-
-// Tests the events are fired when going back from the cache.
-// Same as: BackForwardCacheBrowserTest.Events, but with a document-initiated
-// navigation. This is a regression test for https://crbug.com/1000324
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       EventsAfterDocumentInitiatedNavigation) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
-
-  // 1) Navigate to A.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
-  StartRecordingEvents(rfh_a);
-
-  // 2) Navigate to B.
-  ASSERT_TRUE(NavigateToURLFromRenderer(shell(), url_b));
-  RenderFrameHostImpl* rfh_b = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
-
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_FALSE(delete_observer_rfh_b.deleted());
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
-  // TODO(yuzus): Post message to the frozen page, and make sure that the
-  // messages arrive after the page visibility events, not before them.
-
-  // 3) Go back to A. Confirm that expected events are fired.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_FALSE(delete_observer_rfh_b.deleted());
-  EXPECT_EQ(rfh_a, current_frame_host());
-  // visibilitychange events are added twice per each because it is fired for
-  // both window and document.
-  MatchEventList(
-      rfh_a,
-      ListValueOf("window.pagehide.persisted", "document.visibilitychange",
-                  "window.visibilitychange", "document.freeze",
-                  "document.resume", "document.visibilitychange",
-                  "window.visibilitychange", "window.pageshow.persisted"));
-}
-
-// Track the events dispatched when a page is deemed ineligible for back-forward
-// cache after we've dispatched the 'pagehide' event with persisted set to true.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       EventsForPageIneligibleAfterPagehidePersisted) {
-  ASSERT_TRUE(CreateHttpsServer()->Start());
-  GURL url_1(https_server()->GetURL("a.com", "/title1.html"));
-  GURL url_2(https_server()->GetURL("a.com", "/title2.html"));
-
-  // 1) Navigate to |url_1|.
-  EXPECT_TRUE(NavigateToURL(shell(), url_1));
-  RenderFrameHostImpl* rfh_1 = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_1(rfh_1);
-  // 2) Use BroadcastChannel (a non-sticky blocklisted feature), so that we
-  // would still do a RFH swap on same-site navigation and fire the 'pagehide'
-  // event during commit of the new page with 'persisted' set to true, but the
-  // page will not be eligible for back-forward cache after commit.
-  EXPECT_TRUE(ExecJs(rfh_1, "window.foo = new BroadcastChannel('foo');"));
-
-  EXPECT_TRUE(ExecJs(rfh_1, R"(
-    window.onpagehide = (e) => {
-      if (e.persisted) {
-        window.domAutomationController.send('pagehide.persisted');
-      }
-    }
-    document.onvisibilitychange = () => {
-      if (document.visibilityState == 'hidden') {
-        window.domAutomationController.send('visibilitychange.hidden');
-      }
-    }
-    window.onunload = () => {
-      window.domAutomationController.send('unload');
-    }
-  )"));
-
-  DOMMessageQueue dom_message_queue(shell()->web_contents());
-  // 3) Navigate to |url_2|.
-  EXPECT_TRUE(NavigateToURL(shell(), url_2));
-  // |rfh_1| will not get into the back-forward cache and eventually get deleted
-  // because it uses a blocklisted feature.
-  delete_observer_rfh_1.WaitUntilDeleted();
-
-  // Only the pagehide and visibilitychange events will be dispatched.
-  int num_messages_received = 0;
-  std::string expected_messages[] = {"\"pagehide.persisted\"",
-                                     "\"visibilitychange.hidden\""};
-  std::string message;
-  while (dom_message_queue.PopMessage(&message)) {
-    EXPECT_EQ(expected_messages[num_messages_received], message);
-    num_messages_received++;
-  }
-  EXPECT_EQ(num_messages_received, 2);
-}
-
-// Track the events dispatched when a page is deemed ineligible for back-forward
-// cache before we've dispatched the pagehide event on it.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       EventsForPageIneligibleBeforePagehide) {
-  ASSERT_TRUE(CreateHttpsServer()->Start());
-  GURL url_1(https_server()->GetURL("a.com", "/title1.html"));
-  GURL url_2(https_server()->GetURL("b.com", "/title2.html"));
-
-  // 1) Navigate to |url_1|.
-  EXPECT_TRUE(NavigateToURL(shell(), url_1));
-  RenderFrameHostImpl* rfh_1 = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_1(rfh_1);
-  // 2) Use a dummy sticky blocklisted feature, so that the page is known to be
-  // ineligible for bfcache at commit time, before we dispatch pagehide event.
-  rfh_1->UseDummyStickyBackForwardCacheDisablingFeatureForTesting();
-
-  EXPECT_TRUE(ExecJs(rfh_1, R"(
-    window.onpagehide = (e) => {
-      if (!e.persisted) {
-        window.domAutomationController.send('pagehide.not_persisted');
-      }
-    }
-    document.onvisibilitychange = () => {
-      if (document.visibilityState == 'hidden') {
-        window.domAutomationController.send('visibilitychange.hidden');
-      }
-    }
-    window.onunload = () => {
-      window.domAutomationController.send('unload');
-    }
-  )"));
-
-  DOMMessageQueue dom_message_queue(shell()->web_contents());
-  // 3) Navigate to |url_2|.
-  EXPECT_TRUE(NavigateToURL(shell(), url_2));
-  // |rfh_1| will not get into the back-forward cache and eventually get deleted
-  // because it uses a blocklisted feature.
-  delete_observer_rfh_1.WaitUntilDeleted();
-
-  // "pagehide", "visibilitychange", and "unload" events will be dispatched.
-  int num_messages_received = 0;
-  std::string expected_messages[] = {"\"pagehide.not_persisted\"",
-                                     "\"visibilitychange.hidden\"",
-                                     "\"unload\""};
-  std::string message;
-  while (dom_message_queue.PopMessage(&message)) {
-    EXPECT_EQ(expected_messages[num_messages_received], message);
-    num_messages_received++;
-  }
-  EXPECT_EQ(num_messages_received, 3);
-}
-
 // Only HTTP/HTTPS main document can enter the BackForwardCache.
 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CacheHTTPDocumentOnly) {
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -2150,58 +1129,6 @@
   delete_rfh_a2.WaitUntilDeleted();
 }
 
-IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,
-                       CanCacheMultiplesPagesOnSameDomain) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  GURL url_b2(embedded_test_server()->GetURL("b.com", "/title1.html"));
-  GURL url_a3(embedded_test_server()->GetURL("a.com", "/title2.html"));
-  GURL url_b4(embedded_test_server()->GetURL("b.com", "/title2.html"));
-
-  // 1) Navigate to A1.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a1));
-  RenderFrameHostImpl* rfh_a1 = current_frame_host();
-
-  // 2) Navigate to B2.
-  EXPECT_TRUE(NavigateToURL(shell(), url_b2));
-  RenderFrameHostImpl* rfh_b2 = current_frame_host();
-  EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
-
-  // 3) Navigate to A3.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a3));
-  RenderFrameHostImpl* rfh_a3 = current_frame_host();
-  EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
-  // A1 and A3 shouldn't be treated as the same site instance.
-  EXPECT_NE(rfh_a1->GetSiteInstance(), rfh_a3->GetSiteInstance());
-
-  // 4) Navigate to B4.
-  // Make sure we can store A1 and A3 in the cache at the same time.
-  EXPECT_TRUE(NavigateToURL(shell(), url_b4));
-  RenderFrameHostImpl* rfh_b4 = current_frame_host();
-  EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_a3->IsInBackForwardCache());
-
-  // 5) Go back to A3.
-  // Make sure we can restore A3, while A1 remains in the cache.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_b4->IsInBackForwardCache());
-  EXPECT_EQ(rfh_a3, current_frame_host());
-  // B2 and B4 shouldn't be treated as the same site instance.
-  EXPECT_NE(rfh_b2->GetSiteInstance(), rfh_b4->GetSiteInstance());
-
-  // 6) Do a history navigation back to A1.
-  // Make sure we can restore A1, while coming from A3.
-  ASSERT_TRUE(HistoryGoToIndex(web_contents(), 0));
-  EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_b4->IsInBackForwardCache());
-  EXPECT_TRUE(rfh_a3->IsInBackForwardCache());
-  EXPECT_EQ(rfh_a1, current_frame_host());
-}
-
 class BackForwardCacheBrowserTestSkipSameSiteUnload
     : public BackForwardCacheBrowserTest {
  public:
@@ -2354,140 +1281,6 @@
   // trigger unload handlers and be destroyed directly.
 }
 
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Encoding) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL(
-      "a.com", "/back_forward_cache/charset_windows-1250.html"));
-  GURL url_b(embedded_test_server()->GetURL(
-      "b.com", "/back_forward_cache/charset_utf-8.html"));
-  url::Origin origin_a = url::Origin::Create(url_a);
-  url::Origin origin_b = url::Origin::Create(url_b);
-
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  EXPECT_EQ(web_contents()->GetEncoding(), "windows-1250");
-
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-  EXPECT_EQ(web_contents()->GetEncoding(), "UTF-8");
-
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  EXPECT_EQ(web_contents()->GetEncoding(), "windows-1250");
-}
-
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       DoesNotCacheCrossSiteHttpPost) {
-  SetupCrossSiteRedirector(embedded_test_server());
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  // Note we do a cross-site post because same-site navigations of any kind
-  // aren't cached currently.
-  GURL form_url(embedded_test_server()->GetURL(
-      "a.com", "/form_that_posts_cross_site.html"));
-  GURL redirect_target_url(embedded_test_server()->GetURL("x.com", "/echoall"));
-  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
-
-  // Navigate to the page with form that posts via 307 redirection to
-  // |redirect_target_url| (cross-site from |form_url|).
-  EXPECT_TRUE(NavigateToURL(shell(), form_url));
-
-  // Submit the form.
-  TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
-  EXPECT_TRUE(ExecJs(shell(), "document.getElementById('text-form').submit()"));
-  form_post_observer.Wait();
-
-  // Verify that we arrived at the expected, redirected location.
-  EXPECT_EQ(redirect_target_url,
-            shell()->web_contents()->GetLastCommittedURL());
-  RenderFrameDeletedObserver delete_observer_rfh(current_frame_host());
-
-  // Navigate away. |redirect_target_url|'s page should not be cached.
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  delete_observer_rfh.WaitUntilDeleted();
-}
-
-// On windows, the expected value is off by ~20ms. In order to get the
-// feature out to canary, the test is disabled for WIN.
-// TODO(crbug.com/1022191): Fix this for Win.
-// TODO(crbug.com/1211428): Flaky on other platforms.
-// Make sure we are exposing the duration between back navigation's
-// navigationStart and the page's original navigationStart through pageshow
-// event's timeStamp, and that we aren't modifying
-// performance.timing.navigationStart.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DISABLED_NavigationStart) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL(
-      "a.com", "/back_forward_cache/record_navigation_start_time_stamp.html"));
-  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
-
-  // 1) Navigate to A.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
-
-  double initial_page_show_time_stamp =
-      EvalJs(shell(), "window.initialPageShowTimeStamp").ExtractDouble();
-  EXPECT_DOUBLE_EQ(
-      initial_page_show_time_stamp,
-      EvalJs(shell(), "window.latestPageShowTimeStamp").ExtractDouble());
-  double initial_navigation_start =
-      EvalJs(shell(), "window.initialNavigationStart").ExtractDouble();
-
-  // 2) Navigate to B. A should be in the back forward cache.
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-
-  // 3) Navigate back and expect everything to be restored.
-  NavigationHandleObserver observer(web_contents(), url_a);
-  base::TimeTicks time_before_navigation = base::TimeTicks::Now();
-  double js_time_before_navigation =
-      EvalJs(shell(), "performance.now()").ExtractDouble();
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  base::TimeTicks time_after_navigation = base::TimeTicks::Now();
-  double js_time_after_navigation =
-      EvalJs(shell(), "performance.now()").ExtractDouble();
-
-  // The navigation start time should be between the time we saved just before
-  // calling GoBack() and the time we saved just after calling GoBack().
-  base::TimeTicks back_navigation_start = observer.navigation_start();
-  EXPECT_LT(time_before_navigation, back_navigation_start);
-  EXPECT_GT(time_after_navigation, back_navigation_start);
-
-  // Check JS values. window.initialNavigationStart should not change.
-  EXPECT_DOUBLE_EQ(
-      initial_navigation_start,
-      EvalJs(shell(), "window.initialNavigationStart").ExtractDouble());
-  // performance.timing.navigationStart should not change.
-  EXPECT_DOUBLE_EQ(
-      initial_navigation_start,
-      EvalJs(shell(), "performance.timing.navigationStart").ExtractDouble());
-  // window.initialPageShowTimeStamp should not change.
-  EXPECT_DOUBLE_EQ(
-      initial_page_show_time_stamp,
-      EvalJs(shell(), "window.initialPageShowTimeStamp").ExtractDouble());
-  // window.latestPageShowTimeStamp should be updated with the timestamp of the
-  // last pageshow event, which occurs after the page is restored. This should
-  // be greater than the initial pageshow event's timestamp.
-  double latest_page_show_time_stamp =
-      EvalJs(shell(), "window.latestPageShowTimeStamp").ExtractDouble();
-  EXPECT_LT(initial_page_show_time_stamp, latest_page_show_time_stamp);
-
-  // |latest_page_show_time_stamp| should be the duration between initial
-  // navigation start and |back_navigation_start|. Note that since
-  // performance.timing.navigationStart returns a 64-bit integer instead of
-  // double, we might be losing somewhere between 0 to 1 milliseconds of
-  // precision, hence the usage of EXPECT_NEAR.
-  EXPECT_NEAR(
-      (back_navigation_start - base::TimeTicks::UnixEpoch()).InMillisecondsF(),
-      latest_page_show_time_stamp + initial_navigation_start, 1.0);
-  // Expect that the back navigation start value calculated from the JS results
-  // are between time taken before & after navigation, just like
-  // |before_navigation_start|.
-  EXPECT_LT(js_time_before_navigation, latest_page_show_time_stamp);
-  EXPECT_GT(js_time_after_navigation, latest_page_show_time_stamp);
-}
-
 // Do a same document navigation and make sure we do not fire the
 // DidFirstVisuallyNonEmptyPaint again
 IN_PROC_BROWSER_TEST_F(
@@ -2850,28 +1643,6 @@
           ->trial_name()));
 }
 
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       CanUseCacheWhenNavigatingAwayToErrorPage) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  GURL error_url(embedded_test_server()->GetURL("b.com", "/empty.html"));
-  auto url_interceptor = URLLoaderInterceptor::SetupRequestFailForURL(
-      error_url, net::ERR_DNS_TIMED_OUT);
-
-  // 1) Navigate to A.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-
-  // 2) Navigate to an error page and expect the old page to be stored in
-  // bfcache.
-  EXPECT_FALSE(NavigateToURL(shell(), error_url));
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-
-  // 3) Navigate back and expect the page to be restored from bfcache.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-}
-
 // Start an inifite dialogs in JS, yielding after each. The first dialog should
 // be dismissed by navigation. The later dialogs should be handled gracefully
 // and not appear while in BFCache. Finally, when the page comes out of BFCache,
@@ -2988,160 +1759,6 @@
   dialog_waiter.Wait();
 }
 
-// RenderFrameHostImpl::coep_reporter() must be preserved when doing a back
-// navigation using the BackForwardCache.
-// Regression test for https://crbug.com/1102285.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CoepReporter) {
-  ASSERT_TRUE(CreateHttpsServer()->Start());
-  GURL url_a(https_server()->GetURL("a.com",
-                                    "/set-header?"
-                                    "Cross-Origin-Embedder-Policy-Report-Only: "
-                                    "require-corp; report-to%3d\"a\""));
-  GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
-
-  // Navigate to a document that set RenderFrameHostImpl::coep_reporter().
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  EXPECT_TRUE(rfh_a->coep_reporter());
-
-  // Navigate away and back using the BackForwardCache. The
-  // RenderFrameHostImpl::coep_reporter() must still be there.
-  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_EQ(rfh_a, current_frame_host());
-
-  EXPECT_TRUE(rfh_a->coep_reporter());
-}
-
-// RenderFrameHostImpl::coop_reporter() must be preserved when doing a back
-// navigation using the BackForwardCache.
-// Regression test for https://crbug.com/1102285.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CoopReporter) {
-  ASSERT_TRUE(CreateHttpsServer()->Start());
-  GURL url_a(https_server()->GetURL("a.com",
-                                    "/set-header?"
-                                    "Cross-Origin-Opener-Policy-Report-Only: "
-                                    "same-origin; report-to%3d\"a\""));
-  GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
-
-  // Navigate to a document that set RenderFrameHostImpl::coop_reporter().
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  EXPECT_TRUE(rfh_a->coop_access_report_manager()->coop_reporter());
-
-  // Navigate away and back using the BackForwardCache. The
-  // RenderFrameHostImpl::coop_reporter() must still be there.
-  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_EQ(rfh_a, current_frame_host());
-
-  EXPECT_TRUE(rfh_a->coop_access_report_manager()->coop_reporter());
-}
-
-// RenderFrameHostImpl::cross_origin_embedder_policy() must be preserved when
-// doing a back navigation using the BackForwardCache.
-// Regression test for https://crbug.com/1021846.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Coep) {
-  ASSERT_TRUE(CreateHttpsServer()->Start());
-  GURL url_a(https_server()->GetURL(
-      "a.com", "/set-header?Cross-Origin-Embedder-Policy: require-corp"));
-  GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
-
-  // Navigate to a document that sets COEP.
-  network::CrossOriginEmbedderPolicy coep;
-  coep.value = network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImpl* rfh_a = current_frame_host();
-  EXPECT_EQ(coep, rfh_a->cross_origin_embedder_policy());
-
-  // Navigate away and back using the BackForwardCache.
-  // RenderFrameHostImpl::cross_origin_embedder_policy() should return the same
-  // result.
-  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  EXPECT_FALSE(delete_observer_rfh_a.deleted());
-  EXPECT_EQ(rfh_a, current_frame_host());
-
-  EXPECT_EQ(coep, rfh_a->cross_origin_embedder_policy());
-}
-
-// Tests that pagehide and visibilitychange handlers of the old RFH are run for
-// bfcached pages.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       PagehideAndVisibilitychangeRuns) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
-  GURL url_3(embedded_test_server()->GetURL("a.com", "/title2.html"));
-  WebContentsImpl* web_contents =
-      static_cast<WebContentsImpl*>(shell()->web_contents());
-
-  // 1) Navigate to |url_1|.
-  EXPECT_TRUE(NavigateToURL(shell(), url_1));
-  RenderFrameHostImpl* main_frame_1 = web_contents->GetMainFrame();
-
-  // Create a pagehide handler that sets item "pagehide_storage" and a
-  // visibilitychange handler that sets item "visibilitychange_storage" in
-  // localStorage.
-  EXPECT_TRUE(ExecJs(main_frame_1,
-                     R"(
-    localStorage.setItem('pagehide_storage', 'not_dispatched');
-    var dispatched_pagehide = false;
-    window.onpagehide = function(e) {
-      if (dispatched_pagehide) {
-        // We shouldn't dispatch pagehide more than once.
-        localStorage.setItem('pagehide_storage', 'dispatched_more_than_once');
-      } else if (!e.persisted) {
-        localStorage.setItem('pagehide_storage', 'wrong_persisted');
-      } else {
-        localStorage.setItem('pagehide_storage', 'dispatched_once');
-      }
-      dispatched_pagehide = true;
-    }
-    localStorage.setItem('visibilitychange_storage', 'not_dispatched');
-    var dispatched_visibilitychange = false;
-    document.onvisibilitychange = function(e) {
-      if (dispatched_visibilitychange) {
-        // We shouldn't dispatch visibilitychange more than once.
-        localStorage.setItem('visibilitychange_storage',
-          'dispatched_more_than_once');
-      } else if (document.visibilityState != 'hidden') {
-        // We should dispatch the event when the visibilityState is 'hidden'.
-        localStorage.setItem('visibilitychange_storage', 'not_hidden');
-      } else {
-        localStorage.setItem('visibilitychange_storage', 'dispatched_once');
-      }
-      dispatched_visibilitychange = true;
-    }
-  )"));
-
-  // 2) Navigate cross-site to |url_2|. We need to navigate cross-site to make
-  // sure we won't run pagehide and visibilitychange during new page's commit,
-  // which is tested in ProactivelySwapBrowsingInstancesSameSiteTest.
-  EXPECT_TRUE(NavigateToURL(shell(), url_2));
-
-  // |main_frame_1| should be in the back-forward cache.
-  EXPECT_TRUE(main_frame_1->IsInBackForwardCache());
-
-  // 3) Navigate to |url_3| which is same-origin with |url_1|, so we can check
-  // the localStorage values.
-  EXPECT_TRUE(NavigateToURL(shell(), url_3));
-  RenderFrameHostImpl* main_frame_3 = web_contents->GetMainFrame();
-
-  // Check that the value for 'pagehide_storage' and 'visibilitychange_storage'
-  // are set correctly.
-  EXPECT_EQ("dispatched_once",
-            EvalJs(main_frame_3, "localStorage.getItem('pagehide_storage')"));
-  EXPECT_EQ(
-      "dispatched_once",
-      EvalJs(main_frame_3, "localStorage.getItem('visibilitychange_storage')"));
-}
-
 // Tests that pagehide handlers of the old RFH are run for bfcached pages even
 // if the page is already hidden (and visibilitychange won't run).
 // Disabled on Linux and Win because of flakiness, see crbug.com/1170802.
@@ -3476,130 +2093,6 @@
   ExpectRestored(FROM_HERE);
 }
 
-// Tests that the history value saved in the renderer is updated correctly when
-// a page gets restored from the back-forward cache through browser-initiated
-// navigation.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       RendererHistory_BrowserInitiated) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url1(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(b)"));
-  GURL url2(embedded_test_server()->GetURL("a.com", "/title1.html"));
-
-  // 1) Go to |url1|, then |url2|. Both pages should have script to save the
-  // history.length value when getting restored from the back-forward cache.
-  EXPECT_TRUE(NavigateToURL(shell(), url1));
-  FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
-  FrameTreeNode* subframe = root->child_at(0);
-
-  std::string restore_time_length_saver_script =
-      "var resumeLength = -1;"
-      "var pageshowLength = -1;"
-      "document.onresume = () => {"
-      "  resumeLength = history.length;"
-      "};"
-      "window.onpageshow  = () => {"
-      "  pageshowLength = history.length;"
-      "};";
-  EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
-  EXPECT_TRUE(ExecJs(subframe, restore_time_length_saver_script));
-  // We should have one history entry.
-  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 1);
-  EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 1);
-
-  EXPECT_TRUE(NavigateToURL(shell(), url2));
-  EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
-  // We should have two history entries.
-  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
-
-  // 2) Go back to |url1|, browser-initiated.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  EXPECT_EQ(web_contents()->GetLastCommittedURL(), url1);
-
-  // We should still have two history entries, and recorded the correct length
-  // when the 'resume' and 'pageshow' events were dispatched.
-  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(subframe, "resumeLength").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(subframe, "pageshowLength").ExtractInt(), 2);
-
-  // 3) Go forward to |url2|, browser-initiated.
-  ASSERT_TRUE(HistoryGoForward(web_contents()));
-  EXPECT_EQ(web_contents()->GetLastCommittedURL(), url2);
-
-  // We should still have two history entries, and recorded the correct length
-  // when the 'resume' and 'pageshow' events were dispatched.
-  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
-}
-
-// Tests that the history value saved in the renderer is updated correctly when
-// a page gets restored from the back-forward cache through renderer-initiated
-// navigation.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       RendererHistory_RendererInitiated) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  GURL url1(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(b)"));
-  GURL url2(embedded_test_server()->GetURL("a.com", "/title1.html"));
-
-  // 1) Go to |url1|, then |url2|. Both pages should have script to save the
-  // history.length value when getting restored from the back-forward cache.
-  EXPECT_TRUE(NavigateToURL(shell(), url1));
-  FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
-  FrameTreeNode* subframe = root->child_at(0);
-
-  std::string restore_time_length_saver_script =
-      "var resumeLength = -1;"
-      "var pageshowLength = -1;"
-      "document.onresume = () => {"
-      "  resumeLength = history.length;"
-      "};"
-      "window.onpageshow  = () => {"
-      "  pageshowLength = history.length;"
-      "};";
-  EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
-  EXPECT_TRUE(ExecJs(subframe, restore_time_length_saver_script));
-  // We should have one history entry.
-  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 1);
-  EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 1);
-
-  EXPECT_TRUE(NavigateToURL(shell(), url2));
-  EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
-  // We should have two history entries.
-  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
-
-  // 2) Go back to |url1|, renderer-initiated.
-  EXPECT_TRUE(ExecJs(root, "history.back()"));
-  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
-  EXPECT_EQ(web_contents()->GetLastCommittedURL(), url1);
-
-  // We should still have two history entries, and recorded the correct length
-  // when the 'resume' and 'pageshow' events were dispatched.
-  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(subframe, "resumeLength").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(subframe, "pageshowLength").ExtractInt(), 2);
-
-  // 3) Go forward to |url2|, renderer-initiated.
-  EXPECT_TRUE(ExecJs(root, "history.forward()"));
-  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
-
-  EXPECT_EQ(web_contents()->GetLastCommittedURL(), url2);
-
-  // We should still have two history entries, and recorded the correct length
-  // when the 'resume' and 'pageshow' events were dispatched.
-  EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
-  EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
-}
-
 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
                        MainDocumentCSPHeadersAreRestored) {
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -3731,25 +2224,6 @@
       {}, {ShouldSwapBrowsingInstance::kNo_DoesNotHaveSite}, {}, {}, FROM_HERE);
 }
 
-// Check that an eligible page is cached when navigating to about:blank.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       NavigatingToAboutBlankDoesNotPreventCaching) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  // 1) Navigate to a.com,
-  GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-
-  // 2) Navigate to about:blank.
-  GURL blank_url(url::kAboutBlankURL);
-  EXPECT_TRUE(NavigateToURL(shell(), blank_url));
-
-  // 3) Navigate back to a.com.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-
-  ExpectRestored(FROM_HERE);
-}
-
 // Check that browsing instances are not swapped when a navigation redirects
 // toward the last committed URL and the reasons are recorded correctly.
 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, RedirectToSelf) {
@@ -3792,37 +2266,6 @@
       FROM_HERE);
 }
 
-// Check that the response 204 No Content doesn't affect back-forward cache.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, NoContent) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  NavigationControllerImpl& controller = web_contents()->GetController();
-
-  // 1) Navigate to a.com.
-  GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  EXPECT_EQ(1, controller.GetEntryCount());
-  EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL());
-
-  // 2) Navigate to b.com
-  GURL url_b(embedded_test_server()->GetURL("b.com", "/empty.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  EXPECT_EQ(2, controller.GetEntryCount());
-  EXPECT_EQ(url_b, controller.GetLastCommittedEntry()->GetURL());
-
-  // 3) Navigate to c.com with 204 No Content, then the URL will still be b.com.
-  GURL url_c(embedded_test_server()->GetURL("c.com", "/echo?status=204"));
-  EXPECT_TRUE(NavigateToURL(shell(), url_c, url_b));
-  EXPECT_EQ(2, controller.GetEntryCount());
-  EXPECT_EQ(url_b, controller.GetLastCommittedEntry()->GetURL());
-
-  // 4) Navigate back to a.com.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  EXPECT_EQ(2, controller.GetEntryCount());
-  EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL());
-
-  ExpectRestored(FROM_HERE);
-}
-
 // Check that reloading doesn't affect the back-forward cache usage.
 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, ReloadDoesntAffectCache) {
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -4293,8 +2736,10 @@
                        FencedFramePageNotStoredInBackForwardCache) {
   ASSERT_TRUE(embedded_test_server()->Start());
   GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
-  GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
+  GURL url_b(
+      embedded_test_server()->GetURL("b.com", "/fenced_frames/title1.html"));
+  GURL url_c(
+      embedded_test_server()->GetURL("c.com", "/fenced_frames/title1.html"));
 
   // 1) Navigate to A.
   EXPECT_TRUE(NavigateToURL(shell(), url_a));
@@ -4315,64 +2760,6 @@
     EXPECT_FALSE(fenced_frame_host->IsInBackForwardCache());
 }
 
-// A testing subclass that limits the cache size to 1 for ease of testing
-// evictions.
-class CacheSizeOneBackForwardCacheBrowserTest
-    : public BackForwardCacheBrowserTest {
- protected:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    EnableFeatureAndSetParams(features::kBackForwardCache, "cache_size",
-                              base::NumberToString(1));
-    BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
-  }
-};
-
-IN_PROC_BROWSER_TEST_F(CacheSizeOneBackForwardCacheBrowserTest,
-                       ReplacedNavigationEntry) {
-  // Set the bfcache value to 1 to ensure that the test fails if a page
-  // that replaces the current history entry is stored in back-forward cache.
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url_a(embedded_test_server()->GetURL("a.test", "/title1.html"));
-  GURL url_b(embedded_test_server()->GetURL("b.test", "/title1.html"));
-  GURL url_c(embedded_test_server()->GetURL("c.test", "/title1.html"));
-
-  // 1) Navigate to A.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
-  RenderFrameHostImplWrapper rfh_a(current_frame_host());
-
-  // 2) Navigate to B.
-  EXPECT_TRUE(NavigateToURL(shell(), url_b));
-  RenderFrameHostImplWrapper rfh_b(current_frame_host());
-  EXPECT_FALSE(rfh_a.IsRenderFrameDeleted());
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-  EXPECT_FALSE(rfh_b->IsInBackForwardCache());
-
-  // 3) Navigate to a new page by replacing the location. The old page can't
-  // be navigated back to and we should not store it in the back-forward
-  // cache.
-  EXPECT_TRUE(
-      ExecJs(shell(), JsReplace("window.location.replace($1);", url_c)));
-  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
-  RenderFrameHostImplWrapper rfh_c(current_frame_host());
-
-  // 4) Confirm A is still in BackForwardCache and it wasn't evicted due to the
-  // cache size limit, which would happen if we tried to store a new page in the
-  // cache in the previous step.
-  EXPECT_FALSE(rfh_a.IsRenderFrameDeleted());
-  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
-
-  // 5) Confirm that navigating backwards goes back to A.
-  ASSERT_TRUE(HistoryGoBack(shell()->web_contents()));
-  EXPECT_EQ(rfh_a.get(), current_frame_host());
-  EXPECT_FALSE(rfh_a->IsInBackForwardCache());
-  EXPECT_EQ(rfh_a->GetVisibilityState(), PageVisibilityState::kVisible);
-
-  // Go forward again, should return to C
-  ASSERT_TRUE(HistoryGoForward(shell()->web_contents()));
-  EXPECT_EQ(rfh_c.get(), current_frame_host());
-  EXPECT_EQ(rfh_c->GetVisibilityState(), PageVisibilityState::kVisible);
-}
-
 // BEFORE ADDING A NEW TEST HERE
 // Read the note at the top about the other files you could add it to.
 }  // namespace content
diff --git a/content/browser/back_forward_cache_internal_browsertest.cc b/content/browser/back_forward_cache_internal_browsertest.cc
index c928367..e5e3c13 100644
--- a/content/browser/back_forward_cache_internal_browsertest.cc
+++ b/content/browser/back_forward_cache_internal_browsertest.cc
@@ -3579,10 +3579,12 @@
 // Test that a series of cross-site navigations (which use different processes)
 // use the background limit.
 //
-// TODO(crbug.com/1203418): This test is flaky.
+// TODO(crbug.com/1203418): This test is flaky. It has been reenabled with
+// improved failure output (https://crrev.com/c/2862346). It's OK to disable it
+// again when it fails.
 IN_PROC_BROWSER_TEST_F(
     BackgroundForegroundProcessLimitBackForwardCacheBrowserTest,
-    DISABLED_CacheEvictionCrossSite) {
+    CacheEvictionCrossSite) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
   std::vector<RenderFrameHostImplWrapper> rfhs;
diff --git a/content/browser/background_fetch/background_fetch_registration_service_impl.h b/content/browser/background_fetch/background_fetch_registration_service_impl.h
index 9e8d692..ac5ad21 100644
--- a/content/browser/background_fetch/background_fetch_registration_service_impl.h
+++ b/content/browser/background_fetch/background_fetch_registration_service_impl.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_REGISTRATION_SERVICE_IMPL_H_
 #define CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_REGISTRATION_SERVICE_IMPL_H_
 
+#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "content/browser/background_fetch/background_fetch_context.h"
 #include "content/browser/background_fetch/background_fetch_registration_id.h"
diff --git a/content/browser/browser_main.cc b/content/browser/browser_main.cc
index fd2d08a8..cda2322 100644
--- a/content/browser/browser_main.cc
+++ b/content/browser/browser_main.cc
@@ -12,28 +12,9 @@
 
 namespace content {
 
-namespace {
-
-// Generates a pair of BrowserMain async events. We don't use the TRACE_EVENT0
-// macro because the tracing infrastructure doesn't expect synchronous events
-// around the main loop of a thread.
-class ScopedBrowserMainEvent {
- public:
-  ScopedBrowserMainEvent() {
-    TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("startup", "BrowserMain",
-                                      TRACE_ID_WITH_SCOPE("BrowserMain", 0));
-  }
-  ~ScopedBrowserMainEvent() {
-    TRACE_EVENT_NESTABLE_ASYNC_END0("startup", "BrowserMain",
-                                    TRACE_ID_WITH_SCOPE("BrowserMain", 0));
-  }
-};
-
-}  // namespace
-
 // Main routine for running as the Browser process.
 int BrowserMain(MainFunctionParams parameters) {
-  ScopedBrowserMainEvent scoped_browser_main_event;
+  TRACE_EVENT_INSTANT0("startup", "BrowserMain", TRACE_EVENT_SCOPE_THREAD);
 
   base::trace_event::TraceLog::GetInstance()->set_process_name("Browser");
   base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex(
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h
index 475ca9f..5f19adb1 100644
--- a/content/browser/browser_main_loop.h
+++ b/content/browser/browser_main_loop.h
@@ -21,10 +21,6 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/buildflags.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "content/browser/media/keyboard_mic_registration.h"
-#endif
-
 #if defined(USE_AURA)
 namespace aura {
 class Env;
@@ -187,9 +183,6 @@
   net::NetworkChangeNotifier* network_change_notifier() const {
     return network_change_notifier_.get();
   }
-  KeyboardMicRegistration* keyboard_mic_registration() {
-    return &keyboard_mic_registration_;
-  }
 #endif
 
   midi::MidiService* midi_service() const { return midi_service_.get(); }
@@ -392,9 +385,6 @@
   scoped_refptr<responsiveness::Watcher> responsiveness_watcher_;
 
   // Members not associated with a specific phase.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  KeyboardMicRegistration keyboard_mic_registration_;
-#endif
   std::unique_ptr<SmsProvider> sms_provider_;
 
   // DO NOT add members here. Add them to the right categories above.
diff --git a/content/browser/compute_pressure/compute_pressure_sampler_unittest.cc b/content/browser/compute_pressure/compute_pressure_sampler_unittest.cc
index 1da3eff0..2f72e6b0 100644
--- a/content/browser/compute_pressure/compute_pressure_sampler_unittest.cc
+++ b/content/browser/compute_pressure/compute_pressure_sampler_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "content/browser/compute_pressure/compute_pressure_sampler.h"
+#include "build/build_config.h"
 
 #include <cstddef>
 #include <memory>
@@ -177,7 +178,15 @@
                             {.cpu_utilization = 0.4, .cpu_speed = 0.6})));
 }
 
-TEST_F(ComputePressureSamplerTest, Stop_Delayed_EnsureStarted_Immediate) {
+// TODO(crbug.com/1271419): Flaky.
+#if defined(OS_LINUX) || defined(OS_FUCHSIA)
+#define MAYBE_Stop_Delayed_EnsureStarted_Immediate \
+  DISABLED_Stop_Delayed_EnsureStarted_Immediate
+#else
+#define MAYBE_Stop_Delayed_EnsureStarted_Immediate \
+  Stop_Delayed_EnsureStarted_Immediate
+#endif
+TEST_F(ComputePressureSamplerTest, MAYBE_Stop_Delayed_EnsureStarted_Immediate) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   sampler_->EnsureStarted();
diff --git a/content/browser/content_security_policy_browsertest.cc b/content/browser/content_security_policy_browsertest.cc
index 0cc8154c..22d3033f 100644
--- a/content/browser/content_security_policy_browsertest.cc
+++ b/content/browser/content_security_policy_browsertest.cc
@@ -100,6 +100,46 @@
   console_observer.Wait();
 }
 
+IN_PROC_BROWSER_TEST_F(ContentSecurityPolicyBrowserTest,
+                       WildcardNotMatchingNonNetworkSchemeBrowserSide) {
+  const char* page = R"(
+    data:text/html,
+    <meta http-equiv="Content-Security-Policy" content="frame-src *">
+    <iframe src="mailto:arthursonzogni@chromium.org"></iframe>
+  )";
+
+  GURL url(page);
+  WebContentsConsoleObserver console_observer(web_contents());
+  console_observer.SetPattern(
+      "Refused to frame '' because it violates the following Content Security "
+      "Policy directive: \"frame-src *\". Note that '*' matches only URLs with "
+      "network schemes ('http', 'https', 'ws', 'wss'), or URLs whose scheme "
+      "matches `self`'s scheme. mailto:' must be added explicitely.\n");
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+  console_observer.Wait();
+}
+
+IN_PROC_BROWSER_TEST_F(ContentSecurityPolicyBrowserTest,
+                       WildcardNotMatchingNonNetworkSchemeRendererSide) {
+  const char* page = R"(
+    data:text/html,
+    <meta http-equiv="Content-Security-Policy" content="script-src *">
+    <script src="mailto:arthursonzogni@chromium.org"></script>
+  )";
+
+  GURL url(page);
+  WebContentsConsoleObserver console_observer(web_contents());
+  console_observer.SetPattern(
+      "Refused to load the script 'mailto:arthursonzogni@chromium.org' because "
+      "it violates the following Content Security Policy directive: "
+      "\"script-src *\". Note that 'script-src-elem' was not explicitly set, "
+      "so 'script-src' is used as a fallback. Note that '*' matches only URLs "
+      "with network schemes ('http', 'https', 'ws', 'wss'), or URLs whose "
+      "scheme matches `self`'s scheme. mailto:' must be added explicitely.\n");
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+  console_observer.Wait();
+}
+
 namespace {
 
 base::FilePath TestFilePath(const char* filename) {
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 7aa8e6e5..0e09335 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -200,7 +200,12 @@
       DCHECK(serialized);
       devtools_cookie->SetPartitionKey(serialized_partition_key);
     } else {
-      devtools_cookie->SetPartitionKeyOpaque(true);
+      devtools_cookie->SetPartitionKeyOpaque(partition_key->site().opaque());
+      // IsSerializeable may return false when the partition key's site is not
+      // opaque since we introduced nonce-based cookie partitioning in
+      // https://crrev.com/c/3285244.
+      // TODO(1225444,1229638): Surface nonce-based cookie partition keys in
+      // DevTools.
     }
   }
   return devtools_cookie;
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index 8ce952c4..0dde926 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -25,6 +25,7 @@
 #include "content/browser/renderer_host/frame_tree_node.h"
 #include "content/browser/renderer_host/navigation_request.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/cors_origin_pattern_setter.h"
 #include "content/public/browser/devtools_agent_host_client.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/browser/web_contents.h"
@@ -1124,6 +1125,7 @@
     Maybe<bool> in_disposeOnDetach,
     Maybe<String> in_proxyServer,
     Maybe<String> in_proxyBypassList,
+    Maybe<protocol::Array<String>> in_originsToGrantUniversalNetworkAccess,
     std::unique_ptr<CreateBrowserContextCallback> callback) {
   if (access_mode_ != AccessMode::kBrowser) {
     callback->sendFailure(Response::ServerError(kNotAllowedError));
@@ -1155,6 +1157,32 @@
     return;
   }
 
+  if (in_originsToGrantUniversalNetworkAccess.isJust()) {
+    std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns;
+    allow_patterns.push_back(network::mojom::CorsOriginPattern::New());
+    allow_patterns.back()->protocol = "http";
+    allow_patterns.back()->priority =
+        network::mojom::CorsOriginAccessMatchPriority::kMaxPriority;
+    allow_patterns.push_back(network::mojom::CorsOriginPattern::New());
+    allow_patterns.back()->protocol = "https";
+    allow_patterns.back()->priority =
+        network::mojom::CorsOriginAccessMatchPriority::kMaxPriority;
+
+    for (const auto& origin_str :
+         *in_originsToGrantUniversalNetworkAccess.fromJust()) {
+      GURL url(origin_str);
+      url::Origin origin = url::Origin::Create(url);
+      if (!url.is_valid() || origin.opaque()) {
+        delegate->DisposeBrowserContext(context, base::DoNothing());
+        callback->sendFailure(Response::InvalidParams("Invalid origin"));
+        return;
+      }
+      content::CorsOriginPatternSetter::Set(context, std::move(origin),
+                                            mojo::Clone(allow_patterns), {},
+                                            base::DoNothing());
+    }
+  }
+
   if (pending_proxy_config_) {
     contexts_with_overridden_proxy_[context->UniqueId()] =
         std::move(*pending_proxy_config_);
diff --git a/content/browser/devtools/protocol/target_handler.h b/content/browser/devtools/protocol/target_handler.h
index 8d0a107..36842cb 100644
--- a/content/browser/devtools/protocol/target_handler.h
+++ b/content/browser/devtools/protocol/target_handler.h
@@ -99,6 +99,7 @@
       Maybe<bool> in_disposeOnDetach,
       Maybe<String> in_proxyServer,
       Maybe<String> in_proxyBypassList,
+      Maybe<protocol::Array<String>> in_originsToGrantUniversalNetworkAccess,
       std::unique_ptr<CreateBrowserContextCallback> callback) override;
   void DisposeBrowserContext(
       const std::string& context_id,
diff --git a/content/browser/fenced_frame/fenced_frame_browsertest.cc b/content/browser/fenced_frame/fenced_frame_browsertest.cc
index 0d0faec..0a3bd99 100644
--- a/content/browser/fenced_frame/fenced_frame_browsertest.cc
+++ b/content/browser/fenced_frame/fenced_frame_browsertest.cc
@@ -130,13 +130,12 @@
       .Times(0);
 
   RenderFrameHostImpl* primary_rfh = primary_main_frame_host();
-  RenderFrameHost* fenced_frame_rfh =
-      fenced_frame_test_helper().CreateFencedFrame(primary_rfh, main_url);
 
   const GURL fenced_frame_url = embedded_test_server()->GetURL(
       "fencedframe.test", "/fenced_frames/title1.html");
-  fenced_frame_rfh = fenced_frame_test_helper().NavigateFrameInFencedFrameTree(
-      fenced_frame_rfh, fenced_frame_url);
+  RenderFrameHost* fenced_frame_rfh =
+      fenced_frame_test_helper().CreateFencedFrame(primary_rfh,
+                                                   fenced_frame_url);
 
   // Test that a fenced frame navigation does not impact the primary main
   // frame...
@@ -150,12 +149,14 @@
 IN_PROC_BROWSER_TEST_F(FencedFrameBrowserTest, FrameIteration) {
   const GURL main_url =
       embedded_test_server()->GetURL("fencedframe.test", "/title1.html");
-  EXPECT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL(
-                                         "fencedframe.test", "/title1.html")));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
   RenderFrameHostImplWrapper primary_rfh(primary_main_frame_host());
+
+  const GURL fenced_frame_url = embedded_test_server()->GetURL(
+      "fencedframe.test", "/fenced_frames/title1.html");
   RenderFrameHostImplWrapper fenced_frame_rfh(
       fenced_frame_test_helper().CreateFencedFrame(primary_rfh.get(),
-                                                   main_url));
+                                                   fenced_frame_url));
 
   // Test that the outer => inner delegate mechanism works correctly.
   EXPECT_THAT(CollectAllRenderFrameHosts(primary_rfh.get()),
diff --git a/content/browser/file_system_access/file_system_access_directory_handle_impl.h b/content/browser/file_system_access/file_system_access_directory_handle_impl.h
index 6d70b89..67b1aac 100644
--- a/content/browser/file_system_access/file_system_access_directory_handle_impl.h
+++ b/content/browser/file_system_access/file_system_access_directory_handle_impl.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_BROWSER_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_DIRECTORY_HANDLE_IMPL_H_
 #define CONTENT_BROWSER_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_DIRECTORY_HANDLE_IMPL_H_
 
+#include "base/compiler_specific.h"
 #include "base/files/file.h"
 #include "base/memory/weak_ptr.h"
 #include "components/services/filesystem/public/mojom/types.mojom.h"
diff --git a/content/browser/indexed_db/indexed_db_backing_store.h b/content/browser/indexed_db/indexed_db_backing_store.h
index a5746ebf..8f3729f6 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.h
+++ b/content/browser/indexed_db/indexed_db_backing_store.h
@@ -15,6 +15,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/dcheck_is_on.h"
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
diff --git a/content/browser/indexed_db/indexed_db_index_writer.h b/content/browser/indexed_db/indexed_db_index_writer.h
index 168f1fa3..221c1e39 100644
--- a/content/browser/indexed_db/indexed_db_index_writer.h
+++ b/content/browser/indexed_db/indexed_db_index_writer.h
@@ -12,6 +12,7 @@
 #include <string>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "content/browser/indexed_db/indexed_db_backing_store.h"
 #include "content/browser/indexed_db/indexed_db_database.h"
 #include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding.h b/content/browser/indexed_db/indexed_db_leveldb_coding.h
index 536da74..7f67311e 100644
--- a/content/browser/indexed_db/indexed_db_leveldb_coding.h
+++ b/content/browser/indexed_db/indexed_db_leveldb_coding.h
@@ -13,6 +13,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_piece.h"
 #include "components/services/storage/indexed_db/scopes/scope_lock_range.h"
diff --git a/content/browser/indexed_db/indexed_db_leveldb_operations.h b/content/browser/indexed_db/indexed_db_leveldb_operations.h
index b6b68ad..8a815de 100644
--- a/content/browser/indexed_db/indexed_db_leveldb_operations.h
+++ b/content/browser/indexed_db/indexed_db_leveldb_operations.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/strings/string_piece.h"
diff --git a/content/browser/indexed_db/indexed_db_metadata_coding.h b/content/browser/indexed_db/indexed_db_metadata_coding.h
index 627db46..456e588 100644
--- a/content/browser/indexed_db/indexed_db_metadata_coding.h
+++ b/content/browser/indexed_db/indexed_db_metadata_coding.h
@@ -10,6 +10,7 @@
 #include <string>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "content/common/content_export.h"
 #include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
diff --git a/content/browser/indexed_db/indexed_db_storage_key_state.h b/content/browser/indexed_db/indexed_db_storage_key_state.h
index 8f06adfd..df70acb 100644
--- a/content/browser/indexed_db/indexed_db_storage_key_state.h
+++ b/content/browser/indexed_db/indexed_db_storage_key_state.h
@@ -10,6 +10,7 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/compiler_specific.h"
 #include "base/containers/flat_map.h"
 #include "base/feature_list.h"
 #include "base/gtest_prod_util.h"
diff --git a/content/browser/loader/cors_origin_pattern_setter_browsertest.cc b/content/browser/loader/cors_origin_pattern_setter_browsertest.cc
index 2934236..085ddaf2 100644
--- a/content/browser/loader/cors_origin_pattern_setter_browsertest.cc
+++ b/content/browser/loader/cors_origin_pattern_setter_browsertest.cc
@@ -13,10 +13,12 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/cors_origin_pattern_setter.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
+#include "content/public/test/test_browser_context.h"
 #include "content/shell/browser/shell.h"
 #include "net/base/host_port_pair.h"
 #include "net/dns/mock_host_resolver.h"
@@ -88,7 +90,7 @@
 
       base::RunLoop run_loop;
       CorsOriginPatternSetter::Set(
-          web_contents()->GetBrowserContext(),
+          browser_context(),
           url::Origin::Create(
               embedded_test_server()->base_url().DeprecatedGetOriginAsURL()),
           std::move(list), std::vector<network::mojom::CorsOriginPatternPtr>(),
@@ -105,7 +107,7 @@
 
       base::RunLoop run_loop;
       CorsOriginPatternSetter::Set(
-          web_contents()->GetBrowserContext(),
+          browser_context(),
           url::Origin::Create(embedded_test_server()
                                   ->GetURL(kTestHost, "/")
                                   .DeprecatedGetOriginAsURL()),
@@ -120,9 +122,11 @@
   const std::u16string& pass_string() const { return pass_string_; }
   const std::u16string& fail_string() const { return fail_string_; }
 
-  WebContents* web_contents() { return shell()->web_contents(); }
+  virtual WebContents* web_contents() { return shell()->web_contents(); }
+  virtual BrowserContext* browser_context() {
+    return web_contents()->GetBrowserContext();
+  }
 
- private:
   void SetUpOnMainThread() override {
     ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -136,6 +140,7 @@
                              embedded_test_server()->host_port_pair().host());
   }
 
+ private:
   const std::u16string pass_string_ = u"PASS";
   const std::u16string fail_string_ = u"FAIL";
   const std::u16string script_ = u"reason";
@@ -258,4 +263,54 @@
   EXPECT_EQ(fail_string(), watcher->WaitAndGetTitle()) << GetReason();
 }
 
+// Assures that the access lists are properly propagated to the storage
+// partitions and network contexts created after the lists have been set.
+class NewContextCorsOriginPatternSetterBrowserTest
+    : public CorsOriginPatternSetterBrowserTest {
+ protected:
+  void SetUpOnMainThread() override {
+    browser_context_ = std::make_unique<TestBrowserContext>();
+    CorsOriginPatternSetterBrowserTest::SetUpOnMainThread();
+  }
+
+  void TearDownOnMainThread() override {
+    web_contents_.reset();
+    CorsOriginPatternSetterBrowserTest::TearDownOnMainThread();
+  }
+
+  void TearDown() override {
+    content::GetUIThreadTaskRunner({})->DeleteSoon(FROM_HERE,
+                                                   browser_context_.release());
+    CorsOriginPatternSetterBrowserTest::TearDown();
+  }
+
+  NewContextCorsOriginPatternSetterBrowserTest() = default;
+
+  WebContents* web_contents() override { return web_contents_.get(); }
+  BrowserContext* browser_context() override { return browser_context_.get(); }
+
+  void CreateWebContents() {
+    web_contents_ = content::WebContents::Create(
+        content::WebContents::CreateParams(browser_context_.get()));
+  }
+
+ private:
+  std::unique_ptr<BrowserContext> browser_context_;
+  std::unique_ptr<WebContents> web_contents_;
+};
+
+IN_PROC_BROWSER_TEST_F(NewContextCorsOriginPatternSetterBrowserTest,
+                       PatternListPropagation) {
+  SetAllowList("http", "", kAllowSubdomains);
+  CreateWebContents();
+
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
+  EXPECT_TRUE(NavigateToURL(
+      web_contents(),
+      embedded_test_server()->GetURL(
+          kTestHost,
+          base::StringPrintf("%s?target=%s", kTestPath, host_ip().c_str()))));
+  EXPECT_EQ(pass_string(), watcher->WaitAndGetTitle()) << GetReason();
+}
+
 }  // namespace content
diff --git a/content/browser/loader/loader_browsertest.cc b/content/browser/loader/loader_browsertest.cc
index df61fa75..548f43f 100644
--- a/content/browser/loader/loader_browsertest.cc
+++ b/content/browser/loader/loader_browsertest.cc
@@ -831,7 +831,8 @@
   EXPECT_TRUE(image_request->load_flags & net::LOAD_PREFETCH);
 }
 
-IN_PROC_BROWSER_TEST_F(RequestDataBrowserTest, BasicCrossSite) {
+// TODO(crbug.com/1271868): Flaky on all platforms.
+IN_PROC_BROWSER_TEST_F(RequestDataBrowserTest, DISABLED_BasicCrossSite) {
   GURL top_url(embedded_test_server()->GetURL(
       "a.com", "/nested_page_with_subresources.html"));
   GURL nested_url(embedded_test_server()->GetURL(
diff --git a/content/browser/loader/navigation_url_loader_delegate.h b/content/browser/loader/navigation_url_loader_delegate.h
index 2e91989..56d61b0df 100644
--- a/content/browser/loader/navigation_url_loader_delegate.h
+++ b/content/browser/loader/navigation_url_loader_delegate.h
@@ -76,8 +76,7 @@
   // |navigation_data| is passed to the NavigationHandle.
   // |subresource_loader_params| is used in the network service only for passing
   // necessary info to create a custom subresource loader in the renderer
-  // process if the navigated context is controlled by a request interceptor
-  // like AppCache or ServiceWorker.
+  // process if the navigated context is controlled by a request interceptor.
   //
   // |is_download| is true if the request must be downloaded, if it isn't
   // disallowed.
diff --git a/content/browser/loader/navigation_url_loader_impl_unittest.cc b/content/browser/loader/navigation_url_loader_impl_unittest.cc
index 4cb2abc2..3bea074 100644
--- a/content/browser/loader/navigation_url_loader_impl_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_impl_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "content/browser/loader/navigation_url_loader_impl.h"
+#include "build/build_config.h"
 
 #include <memory>
 #include <string>
@@ -526,7 +527,14 @@
 
 // Like NavigationTimeoutTest but the navigation initially results in a redirect
 // before hanging, to test a slightly more complicated navigation.
-TEST_F(NavigationURLLoaderImplTest, NavigationTimeoutRedirectTest) {
+// TODO(crbug.com/1271228): Flaky on Linux.
+#if defined(OS_LINUX)
+#define MAYBE_NavigationTimeoutRedirectTest \
+  DISABLED_NavigationTimeoutRedirectTest
+#else
+#define MAYBE_NavigationTimeoutRedirectTest NavigationTimeoutRedirectTest
+#endif
+TEST_F(NavigationURLLoaderImplTest, MAYBE_NavigationTimeoutRedirectTest) {
   ASSERT_TRUE(http_test_server_.Start());
   const GURL hang_url = http_test_server_.GetURL("/hung");
   const GURL redirect_url =
diff --git a/content/browser/loader/prefetch_browsertest.cc b/content/browser/loader/prefetch_browsertest.cc
index 9b2c8e1..f8a627c 100644
--- a/content/browser/loader/prefetch_browsertest.cc
+++ b/content/browser/loader/prefetch_browsertest.cc
@@ -828,14 +828,8 @@
 // Variants of this test:
 // - PrefetchBrowserTest.CrossOriginWithPreloadAnonymous
 // - PrefetchBrowserTest.CrossOriginWithPreloadCredentialled
-// Disabling due to flakiness, see https://crbug.com/1257939
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MAC)
-#define MAYBE_CrossOriginWithPreloadCredentialled DISABLED_CrossOriginWithPreloadCredentialled
-#else
-#define MAYBE_CrossOriginWithPreloadCredentialled CrossOriginWithPreloadCredentialled
-#endif
 IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest,
-                       MAYBE_CrossOriginWithPreloadCredentialled) {
+                       CrossOriginWithPreloadCredentialled) {
   ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
   const auto port = embedded_test_server()->port();
   const char target_path[] = "/target.html";
diff --git a/content/browser/media/audio_input_stream_broker.cc b/content/browser/media/audio_input_stream_broker.cc
index f3774261..8099720 100644
--- a/content/browser/media/audio_input_stream_broker.cc
+++ b/content/browser/media/audio_input_stream_broker.cc
@@ -24,44 +24,12 @@
 #include "media/base/user_input_monitor.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "content/browser/media/keyboard_mic_registration.h"
-#endif
-
 namespace content {
 
 using DisconnectReason =
     media::mojom::AudioInputStreamObserver::DisconnectReason;
 using InputStreamErrorCode = media::mojom::InputStreamErrorCode;
 
-namespace {
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-enum KeyboardMicAction { kRegister, kDeregister };
-
-void UpdateKeyboardMicRegistration(KeyboardMicAction action) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
-    GetUIThreadTaskRunner({})->PostTask(
-        FROM_HERE, base::BindOnce(&UpdateKeyboardMicRegistration, action));
-    return;
-  }
-  BrowserMainLoop* browser_main_loop = BrowserMainLoop::GetInstance();
-  // May be null in unit tests.
-  if (!browser_main_loop)
-    return;
-  switch (action) {
-    case kRegister:
-      browser_main_loop->keyboard_mic_registration()->Register();
-      return;
-    case kDeregister:
-      browser_main_loop->keyboard_mic_registration()->Deregister();
-      return;
-  }
-}
-#endif
-
-}  // namespace
-
 AudioInputStreamBroker::AudioInputStreamBroker(
     int render_process_id,
     int render_frame_id,
@@ -96,25 +64,11 @@
           switches::kUseFakeDeviceForMediaStream)) {
     params_.set_format(media::AudioParameters::AUDIO_FAKE);
   }
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (params_.channel_layout() ==
-      media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
-    UpdateKeyboardMicRegistration(kRegister);
-  }
-#endif
 }
 
 AudioInputStreamBroker::~AudioInputStreamBroker() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (params_.channel_layout() ==
-      media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
-    UpdateKeyboardMicRegistration(kDeregister);
-  }
-#endif
-
   // This relies on CreateStream() being called synchronously right after the
   // constructor.
   if (user_input_monitor_)
diff --git a/content/browser/media/capture/crop_id_web_contents_helper.cc b/content/browser/media/capture/crop_id_web_contents_helper.cc
new file mode 100644
index 0000000..122c950
--- /dev/null
+++ b/content/browser/media/capture/crop_id_web_contents_helper.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 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 "content/browser/media/capture/crop_id_web_contents_helper.h"
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/containers/contains.h"
+#include "base/guid.h"
+#include "base/token.h"
+#include "build/build_config.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+
+#if defined(OS_ANDROID)
+#error Region Capture not supported on Android.
+#endif
+
+namespace content {
+
+// TODO(crbug.com/1247761): Remove this protected static function.
+// See header for more details.
+base::Token CropIdWebContentsHelper::GUIDToToken(const base::GUID& guid) {
+  std::string lowercase = guid.AsLowercaseString();
+
+  // |lowercase| is either empty, or follows the expected pattern.
+  // TODO(crbug.com/1260380): Resolve open question of correct treatment
+  // of an invalid GUID.
+  if (lowercase.empty()) {
+    return base::Token();
+  }
+  DCHECK_EQ(lowercase.length(), 32u + 4u);  // 32 hex-chars; 4 hyphens.
+
+  base::RemoveChars(lowercase, "-", &lowercase);
+  DCHECK_EQ(lowercase.length(), 32u);  // 32 hex-chars; 0 hyphens.
+
+  base::StringPiece string_piece(lowercase);
+
+  uint64_t high = 0;
+  bool success = base::HexStringToUInt64(string_piece.substr(0, 16), &high);
+  DCHECK(success);
+
+  uint64_t low = 0;
+  success = base::HexStringToUInt64(string_piece.substr(16, 16), &low);
+  DCHECK(success);
+
+  return base::Token(high, low);
+}
+
+CropIdWebContentsHelper::CropIdWebContentsHelper(WebContents* web_contents)
+    : WebContentsObserver(web_contents),
+      WebContentsUserData<CropIdWebContentsHelper>(*web_contents) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(web_contents);
+}
+
+CropIdWebContentsHelper::~CropIdWebContentsHelper() = default;
+
+std::string CropIdWebContentsHelper::ProduceCropId() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  // Prevent Web-applications from producing an excessive number of crop-IDs.
+  if (crop_ids_.size() >= kMaxCropIdsPerWebContents) {
+    return std::string();
+  }
+
+  // Given the exceedingly low likelihood of collisions, the check for
+  // uniqueness could have theoretically been skipped. But it's cheap
+  // enough to perform, given that `kMaxCropIdsPerWebContents` is so small
+  // compared to the space of GUIDs, and it guarantees we never silently fail
+  // the application by cropping to the wrong, duplicate target.
+  base::GUID guid;
+  base::Token crop_id;
+  do {
+    guid = base::GUID::GenerateRandomV4();
+    crop_id = GUIDToToken(guid);
+  } while (IsAssociatedWithCropId(crop_id));
+  crop_ids_.push_back(crop_id);
+
+  return guid.AsLowercaseString();
+}
+
+bool CropIdWebContentsHelper::IsAssociatedWithCropId(
+    const base::Token& crop_id) const {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  return base::Contains(crop_ids_, crop_id);
+}
+
+void CropIdWebContentsHelper::ReadyToCommitNavigation(
+    NavigationHandle* navigation_handle) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(navigation_handle);
+
+  // Cross-document navigation of the top-level frame invalidates all crop-IDs
+  // associated with the observed WebContents.
+  // Using IsInPrimaryMainFrame is valid here since the browser only caches this
+  // state for the active main frame.
+  if (!navigation_handle->IsSameDocument() &&
+      navigation_handle->IsInPrimaryMainFrame()) {
+    ClearCropIds();
+  }
+}
+
+void CropIdWebContentsHelper::ClearCropIds() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  crop_ids_.clear();
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(CropIdWebContentsHelper);
+
+}  // namespace content
diff --git a/content/browser/media/capture/crop_id_web_contents_helper.h b/content/browser/media/capture/crop_id_web_contents_helper.h
new file mode 100644
index 0000000..0c01ed9
--- /dev/null
+++ b/content/browser/media/capture/crop_id_web_contents_helper.h
@@ -0,0 +1,89 @@
+// Copyright (c) 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 CONTENT_BROWSER_MEDIA_CAPTURE_CROP_ID_WEB_CONTENTS_HELPER_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_CROP_ID_WEB_CONTENTS_HELPER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/guid.h"
+#include "base/token.h"
+#include "build/build_config.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+#if defined(OS_ANDROID)
+#error Region Capture not supported on Android.
+#endif
+
+namespace content {
+
+class NavigationHandle;
+
+class CONTENT_EXPORT CropIdWebContentsHelper final
+    : public WebContentsObserver,
+      public WebContentsUserData<CropIdWebContentsHelper> {
+ public:
+  // Limits the number of crop-IDs a given Web-application can produce
+  // so as to limit the potential for abuse.
+  // Known and accepted issue - embedded iframes can be intentionally disruptive
+  // by producing too many crop-IDs. It's up to the Web-application to not
+  // embed such iframes.
+  constexpr static size_t kMaxCropIdsPerWebContents = 100;
+
+  explicit CropIdWebContentsHelper(WebContents* web_contents);
+  CropIdWebContentsHelper(const CropIdWebContentsHelper&) = delete;
+  CropIdWebContentsHelper& operator=(const CropIdWebContentsHelper&) = delete;
+  ~CropIdWebContentsHelper() final;
+
+  // Produces a new crop-ID, records its association with this WebContents
+  // and returns it.
+  // This method can soft-fail if invoked more than |kMaxCropIdsPerWebContents|
+  // times for a given WebContents. Failure is signaled by returning an
+  // empty string.
+  std::string ProduceCropId();
+
+  // Checks whether this WebContents is associated with a crop-ID.
+  // This allows us to check whether a call to cropTo() by the Web-application
+  // is permitted.
+  bool IsAssociatedWithCropId(const base::Token& crop_id) const;
+
+ protected:
+  // TODO(crbug.com/1247761): Remove this local copy of GUIDToToken().
+  // It is copy of a function that is not currently visible from the browser
+  // process. It should be made visible to the browser process and reused
+  // rather than redefined. It is defined as protected so that unit tests
+  // can use it, too.
+  static base::Token GUIDToToken(const base::GUID& guid);
+
+ private:
+  friend class WebContentsUserData<CropIdWebContentsHelper>;
+  friend class CropIdWebContentsHelperTest;
+
+  // WebContentsObserver implementation.
+  // Cross-document navigation of the top-level document discards all crop-IDs
+  // associated with the top-level WebContents.
+  // TODO(crbug.com/1247761): Record per RFH and treat its navigation.
+  void ReadyToCommitNavigation(NavigationHandle* navigation_handle) final;
+
+  // Forgets all associations of crop-IDs to this WebContents.
+  // TODO(crbug.com/1247761): Clear per-RFH or throughout.
+  void ClearCropIds();
+
+  // Records which crop-IDs are associated with this WebContents.
+  // At most |kMaxCropIdsPerWebContents|, as discussed where
+  // |kMaxCropIdsPerWebContents| is defined.
+  std::vector<base::Token> crop_ids_;
+
+  WEB_CONTENTS_USER_DATA_KEY_DECL();
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_MEDIA_CAPTURE_CROP_ID_WEB_CONTENTS_HELPER_H_
diff --git a/content/browser/media/keyboard_mic_registration.cc b/content/browser/media/keyboard_mic_registration.cc
deleted file mode 100644
index 1ac46dbc..0000000
--- a/content/browser/media/keyboard_mic_registration.cc
+++ /dev/null
@@ -1,31 +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 "content/browser/media/keyboard_mic_registration.h"
-
-#include "ash/components/audio/cras_audio_handler.h"
-#include "content/public/browser/browser_thread.h"
-
-namespace content {
-
-KeyboardMicRegistration::KeyboardMicRegistration() = default;
-
-KeyboardMicRegistration::~KeyboardMicRegistration() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK_EQ(0, register_count_);
-}
-
-void KeyboardMicRegistration::Register() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (++register_count_ == 1)
-    ash::CrasAudioHandler::Get()->SetKeyboardMicActive(true);
-}
-
-void KeyboardMicRegistration::Deregister() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (--register_count_ == 0)
-    ash::CrasAudioHandler::Get()->SetKeyboardMicActive(false);
-}
-
-}  // namespace content
diff --git a/content/browser/media/keyboard_mic_registration.h b/content/browser/media/keyboard_mic_registration.h
deleted file mode 100644
index 5cc95a0..0000000
--- a/content/browser/media/keyboard_mic_registration.h
+++ /dev/null
@@ -1,31 +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 CONTENT_BROWSER_MEDIA_KEYBOARD_MIC_REGISTRATION_H_
-#define CONTENT_BROWSER_MEDIA_KEYBOARD_MIC_REGISTRATION_H_
-
-namespace content {
-
-// Chrome OS keyboard mic stream registration. Used on UI thread only and owned
-// by BrowserMainLoop; instance must be obtained through
-// BrowserMainLoop::keyboard_mic_registration().
-class KeyboardMicRegistration {
- public:
-  KeyboardMicRegistration();
-
-  KeyboardMicRegistration(const KeyboardMicRegistration&) = delete;
-  KeyboardMicRegistration& operator=(const KeyboardMicRegistration&) = delete;
-
-  ~KeyboardMicRegistration();
-
-  void Register();
-  void Deregister();
-
- private:
-  int register_count_ = 0;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_MEDIA_KEYBOARD_MIC_REGISTRATION_H_
diff --git a/content/browser/permissions/permission_util.cc b/content/browser/permissions/permission_util.cc
index 7d0662d..993c6d7 100644
--- a/content/browser/permissions/permission_util.cc
+++ b/content/browser/permissions/permission_util.cc
@@ -4,7 +4,6 @@
 
 #include "content/browser/permissions/permission_util.h"
 
-#include "components/permissions/features.h"
 #include "content/public/browser/web_contents.h"
 #include "third_party/blink/public/common/web_preferences/web_preferences.h"
 #include "url/gurl.h"
@@ -26,28 +25,19 @@
     content::RenderFrameHost* render_frame_host) {
   DCHECK(render_frame_host);
 
-  if (base::FeatureList::IsEnabled(
-          permissions::features::kRevisedOriginHandling)) {
-    content::WebContents* web_contents =
-        content::WebContents::FromRenderFrameHost(render_frame_host);
-    // If `allow_universal_access_from_file_urls` flag is enabled, a file can
-    // introduce discrepancy between GetLastCommittedURL and
-    // GetLastCommittedOrigin. In that case GetLastCommittedURL should be used
-    // for requesting and verifying permissions.
-    // Disabling `kRevisedOriginHandling` feature introduces no side effects,
-    // because in both cases we rely on
-    // GetLastCommittedURL().DeprecatedGetOriginAsURL().
-    if (web_contents->GetOrCreateWebPreferences()
-            .allow_universal_access_from_file_urls &&
-        render_frame_host->GetLastCommittedOrigin().GetURL().SchemeIsFile()) {
-      return render_frame_host->GetLastCommittedURL()
-          .DeprecatedGetOriginAsURL();
-    }
-
-    return render_frame_host->GetLastCommittedOrigin().GetURL();
+  content::WebContents* web_contents =
+      content::WebContents::FromRenderFrameHost(render_frame_host);
+  // If `allow_universal_access_from_file_urls` flag is enabled, a file can
+  // introduce discrepancy between GetLastCommittedURL and
+  // GetLastCommittedOrigin. In that case GetLastCommittedURL should be used
+  // for requesting and verifying permissions.
+  if (web_contents->GetOrCreateWebPreferences()
+          .allow_universal_access_from_file_urls &&
+      render_frame_host->GetLastCommittedOrigin().GetURL().SchemeIsFile()) {
+    return render_frame_host->GetLastCommittedURL().DeprecatedGetOriginAsURL();
   }
 
-  return render_frame_host->GetLastCommittedURL().DeprecatedGetOriginAsURL();
+  return render_frame_host->GetLastCommittedOrigin().GetURL();
 }
 
 }  // namespace content
diff --git a/content/browser/prerender/prerender_browsertest.cc b/content/browser/prerender/prerender_browsertest.cc
index 1ba3f96..70a2207 100644
--- a/content/browser/prerender/prerender_browsertest.cc
+++ b/content/browser/prerender/prerender_browsertest.cc
@@ -3487,6 +3487,48 @@
   EXPECT_EQ(web_contents()->GetURL(), kPrerenderingUrl);
 }
 
+// Test that WebContentsObserver::DocumentAvailableInMainFrame is not
+// invoked when the page gets loaded while prerendering but it is deferred and
+// invoked on prerender activation.
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
+                       DocumentAvailableInMainFrameInvokedAfterActivation) {
+  const GURL kInitialUrl = GetUrl("/empty.html");
+  const GURL kPrerenderingUrl = GetUrl("/page_with_iframe.html");
+
+  // Navigate to an initial page.
+  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
+
+  // Initialize a MockWebContentsObserver and ensure that
+  // DocumentAvailableInMainFrame is not invoked while prerendering.
+  testing::NiceMock<MockWebContentsObserver> observer(shell()->web_contents());
+  EXPECT_CALL(observer, DocumentAvailableInMainFrame(testing::_)).Times(0);
+
+  // AddPrerender() below waits until WebContentsObserver::DidStopLoading() is
+  // called and RenderFrameHostImpl::DocumentAvailableInMainFrame() call is
+  // expected before it returns.
+  int prerender_host_id = AddPrerender(kPrerenderingUrl);
+  RenderFrameHostImpl* prerender_frame_host =
+      GetPrerenderedMainFrameHost(prerender_host_id);
+  EXPECT_EQ(prerender_frame_host->child_count(), 1u);
+  ASSERT_NE(prerender_host_id, RenderFrameHost::kNoFrameTreeNodeId);
+
+  // Verify and clear all expectations on the mock observer before setting new
+  // ones.
+  testing::Mock::VerifyAndClearExpectations(&observer);
+  testing::InSequence s;
+
+  // Activate the prerendered page. This should result in invoking
+  // DocumentOnLoadCompletedInMainFrame only for main RenderFrameHost.
+  // Verify that DidFinishNavigation is invoked before
+  // DocumentAvailableInMainFrame on activation.
+  EXPECT_CALL(observer, DidFinishNavigation(testing::_));
+
+  EXPECT_CALL(observer, DocumentAvailableInMainFrame(prerender_frame_host))
+      .Times(1);
+  NavigatePrimaryPage(kPrerenderingUrl);
+  EXPECT_EQ(web_contents()->GetURL(), kPrerenderingUrl);
+}
+
 // Test that WebContentsObserver::LoadProgressChanged is not invoked when the
 // page gets loaded while prerendering but is invoked on prerender activation.
 // Check that LoadProgressChanged is only called once for
diff --git a/content/browser/renderer_host/cross_process_frame_connector.cc b/content/browser/renderer_host/cross_process_frame_connector.cc
index 87c130c..719d28e 100644
--- a/content/browser/renderer_host/cross_process_frame_connector.cc
+++ b/content/browser/renderer_host/cross_process_frame_connector.cc
@@ -365,13 +365,22 @@
     const absl::optional<blink::FrameVisualProperties>& visual_properties) {
   bool intersection_changed = !intersection_state.Equals(intersection_state_);
   if (intersection_changed) {
+    RenderWidgetHostImpl* host = view_ ? view_->host() : nullptr;
+    bool main_frame = host && host->owner_delegate();
     bool visual_properties_changed = false;
     if (visual_properties.has_value()) {
-      absl::optional<blink::VisualProperties> last_properties =
-          view_->host()->LastComputedVisualProperties();
-      SynchronizeVisualProperties(visual_properties.value(), false);
-      visual_properties_changed =
-          last_properties != view_->host()->LastComputedVisualProperties();
+      // Subtlety: RenderWidgetHostViewChildFrame::UpdateViewportIntersection()
+      // will quietly fail to propagate the new intersection state for main
+      // frames, including portals and fenced frames. For those cases, we need
+      // to ensure that the updated VisualProperties are still propagated.
+      absl::optional<blink::VisualProperties> last_properties;
+      if (host && !main_frame)
+        last_properties = host->LastComputedVisualProperties();
+      SynchronizeVisualProperties(visual_properties.value(), main_frame);
+      if (host && !main_frame) {
+        visual_properties_changed =
+            last_properties != host->LastComputedVisualProperties();
+      }
     }
     UpdateViewportIntersectionInternal(intersection_state,
                                        visual_properties_changed);
diff --git a/content/browser/renderer_host/cross_process_frame_connector.h b/content/browser/renderer_host/cross_process_frame_connector.h
index 77a6913c..e9787301a 100644
--- a/content/browser/renderer_host/cross_process_frame_connector.h
+++ b/content/browser/renderer_host/cross_process_frame_connector.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "cc/input/touch_action.h"
 #include "components/viz/common/quads/compositor_frame.h"
diff --git a/content/browser/renderer_host/data_transfer_util.cc b/content/browser/renderer_host/data_transfer_util.cc
index d2f16814..a70ffef 100644
--- a/content/browser/renderer_host/data_transfer_util.cc
+++ b/content/browser/renderer_host/data_transfer_util.cc
@@ -121,6 +121,7 @@
     blink::mojom::DragItemBinaryPtr item = blink::mojom::DragItemBinary::New();
     item->data = mojo_base::BigBuffer(
         base::as_bytes(base::make_span(drop_data.file_contents)));
+    item->is_image_accessible = drop_data.file_contents_image_accessible;
     item->source_url = drop_data.file_contents_source_url;
     item->filename_extension =
         base::FilePath(drop_data.file_contents_filename_extension);
@@ -238,8 +239,8 @@
         const blink::mojom::DragItemBinaryPtr& binary_item = item->get_binary();
         base::span<const uint8_t> contents = base::make_span(binary_item->data);
         result.file_contents.assign(contents.begin(), contents.end());
-        result.file_contents_accessible_from_start_frame =
-            binary_item->is_accessible_from_start_frame;
+        result.file_contents_image_accessible =
+            binary_item->is_image_accessible;
         result.file_contents_source_url = binary_item->source_url;
         result.file_contents_filename_extension =
             binary_item->filename_extension.value();
diff --git a/content/browser/renderer_host/input/double_tap_to_zoom_browsertest.cc b/content/browser/renderer_host/input/double_tap_to_zoom_browsertest.cc
index 171b119..f8ce5226 100644
--- a/content/browser/renderer_host/input/double_tap_to_zoom_browsertest.cc
+++ b/content/browser/renderer_host/input/double_tap_to_zoom_browsertest.cc
@@ -6,6 +6,7 @@
 #include <tuple>
 #include <utility>
 #include <vector>
+#include "build/build_config.h"
 
 #include "base/command_line.h"
 #include "base/test/scoped_feature_list.h"
@@ -107,7 +108,13 @@
       << std::get<2>(GetParam());
 }
 
-IN_PROC_BROWSER_TEST_P(DoubleTapToZoomBrowserTest, TapDelayEnabled) {
+// TODO(crbug.com/1271210): Flaky on mac and linux.
+#if defined(OS_MAC) || defined(OS_LINUX)
+#define MAYBE_TapDelayEnabled DISABLED_TapDelayEnabled
+#else
+#define MAYBE_TapDelayEnabled TapDelayEnabled
+#endif
+IN_PROC_BROWSER_TEST_P(DoubleTapToZoomBrowserTest, MAYBE_TapDelayEnabled) {
   bool expected_is_viewport_mobile_optimized = std::get<1>(GetParam());
   LoadURL();
   WebContents* main_contents = shell()->web_contents();
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue.h b/content/browser/renderer_host/input/mouse_wheel_event_queue.h
index 396a1cf..6ef676d 100644
--- a/content/browser/renderer_host/input/mouse_wheel_event_queue.h
+++ b/content/browser/renderer_host/input/mouse_wheel_event_queue.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/callback.h"
+#include "base/compiler_specific.h"
 #include "base/containers/circular_deque.h"
 #include "base/trace_event/trace_event.h"
 #include "content/browser/renderer_host/event_with_latency_info.h"
diff --git a/content/browser/renderer_host/input/touchpad_pinch_event_queue.h b/content/browser/renderer_host/input/touchpad_pinch_event_queue.h
index 0414327..4ef5454 100644
--- a/content/browser/renderer_host/input/touchpad_pinch_event_queue.h
+++ b/content/browser/renderer_host/input/touchpad_pinch_event_queue.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/compiler_specific.h"
 #include "base/containers/circular_deque.h"
 #include "content/common/content_export.h"
 #include "content/common/input/event_with_latency_info.h"
diff --git a/content/browser/renderer_host/media/audio_input_device_manager.cc b/content/browser/renderer_host/media/audio_input_device_manager.cc
index 6e96b01..f9762b1 100644
--- a/content/browser/renderer_host/media/audio_input_device_manager.cc
+++ b/content/browser/renderer_host/media/audio_input_device_manager.cc
@@ -25,21 +25,10 @@
 #include "third_party/blink/public/common/mediastream/media_stream_request.h"
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/components/audio/cras_audio_handler.h"
-#endif
-
 namespace content {
 
 namespace {
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-void SetKeyboardMicStreamActiveOnUIThread(bool active) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  ash::CrasAudioHandler::Get()->SetKeyboardMicActive(active);
-}
-#endif
-
 void SendAudioLogMessage(const std::string& message) {
   MediaStreamManager::SendMessageToNativeLog("AIDM::" + message);
 }
@@ -88,12 +77,7 @@
 
 AudioInputDeviceManager::AudioInputDeviceManager(
     media::AudioSystem* audio_system)
-    :
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-      keyboard_mic_streams_count_(0),
-#endif
-      audio_system_(audio_system) {
-}
+    : audio_system_(audio_system) {}
 
 AudioInputDeviceManager::~AudioInputDeviceManager() {
 }
@@ -173,59 +157,6 @@
                                 this, stream_type, session_id));
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-AudioInputDeviceManager::KeyboardMicRegistration::KeyboardMicRegistration(
-    KeyboardMicRegistration&& other)
-    : shared_registration_count_(other.shared_registration_count_) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  other.shared_registration_count_ = nullptr;
-}
-
-AudioInputDeviceManager::KeyboardMicRegistration::~KeyboardMicRegistration() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DeregisterIfNeeded();
-}
-
-AudioInputDeviceManager::KeyboardMicRegistration::KeyboardMicRegistration(
-    int* shared_registration_count)
-    : shared_registration_count_(shared_registration_count) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-}
-
-void AudioInputDeviceManager::KeyboardMicRegistration::DeregisterIfNeeded() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (shared_registration_count_) {
-    --*shared_registration_count_;
-    DCHECK_GE(*shared_registration_count_, 0);
-    if (*shared_registration_count_ == 0) {
-      GetUIThreadTaskRunner({})->PostTask(
-          FROM_HERE,
-          base::BindOnce(&SetKeyboardMicStreamActiveOnUIThread, false));
-    }
-  }
-
-  // Since we removed our registration, we unset the counter pointer to
-  // indicate this.
-  shared_registration_count_ = nullptr;
-}
-
-void AudioInputDeviceManager::RegisterKeyboardMicStream(
-    base::OnceCallback<void(KeyboardMicRegistration)> callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  ++keyboard_mic_streams_count_;
-  if (keyboard_mic_streams_count_ == 1) {
-    GetUIThreadTaskRunner({})->PostTaskAndReply(
-        FROM_HERE, base::BindOnce(&SetKeyboardMicStreamActiveOnUIThread, true),
-        base::BindOnce(std::move(callback),
-                       KeyboardMicRegistration(&keyboard_mic_streams_count_)));
-  } else {
-    std::move(callback).Run(
-        KeyboardMicRegistration(&keyboard_mic_streams_count_));
-  }
-}
-#endif
-
 void AudioInputDeviceManager::OpenedOnIOThread(
     const base::UnguessableToken& session_id,
     const blink::MediaStreamDevice& device,
diff --git a/content/browser/renderer_host/media/audio_input_device_manager.h b/content/browser/renderer_host/media/audio_input_device_manager.h
index 396a0132..ec6adb4 100644
--- a/content/browser/renderer_host/media/audio_input_device_manager.h
+++ b/content/browser/renderer_host/media/audio_input_device_manager.h
@@ -51,45 +51,6 @@
   base::UnguessableToken Open(const blink::MediaStreamDevice& device) override;
   void Close(const base::UnguessableToken& session_id) override;
 
-  // Owns a keyboard mic stream registration. Dummy implementation on platforms
-  // other than Chrome OS.
-  class KeyboardMicRegistration {
-   public:
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    // No registration.
-    KeyboardMicRegistration() = default;
-
-    KeyboardMicRegistration(KeyboardMicRegistration&& other);
-
-    ~KeyboardMicRegistration();
-
-   private:
-    friend class AudioInputDeviceManager;
-
-    explicit KeyboardMicRegistration(int* shared_registration_count);
-
-    void DeregisterIfNeeded();
-
-    // Null to indicate that there is no stream registration. This points to
-    // a member of the AudioInputDeviceManager, which lives as long as the IO
-    // thread, so the pointer will be valid for the lifetime of the
-    // registration.
-    int* shared_registration_count_ = nullptr;
-#endif
-  };
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  // Registers that a stream using keyboard mic has been opened or closed.
-  // Keeps count of how many such streams are open and activates and
-  // inactivates the keyboard mic accordingly. The (in)activation is done on the
-  // UI thread and for the register case a callback must therefore be provided
-  // which is called when activated. Deregistration is done when the
-  // registration object is destructed or assigned to, which should only be
-  // done on the IO thread.
-  void RegisterKeyboardMicStream(
-      base::OnceCallback<void(KeyboardMicRegistration)> callback);
-#endif
-
  private:
   ~AudioInputDeviceManager() override;
 
@@ -114,11 +75,6 @@
   base::ObserverList<MediaStreamProviderListener>::Unchecked listeners_;
   blink::MediaStreamDevices devices_;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  // Keeps count of how many streams are using keyboard mic.
-  int keyboard_mic_streams_count_;
-#endif
-
   media::AudioSystem* const audio_system_;
 };
 
diff --git a/content/browser/renderer_host/media/crop_id_web_contents_helper_unittest.cc b/content/browser/renderer_host/media/crop_id_web_contents_helper_unittest.cc
new file mode 100644
index 0000000..cb77cc6
--- /dev/null
+++ b/content/browser/renderer_host/media/crop_id_web_contents_helper_unittest.cc
@@ -0,0 +1,217 @@
+// Copyright (c) 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 "content/browser/media/capture/crop_id_web_contents_helper.h"
+
+#include <memory>
+
+#include "base/guid.h"
+#include "build/build_config.h"
+#include "content/test/test_render_view_host.h"
+#include "content/test/test_web_contents.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_ANDROID)
+#error Region Capture not supported on Android.
+#endif
+
+namespace content {
+
+namespace {
+
+MATCHER(IsEmptyCropId, "") {
+  static_assert(std::is_same<decltype(arg), const std::string&>::value, "");
+  return arg.empty();
+}
+
+MATCHER(IsValidCropId, "") {
+  static_assert(std::is_same<decltype(arg), const std::string&>::value, "");
+  return base::GUID::ParseLowercase(arg).is_valid();
+}
+
+}  // namespace
+
+class CropIdWebContentsHelperTest : public RenderViewHostImplTestHarness {
+ public:
+  ~CropIdWebContentsHelperTest() override = default;
+
+  void SetUp() override { RenderViewHostImplTestHarness::SetUp(); }
+
+  std::unique_ptr<TestWebContents> MakeTestWebContents() {
+    scoped_refptr<SiteInstance> instance =
+        SiteInstance::Create(GetBrowserContext());
+    instance->GetProcess()->Init();
+
+    return TestWebContents::Create(GetBrowserContext(), std::move(instance));
+  }
+
+  static CropIdWebContentsHelper* helper(WebContents* web_contents) {
+    // No-op if already created.
+    CropIdWebContentsHelper::CreateForWebContents(web_contents);
+    return CropIdWebContentsHelper::FromWebContents(web_contents);
+  }
+
+  static base::Token GUIDToToken(const base::GUID& guid) {
+    return CropIdWebContentsHelper::GUIDToToken(guid);
+  }
+};
+
+TEST_F(CropIdWebContentsHelperTest,
+       IsAssociatedWithCropIdReturnsFalseForUnknownCropId) {
+  const std::unique_ptr<TestWebContents> web_contents = MakeTestWebContents();
+  CropIdWebContentsHelper::CreateForWebContents(web_contents.get());
+  auto* helper = CropIdWebContentsHelper::FromWebContents(web_contents.get());
+  ASSERT_NE(helper, nullptr);
+
+  // Test focus.
+  const base::GUID unknown_crop_id = base::GUID::GenerateRandomV4();
+  EXPECT_FALSE(helper->IsAssociatedWithCropId(GUIDToToken(unknown_crop_id)));
+
+  // Extra-test: Ensure the query above did not accidentally record
+  // `unknown_crop_id` as a known crop-ID.
+  EXPECT_FALSE(helper->IsAssociatedWithCropId(GUIDToToken(unknown_crop_id)));
+}
+
+TEST_F(CropIdWebContentsHelperTest, ProduceCropIdReturnsCropId) {
+  const std::unique_ptr<TestWebContents> web_contents = MakeTestWebContents();
+  CropIdWebContentsHelper::CreateForWebContents(web_contents.get());
+  auto* helper = CropIdWebContentsHelper::FromWebContents(web_contents.get());
+  ASSERT_NE(helper, nullptr);
+
+  EXPECT_THAT(helper->ProduceCropId(), IsValidCropId());
+}
+
+TEST_F(CropIdWebContentsHelperTest,
+       IsAssociatedWithCropIdReturnsTrueForKnownCropIdIfCorrectWebContents) {
+  const std::unique_ptr<TestWebContents> web_contents = MakeTestWebContents();
+  CropIdWebContentsHelper::CreateForWebContents(web_contents.get());
+  auto* helper = CropIdWebContentsHelper::FromWebContents(web_contents.get());
+  ASSERT_NE(helper, nullptr);
+
+  const std::unique_ptr<TestWebContents> other_web_contents =
+      MakeTestWebContents();
+  CropIdWebContentsHelper::CreateForWebContents(other_web_contents.get());
+  auto* other_helper =
+      CropIdWebContentsHelper::FromWebContents(other_web_contents.get());
+  ASSERT_NE(other_helper, nullptr);
+
+  const std::string crop_id_str = helper->ProduceCropId();
+  EXPECT_THAT(crop_id_str, IsValidCropId());
+
+  const base::Token crop_id =
+      GUIDToToken(base::GUID::ParseLowercase(crop_id_str));
+
+  EXPECT_TRUE(helper->IsAssociatedWithCropId(crop_id));
+  EXPECT_FALSE(other_helper->IsAssociatedWithCropId(crop_id));
+}
+
+TEST_F(CropIdWebContentsHelperTest, MaxCropIdsPerWebContentsObserved) {
+  const std::unique_ptr<TestWebContents> web_contents[2] = {
+      MakeTestWebContents(), MakeTestWebContents()};
+  CropIdWebContentsHelper::CreateForWebContents(web_contents[0].get());
+  CropIdWebContentsHelper::CreateForWebContents(web_contents[1].get());
+  CropIdWebContentsHelper* helpers[2] = {
+      CropIdWebContentsHelper::FromWebContents(web_contents[0].get()),
+      CropIdWebContentsHelper::FromWebContents(web_contents[1].get())};
+
+  std::string crop_ids_str[2]
+                          [CropIdWebContentsHelper::kMaxCropIdsPerWebContents];
+
+  // Up to `kMaxCropIdsPerWebContents` allowed on each WebContents.
+  for (size_t web_contents_idx = 0; web_contents_idx < 2; ++web_contents_idx) {
+    for (size_t i = 0; i < CropIdWebContentsHelper::kMaxCropIdsPerWebContents;
+         ++i) {
+      crop_ids_str[web_contents_idx][i] =
+          helpers[web_contents_idx]->ProduceCropId();
+      EXPECT_THAT(crop_ids_str[web_contents_idx][i], IsValidCropId());
+    }
+  }
+
+  // Attempts to produce more crop-IDs on either WebContents fail.
+  for (CropIdWebContentsHelper* helper : helpers) {
+    EXPECT_THAT(helper->ProduceCropId(), IsEmptyCropId());
+  }
+
+  // The original crop-IDs are not forgotten.
+  for (size_t web_contents_idx = 0; web_contents_idx < 2; ++web_contents_idx) {
+    for (size_t i = 0; i < CropIdWebContentsHelper::kMaxCropIdsPerWebContents;
+         ++i) {
+      const base::Token crop_id = GUIDToToken(
+          base::GUID::ParseLowercase(crop_ids_str[web_contents_idx][i]));
+      EXPECT_TRUE(helpers[web_contents_idx]->IsAssociatedWithCropId(crop_id));
+
+      // Extra-test: They're also still associated *only* with the relevant WC.
+      const size_t other_web_contents_idx = 1 - web_contents_idx;
+      EXPECT_FALSE(
+          helpers[other_web_contents_idx]->IsAssociatedWithCropId(crop_id));
+    }
+  }
+}
+
+TEST_F(CropIdWebContentsHelperTest,
+       CrossDocumentNavigationClearsCropIdsAssociation) {
+  std::unique_ptr<TestWebContents> web_contents = MakeTestWebContents();
+  CropIdWebContentsHelper::CreateForWebContents(web_contents.get());
+  auto* helper = CropIdWebContentsHelper::FromWebContents(web_contents.get());
+  ASSERT_NE(helper, nullptr);
+
+  // Setup - WebContents navigated to a document, crop-ID produced.
+  web_contents->NavigateAndCommit(GURL("https://tests-r-us.com/first.html"));
+  base::Token crop_id_1;
+  {
+    const std::string crop_id_str = helper->ProduceCropId();
+    ASSERT_THAT(crop_id_str, IsValidCropId());
+    crop_id_1 = GUIDToToken(base::GUID::ParseLowercase(crop_id_str));
+  }
+  ASSERT_TRUE(helper->IsAssociatedWithCropId(crop_id_1));  // Sanity-check.
+
+  // Cross-document navigation occurs.
+  web_contents->NavigateAndCommit(GURL("https://tests-r-us.com/second.html"));
+
+  // Verification #1: The old crop-ID is forgotten.
+  ASSERT_FALSE(helper->IsAssociatedWithCropId(crop_id_1));
+
+  // Verification #2: New crop-IDs may be recorded.
+  {
+    const std::string crop_id_str = helper->ProduceCropId();
+    EXPECT_THAT(crop_id_str, IsValidCropId());
+    const base::Token crop_id_2 =
+        GUIDToToken(base::GUID::ParseLowercase(crop_id_str));
+    ASSERT_TRUE(helper->IsAssociatedWithCropId(crop_id_2));  // Sanity-check.
+  }
+
+  // Verification #3: The forgotten crop-ID is not counted against the limit
+  // of crop-IDs applied to a WebContents. (kMaxCropIdsPerWebContents - 1 more
+  // invocations allowed, then the next one fails.)
+  for (size_t i = 0; i < CropIdWebContentsHelper::kMaxCropIdsPerWebContents - 1;
+       ++i) {
+    EXPECT_THAT(helper->ProduceCropId(), IsValidCropId());
+  }
+  EXPECT_THAT(helper->ProduceCropId(), IsEmptyCropId());
+}
+
+TEST_F(CropIdWebContentsHelperTest,
+       InDocumentNavigationDoesNotClearCropIdsAssociation) {
+  std::unique_ptr<TestWebContents> web_contents = MakeTestWebContents();
+  CropIdWebContentsHelper::CreateForWebContents(web_contents.get());
+  auto* helper = CropIdWebContentsHelper::FromWebContents(web_contents.get());
+  ASSERT_NE(helper, nullptr);
+
+  // Setup - WebContents navigated to a document, crop-ID produced.
+  web_contents->NavigateAndCommit(GURL("https://tests-r-us.com/first.html"));
+  const std::string crop_id_str = helper->ProduceCropId();
+  ASSERT_THAT(crop_id_str, IsValidCropId());
+  const base::Token crop_id =
+      GUIDToToken(base::GUID::ParseLowercase(crop_id_str));
+
+  // Test sanity-check.
+  ASSERT_TRUE(helper->IsAssociatedWithCropId(crop_id));
+
+  // In-document navigation occurs. The crop-ID is not forgotten.
+  web_contents->NavigateAndCommit(GURL("https://tests-r-us.com/first.html#a"));
+  EXPECT_TRUE(helper->IsAssociatedWithCropId(crop_id));
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/media/media_devices_dispatcher_host.cc b/content/browser/renderer_host/media/media_devices_dispatcher_host.cc
index b112e414..073b8291 100644
--- a/content/browser/renderer_host/media/media_devices_dispatcher_host.cc
+++ b/content/browser/renderer_host/media/media_devices_dispatcher_host.cc
@@ -13,6 +13,7 @@
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/run_loop.h"
+#include "base/task/bind_post_task.h"
 #include "base/task/post_task.h"
 #include "base/task/task_runner_util.h"
 #include "build/build_config.h"
@@ -36,6 +37,10 @@
 #include "third_party/blink/public/common/mediastream/media_stream_request.h"
 #include "url/origin.h"
 
+#if !defined(OS_ANDROID)
+#include "content/browser/media/capture/crop_id_web_contents_helper.h"
+#endif
+
 using blink::mojom::MediaDeviceType;
 
 namespace content {
@@ -106,6 +111,7 @@
       media_stream_manager_(media_stream_manager),
       num_pending_audio_input_parameters_(0) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(media_stream_manager_);
 }
 
 MediaDevicesDispatcherHost::~MediaDevicesDispatcherHost() {
@@ -286,6 +292,33 @@
       /*is_from_microtask=*/true,
       /*is_from_timer=*/false);
 }
+
+void MediaDevicesDispatcherHost::ProduceCropId(ProduceCropIdCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  GetUIThreadTaskRunner({})->PostTaskAndReplyWithResult(
+      FROM_HERE,
+      base::BindOnce(
+          [](int render_process_id, int render_frame_id) {
+            RenderFrameHostImpl* const rfh =
+                RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
+            if (!rfh || !rfh->IsActive()) {
+              return std::string();  // Might have been asynchronously closed.
+            }
+
+            WebContents* const web_contents =
+                WebContents::FromRenderFrameHost(rfh->GetMainFrame());
+            DCHECK(web_contents);
+
+            // No-op if already created.
+            CropIdWebContentsHelper::CreateForWebContents(web_contents);
+
+            return CropIdWebContentsHelper::FromWebContents(web_contents)
+                ->ProduceCropId();
+          },
+          render_process_id_, render_frame_id_),
+      std::move(callback));
+}
 #endif
 
 void MediaDevicesDispatcherHost::GetDefaultVideoInputDeviceID(
diff --git a/content/browser/renderer_host/media/media_devices_dispatcher_host.h b/content/browser/renderer_host/media/media_devices_dispatcher_host.h
index 5bdfc30..9c490470 100644
--- a/content/browser/renderer_host/media/media_devices_dispatcher_host.h
+++ b/content/browser/renderer_host/media/media_devices_dispatcher_host.h
@@ -71,6 +71,7 @@
       blink::mojom::CaptureHandleConfigPtr config) override;
 #if !defined(OS_ANDROID)
   void CloseFocusWindowOfOpportunity(const std::string& label) override;
+  void ProduceCropId(ProduceCropIdCallback callback) override;
 #endif
 
  private:
@@ -142,7 +143,7 @@
   const int render_frame_id_;
 
   // The following fields can only be accessed on the IO thread.
-  MediaStreamManager* media_stream_manager_;
+  MediaStreamManager* const media_stream_manager_;
 
   struct AudioInputCapabilitiesRequest;
   // Queued requests for audio-input capabilities.
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 80f36a90..239fc0c7 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -2755,11 +2755,12 @@
       RequestTypeToString(request->request_type())));
 
   // Show "Change source" button on notification bar only for tab sharing by
-  // desktopCapture API.
+  // desktopCapture API or getDisplayMedia.
   bool enable_change_source = std::any_of(
       request->devices.cbegin(), request->devices.cend(), [](auto device) {
         DesktopMediaID media_id = DesktopMediaID::Parse(device.id);
-        return device.type == MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE &&
+        return (device.type == MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE ||
+                device.type == MediaStreamType::DISPLAY_VIDEO_CAPTURE) &&
                media_id.type == DesktopMediaID::TYPE_WEB_CONTENTS;
       });
 
diff --git a/content/browser/renderer_host/media/service_video_capture_provider.h b/content/browser/renderer_host/media/service_video_capture_provider.h
index c04b3d0e..e3782c1 100644
--- a/content/browser/renderer_host/media/service_video_capture_provider.h
+++ b/content/browser/renderer_host/media/service_video_capture_provider.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_SERVICE_VIDEO_CAPTURE_PROVIDER_H_
 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_SERVICE_VIDEO_CAPTURE_PROVIDER_H_
 
+#include "base/compiler_specific.h"
 #include "base/threading/sequence_bound.h"
 #include "base/threading/thread_checker.h"
 #include "build/build_config.h"
diff --git a/content/browser/renderer_host/navigation_controller_impl_unittest.cc b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
index 8c0cdf4..e8d120e 100644
--- a/content/browser/renderer_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
@@ -1278,9 +1278,11 @@
 // without ending up in the "we have a wrong process for the URL" branch in
 // NavigationControllerImpl::ReloadInternal.
 TEST_F(NavigationControllerTest, ReloadWithGuest) {
-  const GURL kGuestSiteUrl("my-guest-scheme://someapp/somepath");
+  const StoragePartitionConfig kGuestPartitionConfig =
+      StoragePartitionConfig::Create(browser_context(), "someapp",
+                                     "somepartition", /*in_memory=*/false);
   scoped_refptr<SiteInstance> guest_instance =
-      SiteInstance::CreateForGuest(browser_context(), kGuestSiteUrl);
+      SiteInstance::CreateForGuest(browser_context(), kGuestPartitionConfig);
   std::unique_ptr<TestWebContents> guest_web_contents(
       TestWebContents::Create(browser_context(), guest_instance));
   NavigationControllerImpl& controller = guest_web_contents->GetController();
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index e31891c..e0463a93 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -3650,8 +3650,8 @@
       navigating_frame_host->GetSiteInstance());
   DCHECK(partition);
 
-  // |loader_| should not exist if the service worker handle and app cache
-  // handles will be destroyed, since it holds raw pointers to them. See the
+  // |loader_| should not exist if the service worker handle
+  // will be destroyed, since it holds raw pointers to it. See the
   // comment in the header for |loader_|.
   DCHECK(!loader_);
 
@@ -4908,8 +4908,6 @@
       "details.";
   parent->AddMessageToConsole(blink::mojom::ConsoleMessageLevel::kWarning,
                               console_message);
-  if (!base::FeatureList::IsEnabled(features::kBlockCredentialedSubresources))
-    return CredentialedSubresourceCheckResult::ALLOW_REQUEST;
   return CredentialedSubresourceCheckResult::BLOCK_REQUEST;
 }
 
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index 48b3a80..151371b 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -11,6 +11,7 @@
 
 #include "base/callback.h"
 #include "base/callback_forward.h"
+#include "base/compiler_specific.h"
 #include "base/debug/crash_logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/content/browser/renderer_host/navigation_request_browsertest.cc b/content/browser/renderer_host/navigation_request_browsertest.cc
index c7cf2b2..4e14e2b8 100644
--- a/content/browser/renderer_host/navigation_request_browsertest.cc
+++ b/content/browser/renderer_host/navigation_request_browsertest.cc
@@ -2278,12 +2278,8 @@
 
 // Check that iframe with embedded credentials are blocked.
 // See https://crbug.com/755892.
-// TODO(crbug.com/1262910): Enable the test again.
 IN_PROC_BROWSER_TEST_F(NavigationRequestBrowserTest,
-                       DISABLED_BlockCredentialedSubresources) {
-  if (!base::FeatureList::IsEnabled(features::kBlockCredentialedSubresources))
-    return;
-
+                       BlockCredentialedSubresources) {
   const struct {
     GURL main_url;
     GURL iframe_url;
@@ -2343,10 +2339,16 @@
     GURL iframe_url_with_redirect = GURL(embedded_test_server()->GetURL(
         "/server-redirect?" + iframe_url_final.spec()));
 
-    ASSERT_TRUE(NavigateToURL(shell(), main_url));
-
     // Blocking the request must work, even after a redirect.
     for (bool redirect : {false, true}) {
+      ASSERT_TRUE(NavigateToURL(shell(), main_url));
+      EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+      FrameTreeNode* root =
+          static_cast<WebContentsImpl*>(shell()->web_contents())
+              ->GetPrimaryFrameTree()
+              .root();
+      ASSERT_EQ(1u, root->child_count());
+
       const GURL& iframe_url =
           redirect ? iframe_url_with_redirect : iframe_url_final;
       SCOPED_TRACE(::testing::Message()
@@ -2361,12 +2363,8 @@
           NavigationThrottle::PROCEED);
 
       NavigateIframeToURL(shell()->web_contents(), "child0", iframe_url);
+      EXPECT_EQ(1, installer.install_count());
 
-      FrameTreeNode* root =
-          static_cast<WebContentsImpl*>(shell()->web_contents())
-              ->GetPrimaryFrameTree()
-              .root();
-      ASSERT_EQ(1u, root->child_count());
       if (test_case.blocked) {
         EXPECT_EQ(redirect, !!installer.will_start_called());
         EXPECT_FALSE(installer.will_process_called());
diff --git a/content/browser/renderer_host/navigator.h b/content/browser/renderer_host/navigator.h
index 8a3cf98..8ae50ba 100644
--- a/content/browser/renderer_host/navigator.h
+++ b/content/browser/renderer_host/navigator.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "content/browser/renderer_host/navigation_controller_impl.h"
 #include "content/common/content_export.h"
diff --git a/content/browser/renderer_host/page_impl.cc b/content/browser/renderer_host/page_impl.cc
index 495690b..ef5fdf8 100644
--- a/content/browser/renderer_host/page_impl.cc
+++ b/content/browser/renderer_host/page_impl.cc
@@ -192,6 +192,11 @@
   if (load_progress() != blink::kFinalLoadProgress)
     main_document_.DidChangeLoadProgress(load_progress());
 
+  // Dispatch DocumentAvailableInMainFrame before dispatching following load
+  // complete events.
+  if (is_document_available_in_main_document())
+    main_document_.DocumentAvailableInMainFrame(uses_temporary_zoom_level());
+
   main_document_.ForEachRenderFrameHost(
       base::BindRepeating([](RenderFrameHostImpl* rfh) {
         rfh->MaybeDispatchDOMContentLoadedOnPrerenderActivation();
diff --git a/content/browser/renderer_host/page_impl.h b/content/browser/renderer_host/page_impl.h
index 280d8973..62eda4a 100644
--- a/content/browser/renderer_host/page_impl.h
+++ b/content/browser/renderer_host/page_impl.h
@@ -58,6 +58,18 @@
     is_on_load_completed_in_main_document_ = completed;
   }
 
+  bool is_document_available_in_main_document() const {
+    return is_document_available_in_main_document_;
+  }
+  void set_is_document_available_in_main_document(bool completed) {
+    is_document_available_in_main_document_ = completed;
+  }
+
+  bool uses_temporary_zoom_level() const { return uses_temporary_zoom_level_; }
+  void set_uses_temporary_zoom_level(bool level) {
+    uses_temporary_zoom_level_ = level;
+  }
+
   void OnFirstVisuallyNonEmptyPaint();
   bool did_first_visually_non_empty_paint() const {
     return did_first_visually_non_empty_paint_;
@@ -152,6 +164,13 @@
   // run for the main document.
   bool is_on_load_completed_in_main_document_ = false;
 
+  // True if we've received a notification that the window.document was created
+  // for the main document.
+  bool is_document_available_in_main_document_ = false;
+
+  // True if plugin zoom level is set for the main document.
+  bool uses_temporary_zoom_level_ = false;
+
   // Overall load progress of this Page. Initial load progress value is 0.0
   // before the load has begun.
   double load_progress_ = 0.0;
diff --git a/content/browser/renderer_host/private_network_access_browsertest.cc b/content/browser/renderer_host/private_network_access_browsertest.cc
index 31918e1e..851f0860 100644
--- a/content/browser/renderer_host/private_network_access_browsertest.cc
+++ b/content/browser/renderer_host/private_network_access_browsertest.cc
@@ -2622,15 +2622,10 @@
 
   // Check that the page can load a local resource.
   //
-  // TODO(https://crbug.com/1256775): The page should be able to load this
-  // resource, since in this feature flag configuration we should send CORS
-  // preflight requests but not gate the actual request based on the preflight's
-  // outcome.
-  //
   // We load the resource from a secure origin to avoid running afoul of mixed
   // content restrictions.
-  EXPECT_EQ(false, EvalJs(root_frame_host(),
-                          FetchSubresourceScript(SecureLocalURL(kCorsPath))));
+  EXPECT_EQ(true, EvalJs(root_frame_host(),
+                         FetchSubresourceScript(SecureLocalURL(kCorsPath))));
 }
 
 // This test verifies that when preflights are sent and enforced, requests:
@@ -2673,15 +2668,10 @@
 
   // Check that the page can load a local resource.
   //
-  // TODO(https://crbug.com/1256775): The page should be able to load this
-  // resource, since in this feature flag configuration we should send CORS
-  // preflight requests but not gate the actual request based on the preflight's
-  // outcome.
-  //
   // We load it from a secure origin to avoid running afoul of mixed content
   // restrictions.
-  EXPECT_EQ(false, EvalJs(root_frame_host(),
-                          FetchSubresourceScript(SecureLocalURL(kCorsPath))));
+  EXPECT_EQ(true, EvalJs(root_frame_host(),
+                         FetchSubresourceScript(SecureLocalURL(kCorsPath))));
 }
 
 // This test verifies that when preflights are sent and enforced, requests:
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 9aa3102..24678aa1 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -5417,6 +5417,16 @@
         GetProcess(), bad_message::RFH_INVALID_CALL_FROM_NOT_MAIN_FRAME);
     return;
   }
+
+  GetPage().set_is_document_available_in_main_document(true);
+  GetPage().set_uses_temporary_zoom_level(uses_temporary_zoom_level);
+
+  // In case of prerendering, we dispatch DocumentAvailableInMainFrame on
+  // activation. This is done to avoid notifying observers about a load event
+  // triggered from an inactive RenderFrameHost.
+  if (lifecycle_state() == LifecycleStateImpl::kPrerendering)
+    return;
+
   delegate_->DocumentAvailableInMainFrame(this);
 
   if (!uses_temporary_zoom_level)
diff --git a/content/browser/renderer_host/render_frame_host_manager_unittest.cc b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
index 9ff735a..59dea1e 100644
--- a/content/browser/renderer_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
@@ -1438,17 +1438,19 @@
 
 // Test that we reuse the same guest SiteInstance if we navigate across sites.
 TEST_P(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
-  // Create a custom site URL for the SiteInstance. There is nothing special
-  // about this URL other than we expect the resulting SiteInstance to return
-  // this exact URL from its GetSiteURL() method.
-  const GURL kGuestSiteUrl("my-guest-scheme://someapp/somepath");
+  // Create a custom StoragePartitionConfig for the guest SiteInstance. The
+  // resulting SiteInstance should become associated with this
+  // StoragePartitionConfig rather than a default one.
+  const StoragePartitionConfig kGuestPartitionConfig =
+      StoragePartitionConfig::Create(browser_context(), "someapp",
+                                     "somepartition", /*in_memory=*/false);
   scoped_refptr<SiteInstance> instance =
-      SiteInstance::CreateForGuest(browser_context(), kGuestSiteUrl);
+      SiteInstance::CreateForGuest(browser_context(), kGuestPartitionConfig);
   std::unique_ptr<TestWebContents> web_contents(
       TestWebContents::Create(browser_context(), instance));
 
   EXPECT_TRUE(instance->IsGuest());
-  EXPECT_EQ(kGuestSiteUrl, instance->GetSiteURL());
+  EXPECT_EQ(kGuestPartitionConfig, instance->GetStoragePartitionConfig());
 
   RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
 
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 094b586f..63e1f310 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1513,17 +1513,13 @@
     flags |= RenderProcessFlags::kForGuestsOnly;
 
     // If we've made a StoragePartition for guests (e.g., for the <webview>
-    // tag), stash the Site URL on it. This way, when we start a service worker
-    // inside this storage partition, we can create the appropriate SiteInstance
-    // for finding a process (e.g., we will try to start a worker from
-    // "https://example.com/sw.js" but need to use the guest site URL to get a
-    // process in the guest's StoragePartition.)
-    if (storage_partition_impl->site_for_guest_service_worker_or_shared_worker()
-            .is_empty()) {
-      storage_partition_impl
-          ->set_site_for_guest_service_worker_or_shared_worker(
-              site_instance->GetSiteInfo().site_url());
-    }
+    // tag), make the StoragePartition aware of that.  This will be consulted
+    // when we start a service worker inside this StoragePartition, so that we
+    // can create the appropriate SiteInstance (e.g., we will try to start a
+    // worker from "https://example.com/sw.js" but need to use the guest's
+    // StoragePartitionConfig to get a process in the guest's
+    // StoragePartition.)
+    storage_partition_impl->set_is_guest();
   }
 
   if (site_instance) {
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
index a6a826e..ac96fcd 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -498,6 +498,7 @@
         !intersection_state.viewport_intersection.IsEmpty());
 
     // Do not send viewport intersection to main frames.
+    DCHECK(!visual_properties.has_value() || !host()->owner_delegate());
     if (!host()->owner_delegate()) {
       host()->GetAssociatedFrameWidget()->SetViewportIntersection(
           intersection_state.Clone(), visual_properties);
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
index 000f6ba..ec47185b 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
@@ -378,8 +378,14 @@
 }
 
 // Validate that OOPIFs receive presentation feedbacks.
+// TODO(crbug.com/1270981): Flaky.
+#if defined(OS_LINUX) || defined(OS_MAC)
+#define MAYBE_PresentationFeedback DISABLED_PresentationFeedback
+#else
+#define MAYBE_PresentationFeedback PresentationFeedback
+#endif
 IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameBrowserTest,
-                       PresentationFeedback) {
+                       MAYBE_PresentationFeedback) {
   base::HistogramTester histogram_tester;
   GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 6ba7f72..7cc239d 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -1835,17 +1835,18 @@
   RenderFrameHostImplWrapper primary_rfh(primary_main_frame_host());
   RenderFrameHostImplWrapper inner_fenced_frame_rfh(
       fenced_frame_test_helper().CreateFencedFrame(
-          primary_rfh.get(), embedded_test_server()->GetURL("/empty.html")));
+          primary_rfh.get(),
+          embedded_test_server()->GetURL("/fenced_frames/empty.html")));
 
   RenderFrameHost* compromised_renderer = inner_fenced_frame_rfh.get();
   RenderProcessHostBadMojoMessageWaiter kill_waiter(
       compromised_renderer->GetProcess());
   replacer.Activate();
 
-  ignore_result(
-      ExecJs(compromised_renderer,
-             JsReplace("location.href=$1",
-                       embedded_test_server()->GetURL("/title1.html"))));
+  ignore_result(ExecJs(
+      compromised_renderer,
+      JsReplace("location.href=$1",
+                embedded_test_server()->GetURL("/fenced_frames/title1.html"))));
 
   absl::optional<std::string> result = kill_waiter.Wait();
   EXPECT_THAT(result,
diff --git a/content/browser/service_worker/README.md b/content/browser/service_worker/README.md
index 7fc62d51..006fb3e 100644
--- a/content/browser/service_worker/README.md
+++ b/content/browser/service_worker/README.md
@@ -371,7 +371,7 @@
 Service workers storage lasts indefinitely, i.e, there is no periodic deletion
 of old but still installed service workers. Installed service workers are only
 evicted by the [Quota Manager] (or user action). The Quota Manager controls
-several web platform APIs, including sandboxed filesystem, WebSQL, appcache,
+several web platform APIs, including sandboxed filesystem, WebSQL,
 IndexedDB, cache storage, service worker (registration and scripts), and
 background fetch.
 
diff --git a/content/browser/service_worker/service_worker_process_manager.cc b/content/browser/service_worker/service_worker_process_manager.cc
index a812bda7..0143365a 100644
--- a/content/browser/service_worker/service_worker_process_manager.cc
+++ b/content/browser/service_worker/service_worker_process_manager.cc
@@ -114,29 +114,22 @@
   DCHECK(!base::Contains(worker_process_map_, embedded_worker_id))
       << embedded_worker_id << " already has a process allocated";
 
-  // Create a SiteInstance to get the renderer process from. Use the site URL
-  // from the StoragePartition in case this StoragePartition is for guests
-  // (e.g., <webview>).
+  // Create a SiteInstance to get the renderer process from.
+  //
+  // TODO(alexmos): Support CrossOriginIsolated for guests.
   DCHECK(storage_partition_);
-  const bool is_guest =
-      storage_partition_ &&
-      !storage_partition_->site_for_guest_service_worker_or_shared_worker()
-           .is_empty();
-  const GURL service_worker_url =
-      is_guest
-          ? storage_partition_->site_for_guest_service_worker_or_shared_worker()
-          : script_url;
+  const bool is_guest = storage_partition_->is_guest();
   const bool is_coop_coep_cross_origin_isolated =
       !is_guest && cross_origin_embedder_policy.has_value() &&
       network::CompatibleWithCrossOriginIsolated(
           cross_origin_embedder_policy->value);
   UrlInfo url_info(
-      UrlInfoInit(service_worker_url)
+      UrlInfoInit(script_url)
           .WithStoragePartitionConfig(storage_partition_->GetConfig())
           .WithWebExposedIsolationInfo(
               is_coop_coep_cross_origin_isolated
                   ? WebExposedIsolationInfo::CreateIsolated(
-                        url::Origin::Create(service_worker_url))
+                        url::Origin::Create(script_url))
                   : WebExposedIsolationInfo::CreateNonIsolated()));
   scoped_refptr<SiteInstanceImpl> site_instance =
       SiteInstanceImpl::CreateForServiceWorker(
diff --git a/content/browser/service_worker/service_worker_process_manager_unittest.cc b/content/browser/service_worker/service_worker_process_manager_unittest.cc
index d0d51b9ea..5d0f226c 100644
--- a/content/browser/service_worker/service_worker_process_manager_unittest.cc
+++ b/content/browser/service_worker/service_worker_process_manager_unittest.cc
@@ -41,8 +41,9 @@
   RenderProcessHost* CreateRenderProcessHost(
       BrowserContext* browser_context,
       SiteInstance* site_instance) override {
-    processes_.push_back(
-        std::make_unique<MockRenderProcessHost>(browser_context));
+    processes_.push_back(std::make_unique<MockRenderProcessHost>(
+        browser_context, site_instance->GetStoragePartitionConfig(),
+        site_instance->IsGuest()));
 
     // A spare RenderProcessHost is created with a null SiteInstance.
     if (site_instance)
@@ -222,7 +223,7 @@
 TEST_F(ServiceWorkerProcessManagerTest,
        AllocateWorkerProcess_StoragePartitionForGuests) {
   // Allocate a process to a worker. It should use |script_url_| as the
-  // site URL of the SiteInstance.
+  // site URL of the SiteInstance and a default StoragePartition.
   {
     const int kEmbeddedWorkerId = 55;  // dummy value
     ServiceWorkerProcessManager::AllocatedProcessInfo process_info;
@@ -232,40 +233,40 @@
             absl::nullopt /* cross_origin_embedder_policy */,
             true /* can_use_existing_process */, &process_info);
     EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
-    // Instead of testing the input to the CreateRenderProcessHost(), it'd be
-    // more interesting to check the StoragePartition of the returned process
-    // here and below. Alas, MockRenderProcessHosts always use the default
-    // StoragePartition.
     EXPECT_EQ(
         GURL("http://example.com"),
         render_process_host_factory_->last_site_instance_used()->GetSiteURL());
     EXPECT_FALSE(
         render_process_host_factory_->last_site_instance_used()->IsGuest());
+    auto* rph = RenderProcessHost::FromID(process_info.process_id);
+    ASSERT_TRUE(rph);
+    auto* storage_partition =
+        static_cast<StoragePartitionImpl*>(rph->GetStoragePartition());
+    EXPECT_TRUE(storage_partition->GetConfig().is_default());
 
     // Release the process.
     process_manager_->ReleaseWorkerProcess(kEmbeddedWorkerId);
   }
 
-  // Now change ServiceWorkerProcessManager to use a StoragePartition with
-  // |site_for_guest_service_worker_or_shared_worker| set. We must set
-  // |site_for_guest_service_worker_or_shared_worker| manually since the
-  // production codepath in CreateRenderProcessHost() isn't hit here since we
-  // are using RenderProcessHostFactory.
-  const GURL kGuestSiteUrl("my-guest-scheme://someapp/somepath");
-  scoped_refptr<SiteInstanceImpl> site_instance =
-      SiteInstanceImpl::CreateForGuest(browser_context_.get(), kGuestSiteUrl);
-  EXPECT_TRUE(site_instance->IsGuest());
-  // It'd be more realistic to create a non-default StoragePartition, but there
-  // would be no added value to this test since MockRenderProcessHost is not
-  // StoragePartition-aware.
+  // Now change ServiceWorkerProcessManager to use a guest StoragePartition.
+  // We must call |set_is_guest()| manually since the production codepath in
+  // CreateRenderProcessHost() isn't hit here since we are using
+  // RenderProcessHostFactory.
+  const StoragePartitionConfig kGuestPartitionConfig =
+      StoragePartitionConfig::Create(browser_context_.get(), "someapp",
+                                     "somepartition", /*in_memory=*/false);
+  scoped_refptr<SiteInstanceImpl> guest_site_instance =
+      SiteInstanceImpl::CreateForGuest(browser_context_.get(),
+                                       kGuestPartitionConfig);
+  EXPECT_TRUE(guest_site_instance->IsGuest());
   StoragePartitionImpl* storage_partition = static_cast<StoragePartitionImpl*>(
-      browser_context_->GetDefaultStoragePartition());
-  storage_partition->set_site_for_guest_service_worker_or_shared_worker(
-      site_instance->GetSiteURL());
+      browser_context_->GetStoragePartition(kGuestPartitionConfig));
+  storage_partition->set_is_guest();
   process_manager_->set_storage_partition(storage_partition);
 
-  // Allocate a process to a worker. It should use kGuestSiteUrl instead of
-  // |script_url_| as the site URL of the SiteInstance.
+  // Allocate a process to a worker. It should use the site URL of
+  // |guest_site_instance| instead of |script_url_| as the site URL of the
+  // SiteInstance, and it should be in the guest's StoragePartition.
   {
     const int kEmbeddedWorkerId = 77;  // dummy value
     ServiceWorkerProcessManager::AllocatedProcessInfo process_info;
@@ -276,10 +277,13 @@
             true /* can_use_existing_process */, &process_info);
     EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
     EXPECT_EQ(
-        kGuestSiteUrl,
+        guest_site_instance->GetSiteURL(),
         render_process_host_factory_->last_site_instance_used()->GetSiteURL());
     EXPECT_TRUE(
         render_process_host_factory_->last_site_instance_used()->IsGuest());
+    auto* rph = RenderProcessHost::FromID(process_info.process_id);
+    ASSERT_TRUE(rph);
+    EXPECT_EQ(rph->GetStoragePartition(), storage_partition);
 
     // Release the process.
     process_manager_->ReleaseWorkerProcess(kEmbeddedWorkerId);
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 75926a2b..0c196d00 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -1073,7 +1073,7 @@
 
 bool ServiceWorkerVersion::IsControlleeProcessID(int process_id) const {
   for (const auto& controllee : controllee_map_) {
-    if (controllee.second.get()->GetProcessId() == process_id)
+    if (controllee.second && controllee.second->GetProcessId() == process_id)
       return true;
   }
   return false;
diff --git a/content/browser/site_info.cc b/content/browser/site_info.cc
index 935827f..72b0ad6 100644
--- a/content/browser/site_info.cc
+++ b/content/browser/site_info.cc
@@ -7,6 +7,7 @@
 #include "base/containers/contains.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/origin_agent_cluster_isolation_state.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
@@ -14,9 +15,11 @@
 #include "content/browser/webui/url_data_manager_backend.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/site_isolation_policy.h"
+#include "content/public/browser/storage_partition_config.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
+#include "net/base/escape.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 
 namespace content {
@@ -67,6 +70,106 @@
   return GURL(scheme + url::kStandardSchemeSeparator + host);
 }
 
+// Strings used to encode blob url fallback mode in guest site URLs.
+constexpr char kNoFallback[] = "nofallback";
+constexpr char kInMemoryFallback[] = "inmemoryfallback";
+constexpr char kOnDiskFallback[] = "ondiskfallback";
+
+// SiteInstances for <webview> guests currently use a special site URL that
+// encodes that guest's StoragePartition configuration, including the partition
+// name and whether the storage for that partition should be persisted. This
+// helper translates a guest's StoragePartitionConfig into a site URL, and
+// GetGuestPartitionConfigForSite below performs the opposite translation.
+// The format for a guest site URL is:
+// chrome-guest://partition_domain/persist?partition_name
+// The `partition_domain` (i.e., the site URL's host) identifies the guest's
+// embedder.
+//
+// TODO(alexmos): Guest site URLs are deprecated and will be removed once
+// <webview> guests support site isolation.  See https://crbug.com/1267977.
+GURL GetSiteURLForGuestPartitionConfig(
+    const StoragePartitionConfig& storage_partition_config) {
+  DCHECK(!storage_partition_config.is_default());
+  std::string url_encoded_partition = net::EscapeQueryParamValue(
+      storage_partition_config.partition_name(), false);
+  const char* fallback = "";
+  switch (
+      storage_partition_config.fallback_to_partition_domain_for_blob_urls()) {
+    case StoragePartitionConfig::FallbackMode::kNone:
+      fallback = kNoFallback;
+      break;
+    case StoragePartitionConfig::FallbackMode::kFallbackPartitionOnDisk:
+      fallback = kOnDiskFallback;
+      break;
+    case StoragePartitionConfig::FallbackMode::kFallbackPartitionInMemory:
+      fallback = kInMemoryFallback;
+      break;
+  }
+  return GURL(
+      base::StringPrintf("%s://%s/%s?%s#%s", kGuestScheme,
+                         storage_partition_config.partition_domain().c_str(),
+                         storage_partition_config.in_memory() ? "" : "persist",
+                         url_encoded_partition.c_str(), fallback));
+}
+
+// Opposite of GetSiteURLForGuestPartitionConfig. Converts the provided site
+// URL of a <webview> guest into a StoragePartitionConfig.  The return value
+// indicates whether the translation succeeded.
+bool GetGuestPartitionConfigForSite(
+    BrowserContext* browser_context,
+    const GURL& site,
+    StoragePartitionConfig* storage_partition_config) {
+  if (!site.SchemeIs(kGuestScheme))
+    return false;
+
+  // The partition name is user supplied value, which we have encoded when the
+  // URL was created, so it needs to be decoded. Since it was created via
+  // EscapeQueryParamValue(), it should have no path separators or control codes
+  // when unescaped, but safest to check for that and fail if it does.
+  std::string partition_name;
+  if (!net::UnescapeBinaryURLComponentSafe(site.query_piece(),
+                                           true /* fail_on_path_separators */,
+                                           &partition_name)) {
+    return false;
+  }
+
+  // The host must contain an ID for the guest's embedder (e.g., packaged app's
+  // ID or WebUI host).
+  CHECK(site.has_host());
+
+  // Since persistence is optional, the path must either be empty or the
+  // literal string.
+  bool in_memory = (site.path() != "/persist");
+
+  *storage_partition_config = StoragePartitionConfig::Create(
+      browser_context, site.host(), partition_name, in_memory);
+
+  // A <webview> guest inside an embedder needs to be able to resolve Blob URLs
+  // that were created by the embedder (such as a Chrome app). The embedder has
+  // the same partition_domain but empty partition_name. Setting this flag on
+  // the partition config causes it to be used as fallback for the purpose of
+  // resolving blob URLs.
+  //
+  // Default to having the fallback partition on disk, as that matches most
+  // closely what we would have done before fallback behavior started being
+  // encoded in the site URL.
+  StoragePartitionConfig::FallbackMode fallback_mode =
+      StoragePartitionConfig::FallbackMode::kFallbackPartitionOnDisk;
+  if (site.ref() == kNoFallback) {
+    fallback_mode = StoragePartitionConfig::FallbackMode::kNone;
+  } else if (site.ref() == kInMemoryFallback) {
+    fallback_mode =
+        StoragePartitionConfig::FallbackMode::kFallbackPartitionInMemory;
+  } else if (site.ref() == kOnDiskFallback) {
+    fallback_mode =
+        StoragePartitionConfig::FallbackMode::kFallbackPartitionOnDisk;
+  }
+  storage_partition_config->set_fallback_to_partition_domain_for_blob_urls(
+      fallback_mode);
+
+  return true;
+}
+
 }  // namespace
 
 // static
@@ -100,18 +203,23 @@
 }
 
 // static
-SiteInfo SiteInfo::CreateForGuest(BrowserContext* browser_context,
-                                  const GURL& guest_site_url) {
-  // Setting site and lock directly without the site URL conversions we
-  // do for user provided URLs. Callers expect GetSiteURL() to return the
-  // value they provide in |guest_site_url|.
-  return SiteInfo(
-      guest_site_url, guest_site_url, false /* requires_origin_keyed_process */,
-      GetStoragePartitionConfigForUrl(browser_context, guest_site_url,
-                                      /*is_site_url=*/true),
-      WebExposedIsolationInfo::CreateNonIsolated(), true /* is_guest */,
-      false /* does_site_request_dedicated_process_for_coop */,
-      false /* is_jit_disabled */, false /* is_pdf */);
+SiteInfo SiteInfo::CreateForGuest(
+    BrowserContext* browser_context,
+    const StoragePartitionConfig& partition_config) {
+  GURL guest_site_url = GetSiteURLForGuestPartitionConfig(partition_config);
+
+  // Currently, site URLs for guests are expected to have a special value
+  // computed in |guest_site_url|.  So, set site and lock URLs directly without
+  // the site URL conversions we typically do for user-provided URLs.
+  //
+  // TODO(alexmos): Once guests support site isolation, this should no longer
+  // need to use the special guest site URLs.  See https://crbug.com/1267977.
+  return SiteInfo(guest_site_url, guest_site_url,
+                  false /* requires_origin_keyed_process */, partition_config,
+                  WebExposedIsolationInfo::CreateNonIsolated(),
+                  true /* is_guest */,
+                  false /* does_site_request_dedicated_process_for_coop */,
+                  false /* is_jit_disabled */, false /* is_pdf */);
 }
 
 // static
@@ -531,16 +639,19 @@
   if (url.is_empty())
     return StoragePartitionConfig::CreateDefault(browser_context);
 
-  if (!is_site_url && url.SchemeIs(kGuestScheme)) {
-    // Guest schemes should only appear in site URLs. Generate a crash
-    // dump to help debug unexpected callers that might not be setting
-    // |is_site_url| correctly.
-    // TODO(acolwell): Once we have confidence all callers are setting
-    // |is_site_url| correctly, replace crash reporting with code that returns a
-    // default config for this scheme in the non-site URL case.
-    SCOPED_CRASH_KEY_STRING256("StoragePartitionConfigForUrl", "guest_url",
-                               url.possibly_invalid_spec());
-    base::debug::DumpWithoutCrashing();
+  if (url.SchemeIs(kGuestScheme)) {
+    StoragePartitionConfig storage_partition_config =
+        StoragePartitionConfig::CreateDefault(browser_context);
+    // Guest schemes should only appear in site URLs.
+    DCHECK(is_site_url);
+
+    // This should only ever see guest site URLs generated within SiteInfo, so
+    // it shouldn't ever fail.
+    bool success = GetGuestPartitionConfigForSite(browser_context, url,
+                                                  &storage_partition_config);
+    DCHECK(success);
+
+    return storage_partition_config;
   }
 
   return GetContentClient()->browser()->GetStoragePartitionConfigForSite(
diff --git a/content/browser/site_info.h b/content/browser/site_info.h
index 1c7d283..c3581c0b 100644
--- a/content/browser/site_info.h
+++ b/content/browser/site_info.h
@@ -48,8 +48,9 @@
       BrowserContext* browser_context,
       const StoragePartitionConfig storage_partition_config,
       const WebExposedIsolationInfo& web_exposed_isolation_info);
-  static SiteInfo CreateForGuest(BrowserContext* browser_context,
-                                 const GURL& guest_site_url);
+  static SiteInfo CreateForGuest(
+      BrowserContext* browser_context,
+      const StoragePartitionConfig& partition_config);
 
   // This function returns a SiteInfo with the appropriate site_url and
   // process_lock_url computed. This function can only be called on the UI
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 5e0324c..9c72a9b 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -161,7 +161,8 @@
   scoped_refptr<SiteInstanceImpl> site_instance;
 
   if (is_guest) {
-    site_instance = CreateForGuest(browser_context, url_info.url);
+    site_instance = CreateForGuest(browser_context,
+                                   url_info.storage_partition_config.value());
   } else {
     // This will create a new SiteInstance and BrowsingInstance.
     scoped_refptr<BrowsingInstance> instance(new BrowsingInstance(
@@ -192,12 +193,12 @@
 // static
 scoped_refptr<SiteInstanceImpl> SiteInstanceImpl::CreateForGuest(
     BrowserContext* browser_context,
-    const GURL& guest_site_url) {
+    const StoragePartitionConfig& partition_config) {
   DCHECK(browser_context);
-  DCHECK_NE(guest_site_url, GetDefaultSiteURL());
+  DCHECK(!partition_config.is_default());
 
   auto guest_site_info =
-      SiteInfo::CreateForGuest(browser_context, guest_site_url);
+      SiteInfo::CreateForGuest(browser_context, partition_config);
   scoped_refptr<SiteInstanceImpl> site_instance =
       base::WrapRefCounted(new SiteInstanceImpl(new BrowsingInstance(
           browser_context, guest_site_info.web_exposed_isolation_info())));
@@ -765,9 +766,9 @@
 // static
 scoped_refptr<SiteInstance> SiteInstance::CreateForGuest(
     BrowserContext* browser_context,
-    const GURL& guest_site_url) {
+    const StoragePartitionConfig& partition_config) {
   DCHECK(browser_context);
-  return SiteInstanceImpl::CreateForGuest(browser_context, guest_site_url);
+  return SiteInstanceImpl::CreateForGuest(browser_context, partition_config);
 }
 
 // static
diff --git a/content/browser/site_instance_impl.h b/content/browser/site_instance_impl.h
index 03cde26a..a555f63 100644
--- a/content/browser/site_instance_impl.h
+++ b/content/browser/site_instance_impl.h
@@ -36,6 +36,7 @@
 class ProcessLock;
 class RenderProcessHostFactory;
 class SiteInstanceGroup;
+class StoragePartitionConfig;
 class StoragePartitionImpl;
 struct UrlInfo;
 
@@ -75,7 +76,7 @@
       const UrlInfo& url_info);
   static scoped_refptr<SiteInstanceImpl> CreateForGuest(
       BrowserContext* browser_context,
-      const GURL& guest_site_url);
+      const StoragePartitionConfig& partition_config);
 
   // Creates a SiteInstance that will be use for a service worker.
   // `url_info` - The UrlInfo for the service worker. It contains the URL and
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc
index 4d57a91..e00564b 100644
--- a/content/browser/site_instance_impl_unittest.cc
+++ b/content/browser/site_instance_impl_unittest.cc
@@ -1771,18 +1771,15 @@
   }
 
   // Verify that a SiteInstance created with CreateForGuest() is considered
-  // a <webview> guest and has a site URL that is identical to what was passed
-  // to CreateForGuest().
-  auto instance2 = SiteInstanceImpl::CreateForGuest(context(), kGuestUrl);
+  // a <webview> guest and has a site URL that reflects the guest's
+  // StoragePartition configuration.
+  const StoragePartitionConfig kGuestConfig = StoragePartitionConfig::Create(
+      context(), "appid", "partition_name", /*in_memory=*/false);
+  const GURL kGuestSiteUrl(std::string(kGuestScheme) +
+                           "://appid/persist?partition_name#nofallback");
+  auto instance2 = SiteInstanceImpl::CreateForGuest(context(), kGuestConfig);
   EXPECT_TRUE(instance2->IsGuest());
-  EXPECT_EQ(kGuestUrl, instance2->GetSiteURL());
-
-  // Verify that a SiteInstance being considered a <webview> guest does not
-  // depend on using a specific scheme.
-  const GURL kGuestUrl2("my-special-scheme://abc123/path");
-  auto instance3 = SiteInstanceImpl::CreateForGuest(context(), kGuestUrl2);
-  EXPECT_TRUE(instance3->IsGuest());
-  EXPECT_EQ(kGuestUrl2, instance3->GetSiteURL());
+  EXPECT_EQ(kGuestSiteUrl, instance2->GetSiteURL());
 }
 
 TEST_F(SiteInstanceTest, DoesSiteRequireDedicatedProcess) {
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 3f05c9eb..74dba25 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -91,6 +91,7 @@
 #include "content/public/browser/permission_controller.h"
 #include "content/public/browser/service_process_host.h"
 #include "content/public/browser/session_storage_usage_info.h"
+#include "content/public/browser/shared_cors_origin_access_list.h"
 #include "content/public/browser/storage_notification_service.h"
 #include "content/public/browser/storage_usage_info.h"
 #include "content/public/common/content_client.h"
@@ -105,6 +106,7 @@
 #include "net/ssl/client_cert_store.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
+#include "services/network/public/cpp/cors/origin_access_list.h"
 #include "services/network/public/cpp/cross_thread_pending_shared_url_loader_factory.h"
 #include "services/network/public/mojom/cookie_access_observer.mojom.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
@@ -2700,6 +2702,14 @@
   GetContentClient()->browser()->ConfigureNetworkContextParams(
       browser_context_, is_in_memory(), relative_partition_path_,
       context_params.get(), cert_verifier_creation_params.get());
+  // Should be initialized with existing per-profile CORS access lists.
+  DCHECK(context_params->cors_origin_access_list.empty())
+      << "NetworkContextParams::cors_origin_access_list should be populated "
+         "via SharedCorsOriginAccessList";
+  context_params->cors_origin_access_list =
+      browser_context_->GetSharedCorsOriginAccessList()
+          ->GetOriginAccessList()
+          .CreateCorsOriginAccessPatternsList();
   devtools_instrumentation::ApplyNetworkContextParamsOverrides(
       browser_context_, context_params.get());
   DCHECK(!context_params->cert_verifier_params)
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index c4281db..f021d7e4 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -343,19 +343,15 @@
     return cors_exempt_header_list_;
   }
 
-  // When this StoragePartition is for guests (e.g., for a <webview> tag), this
-  // is the site URL to use when creating a SiteInstance for a service worker or
-  // a shared worker. Typically one would use the script URL of the worker
-  // (e.g., "https://example.com/sw.js"), but if this StoragePartition is for
-  // guests, one must use the <webview> guest site URL to ensure that the worker
-  // stays in this StoragePartition. This is an empty GURL if this
-  // StoragePartition is not for guests.
-  void set_site_for_guest_service_worker_or_shared_worker(const GURL& site) {
-    site_for_guest_service_worker_or_shared_worker_ = site;
-  }
-  const GURL& site_for_guest_service_worker_or_shared_worker() const {
-    return site_for_guest_service_worker_or_shared_worker_;
-  }
+  // Tracks whether this StoragePartition is for guests (e.g., for a <webview>
+  // tag).  This is needed to properly create a SiteInstance for a
+  // service worker or a shared worker in a guest. Typically one would use the
+  // script URL of the worker (e.g., "https://example.com/sw.js"), but if this
+  // StoragePartition is for guests, one must create the SiteInstance via
+  // guest-specific helpers that ensure that the worker stays in the same
+  // StoragePartition.
+  void set_is_guest() { is_guest_ = true; }
+  bool is_guest() const { return is_guest_; }
 
   // Use the network context to retrieve the origin policy manager.
   network::mojom::OriginPolicyManager*
@@ -634,8 +630,8 @@
   // Initialized in InitNetworkContext() and never updated after then.
   std::vector<std::string> cors_exempt_header_list_;
 
-  // See comments for site_for_guest_service_worker_or_shared_worker().
-  GURL site_for_guest_service_worker_or_shared_worker_;
+  // See comments for is_guest().
+  bool is_guest_ = false;
 
   // Track number of running deletion. For test use only.
   int deletion_helpers_running_;
diff --git a/content/browser/url_loader_factory_getter.h b/content/browser/url_loader_factory_getter.h
index 9ae7401..6483f39 100644
--- a/content/browser/url_loader_factory_getter.h
+++ b/content/browser/url_loader_factory_getter.h
@@ -38,7 +38,7 @@
   URLLoaderFactoryGetter& operator=(const URLLoaderFactoryGetter&) = delete;
 
   // Initializes this object on the UI thread. The |partition| is used to
-  // initialize the URLLoaderFactories for the network service, AppCache, and
+  // initialize the URLLoaderFactories for the network service, and
   // ServiceWorkers, and will be cached to recover from connection error.
   // After Initialize(), you can get URLLoaderFactories from this
   // getter.
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index e1d90b4..d393855 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -691,8 +691,9 @@
 
 // Same as WebContentsImplBrowserTest.ResourceLoadComplete but with resources
 // retrieved from the network cache.
+// TODO(crbug.com/1271252): Flaky everywhere.
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
-                       ResourceLoadCompleteFromNetworkCache) {
+                       DISABLED_ResourceLoadCompleteFromNetworkCache) {
   ResourceLoadObserver observer(shell());
   ASSERT_TRUE(embedded_test_server()->Start());
   GURL page_url(
@@ -5034,15 +5035,14 @@
   ASSERT_TRUE(WaitForLoadStop(web_contents()));
 
   // Create fenced frame.
+  const GURL fenced_frame_url = embedded_test_server()->GetURL(
+      "fencedframe.test", "/fenced_frames/title1.html");
+
   RenderFrameHost* inner_fenced_frame_rfh =
-      fenced_frame_test_helper().CreateFencedFrame(primary_rfh, main_url);
-  const GURL fenced_frame_url =
-      embedded_test_server()->GetURL("fencedframe.test", "/title2.html");
+      fenced_frame_test_helper().CreateFencedFrame(primary_rfh,
+                                                   fenced_frame_url);
   EXPECT_CALL(observer, DidUpdateFaviconURL(inner_fenced_frame_rfh, testing::_))
       .Times(0);
-  inner_fenced_frame_rfh =
-      fenced_frame_test_helper().NavigateFrameInFencedFrameTree(
-          inner_fenced_frame_rfh, fenced_frame_url);
 }
 
 // Tests that pages are still visible after a page is navigated away
@@ -5058,8 +5058,8 @@
   EXPECT_EQ(Visibility::VISIBLE, web_contents()->GetVisibility());
 
   // Create fenced frame.
-  const GURL fenced_frame_url =
-      embedded_test_server()->GetURL("fencedframe.test", "/title2.html");
+  const GURL fenced_frame_url = embedded_test_server()->GetURL(
+      "fencedframe.test", "/fenced_frames/title1.html");
   content::RenderFrameHost* fenced_frame_host =
       fenced_frame_test_helper().CreateFencedFrame(primary_rfh,
                                                    fenced_frame_url);
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc
index dc7c1ed..fb0dd1ad 100644
--- a/content/browser/web_contents/web_contents_view_aura.cc
+++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -742,6 +742,7 @@
     data.GetFileContents(&filename, &file_contents);
     if (!filename.empty()) {
       drop_data->file_contents = std::move(file_contents);
+      drop_data->file_contents_image_accessible = true;
       drop_data->file_contents_source_url =
           GURL(ui::FilePathToFileURL(filename));
       base::FilePath::StringType extension = filename.Extension();
@@ -1124,7 +1125,7 @@
   drag_start_ =
       DragStart(source_rwh->GetProcess()->GetID(),
                 GetRenderViewHostID(web_contents_->GetRenderViewHost()),
-                drop_data.file_contents_accessible_from_start_frame);
+                drop_data.file_contents_image_accessible);
 
   ui::TouchSelectionController* selection_controller = GetSelectionController();
   if (selection_controller)
diff --git a/content/browser/webauth/webauth_request_security_checker.h b/content/browser/webauth/webauth_request_security_checker.h
index 0f9b56e..79910a73 100644
--- a/content/browser/webauth/webauth_request_security_checker.h
+++ b/content/browser/webauth/webauth_request_security_checker.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "content/common/content_export.h"
 #include "device/fido/public_key_credential_descriptor.h"
diff --git a/content/browser/worker_host/shared_worker_service_impl.cc b/content/browser/worker_host/shared_worker_service_impl.cc
index d7d34b5..e918fe2 100644
--- a/content/browser/worker_host/shared_worker_service_impl.cc
+++ b/content/browser/worker_host/shared_worker_service_impl.cc
@@ -280,8 +280,6 @@
 
   StoragePartitionImpl* partition =
       static_cast<StoragePartitionImpl*>(creator.GetStoragePartition());
-  bool is_guest =
-      !partition->site_for_guest_service_worker_or_shared_worker().is_empty();
 
   // Use the `creator`'s SiteInstance by default, but if that SiteInstance is
   // cross-origin-isolated, create a new non-isolated SiteInstance for the
@@ -293,10 +291,9 @@
   // account.
   scoped_refptr<SiteInstanceImpl> site_instance = creator.GetSiteInstance();
   if (site_instance->IsCrossOriginIsolated()) {
-    if (is_guest) {
+    if (partition->is_guest()) {
       site_instance = SiteInstanceImpl::CreateForGuest(
-          partition->browser_context(),
-          partition->site_for_guest_service_worker_or_shared_worker());
+          partition->browser_context(), partition->GetConfig());
     } else {
       site_instance = SiteInstanceImpl::CreateForUrlInfo(
           partition->browser_context(),
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 52be46b7..7927350 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -339,8 +339,6 @@
           {"AutofillShadowDOM", blink::features::kAutofillShadowDOM},
           {"AndroidDownloadableFontsMatching",
            features::kAndroidDownloadableFontsMatching},
-          {"BlockCredentialedSubresources",
-           features::kBlockCredentialedSubresources},
           {"COLRV1Fonts", blink::features::kCOLRV1Fonts},
           {"CSSContainerQueries", blink::features::kCSSContainerQueries},
           {"ComputePressure", blink::features::kComputePressure,
@@ -398,6 +396,8 @@
           {"WebAppWindowControlsOverlay",
            features::kWebAppWindowControlsOverlay},
           {"WebAuthenticationConditionalUI", features::kWebAuthConditionalUI},
+          {"WindowOpenNewPopupBehavior",
+           blink::features::kWindowOpenNewPopupBehavior},
           {"SyncLoadDataUrlFonts", blink::features::kSyncLoadDataUrlFonts},
           {"CSSCascadeLayers", blink::features::kCSSCascadeLayers},
           // TODO(crbug.com/1185950): Remove this flag when the feature is fully
diff --git a/content/gpu/gpu_child_thread.cc b/content/gpu/gpu_child_thread.cc
index 7fe16ff..d298e367 100644
--- a/content/gpu/gpu_child_thread.cc
+++ b/content/gpu/gpu_child_thread.cc
@@ -175,7 +175,7 @@
   service_factory_ = std::make_unique<GpuServiceFactory>(
       gpu_service->gpu_preferences(),
       gpu_service->gpu_channel_manager()->gpu_driver_bug_workarounds(),
-      gpu_service->gpu_feature_info(),
+      gpu_service->gpu_feature_info(), gpu_service->gpu_info(),
       gpu_service->media_gpu_channel_manager()->AsWeakPtr(),
       gpu_service->gpu_memory_buffer_factory(), std::move(overlay_factory_cb));
   for (auto& receiver : pending_service_receivers_)
diff --git a/content/gpu/gpu_sandbox_hook_linux.cc b/content/gpu/gpu_sandbox_hook_linux.cc
index f21768c..c74f7f3c 100644
--- a/content/gpu/gpu_sandbox_hook_linux.cc
+++ b/content/gpu/gpu_sandbox_hook_linux.cc
@@ -422,9 +422,18 @@
       const char* driver_paths[] = {
 #if defined(DRI_DRIVER_DIR)
         DRI_DRIVER_DIR "/msm_dri.so",
+        DRI_DRIVER_DIR "/panfrost_dri.so",
+        DRI_DRIVER_DIR "/mediatek_dri.so",
+        DRI_DRIVER_DIR "/rockchip_dri.so",
 #else
         "/usr/lib64/dri/msm_dri.so",
+        "/usr/lib64/dri/panfrost_dri.so",
+        "/usr/lib64/dri/mediatek_dri.so",
+        "/usr/lib64/dri/rockchip_dri.so",
         "/usr/lib/dri/msm_dri.so",
+        "/usr/lib/dri/panfrost_dri.so",
+        "/usr/lib/dri/mediatek_dri.so",
+        "/usr/lib/dri/rockchip_dri.so",
 #endif
         nullptr
       };
diff --git a/content/gpu/gpu_service_factory.cc b/content/gpu/gpu_service_factory.cc
index efda557..a9775170 100644
--- a/content/gpu/gpu_service_factory.cc
+++ b/content/gpu/gpu_service_factory.cc
@@ -24,6 +24,7 @@
     const gpu::GpuPreferences& gpu_preferences,
     const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
     const gpu::GpuFeatureInfo& gpu_feature_info,
+    const gpu::GPUInfo& gpu_info,
     base::WeakPtr<media::MediaGpuChannelManager> media_gpu_channel_manager,
     gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
     media::AndroidOverlayMojoFactoryCB android_overlay_factory_cb) {
@@ -31,6 +32,7 @@
   gpu_preferences_ = gpu_preferences;
   gpu_workarounds_ = gpu_workarounds;
   gpu_feature_info_ = gpu_feature_info;
+  gpu_info_ = gpu_info;
   task_runner_ = base::ThreadTaskRunnerHandle::Get();
   media_gpu_channel_manager_ = std::move(media_gpu_channel_manager);
   gpu_memory_buffer_factory_ = gpu_memory_buffer_factory;
@@ -61,7 +63,7 @@
   FactoryCallback factory =
       base::BindOnce(&media::CreateGpuMediaService, std::move(receiver),
                      gpu_preferences_, gpu_workarounds_, gpu_feature_info_,
-                     task_runner_, media_gpu_channel_manager_,
+                     gpu_info_, task_runner_, media_gpu_channel_manager_,
                      gpu_memory_buffer_factory_, android_overlay_factory_cb_);
   task_runner->PostTask(
       FROM_HERE,
diff --git a/content/gpu/gpu_service_factory.h b/content/gpu/gpu_service_factory.h
index 571e53e..3765fb5 100644
--- a/content/gpu/gpu_service_factory.h
+++ b/content/gpu/gpu_service_factory.h
@@ -10,6 +10,7 @@
 #include "base/task/single_thread_task_runner.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "gpu/config/gpu_feature_info.h"
+#include "gpu/config/gpu_info.h"
 #include "gpu/config/gpu_preferences.h"
 #include "media/base/android_overlay_mojo_factory.h"
 #include "media/mojo/buildflags.h"
@@ -33,6 +34,7 @@
       const gpu::GpuPreferences& gpu_preferences,
       const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
       const gpu::GpuFeatureInfo& gpu_feature_info,
+      const gpu::GPUInfo& gpu_info,
       base::WeakPtr<media::MediaGpuChannelManager> media_gpu_channel_manager,
       gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
       media::AndroidOverlayMojoFactoryCB android_overlay_factory_cb);
@@ -59,6 +61,7 @@
   gpu::GpuPreferences gpu_preferences_;
   gpu::GpuDriverBugWorkarounds gpu_workarounds_;
   gpu::GpuFeatureInfo gpu_feature_info_;
+  gpu::GPUInfo gpu_info_;
 #endif
 };
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/font/AndroidFontLookupImpl.java b/content/public/android/java/src/org/chromium/content/browser/font/AndroidFontLookupImpl.java
index d43e510..5d0bfa1 100644
--- a/content/public/android/java/src/org/chromium/content/browser/font/AndroidFontLookupImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/font/AndroidFontLookupImpl.java
@@ -23,6 +23,7 @@
 import org.chromium.base.Log;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.PostTask;
+import org.chromium.base.task.SequencedTaskRunner;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.blink.mojom.AndroidFontLookup;
 import org.chromium.content.R;
@@ -57,6 +58,8 @@
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     static final String MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM =
             "Android.FontLookup.MatchLocalFontByUniqueName.Time";
+    static final String FETCH_ALL_FONT_FILES_HISTOGRAM =
+            "Android.FontLookup.FetchAllFontFiles.Time";
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     static final String GMS_FONT_REQUEST_HISTOGRAM = "Android.FontLookup.GmsFontRequest.Time";
 
@@ -79,6 +82,9 @@
      */
     private final Set<String> mExpectedFonts;
 
+    private final SequencedTaskRunner mTaskRunner =
+            PostTask.createSequencedTaskRunner(TaskTraits.USER_BLOCKING_MAY_BLOCK);
+
     private AndroidFontLookupImpl(Context appContext) {
         this(appContext, new FontsContractWrapper(), createFullFontNameToQueryMap());
     }
@@ -164,27 +170,58 @@
         Executor executor = ExecutorFactory.getExecutorForCurrentThread(core);
 
         // Post synchronous font request to background worker thread.
-        PostTask.postTask(TaskTraits.USER_BLOCKING, () -> {
-            ReadOnlyFile file = null;
-
-            ParcelFileDescriptor fileDescriptor = tryFetchFont(fontUniqueName);
-            if (fileDescriptor == null) {
-                // Avoid re-requesting this font in future.
-                mExpectedFonts.remove(fontUniqueName);
-            } else {
-                // Wrap file descriptor as an opened Mojo file handle.
-                file = new ReadOnlyFile();
-                file.fd = core.wrapFileDescriptor(fileDescriptor);
-                file.async = false;
-            }
-
-            final ReadOnlyFile result = file;
+        mTaskRunner.postTask(() -> {
+            final ReadOnlyFile result = fetchFontInBackground(fontUniqueName, core);
             RecordHistogram.recordTimesHistogram(MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM,
                     SystemClock.elapsedRealtime() - startTimeMs);
             executor.execute(() -> callback.call(result));
         });
     }
 
+    /** Fetches all available font files from the {@link #mExpectedFonts} array. */
+    @Override
+    public void fetchAllFontFiles(FetchAllFontFiles_Response callback) {
+        long startTimeMs = SystemClock.elapsedRealtime();
+        Core core = CoreImpl.getInstance();
+        Executor executor = ExecutorFactory.getExecutorForCurrentThread(core);
+
+        // Post synchronous font request to background worker thread.
+        mTaskRunner.postTask(() -> {
+            HashMap<String, ReadOnlyFile> result = new HashMap<>();
+            // Make a copy of mExpectedFonts because it may be modified.
+            for (String font : mExpectedFonts.toArray(new String[mExpectedFonts.size()])) {
+                ReadOnlyFile file = fetchFontInBackground(font, core);
+                if (file != null) {
+                    result.put(font, file);
+                }
+            }
+            RecordHistogram.recordTimesHistogram(
+                    FETCH_ALL_FONT_FILES_HISTOGRAM, SystemClock.elapsedRealtime() - startTimeMs);
+            executor.execute(() -> callback.call(result));
+        });
+    }
+
+    /**
+     * Fetches the font file from GMS Core and removes from the expected fonts array if not
+     * available.
+     *
+     * @param fontUniqueName The ICU case folded unique full font name to fetch.
+     */
+    private ReadOnlyFile fetchFontInBackground(String fontUniqueName, Core core) {
+        ParcelFileDescriptor fileDescriptor = tryFetchFont(fontUniqueName);
+        if (fileDescriptor == null) {
+            // Avoid re-requesting this font in future.
+            mExpectedFonts.remove(fontUniqueName);
+        } else {
+            // Wrap file descriptor as an opened Mojo file handle.
+            ReadOnlyFile file = new ReadOnlyFile();
+            file.fd = core.wrapFileDescriptor(fileDescriptor);
+            file.async = false;
+            return file;
+        }
+        return null;
+    }
+
     /**
      * Tries to fetch the specified font from GMS Core (the Android Downloadable fonts provider).
      *
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/font/AndroidFontLookupImplTest.java b/content/public/android/javatests/src/org/chromium/content/browser/font/AndroidFontLookupImplTest.java
index cc87bb7d..8bf591ac4 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/font/AndroidFontLookupImplTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/font/AndroidFontLookupImplTest.java
@@ -5,6 +5,8 @@
 package org.chromium.content.browser.font;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.AdditionalMatchers.aryEq;
 import static org.mockito.ArgumentMatchers.argThat;
@@ -39,6 +41,8 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.stubbing.OngoingStubbing;
 
@@ -46,12 +50,14 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.blink.mojom.AndroidFontLookup;
+import org.chromium.blink.mojom.AndroidFontLookup.FetchAllFontFiles_Response;
 import org.chromium.blink.mojom.AndroidFontLookup.GetUniqueNameLookupTable_Response;
 import org.chromium.blink.mojom.AndroidFontLookup.MatchLocalFontByUniqueName_Response;
 import org.chromium.content.browser.font.AndroidFontLookupImpl.FetchFontName;
 import org.chromium.content.browser.font.AndroidFontLookupImpl.FetchFontResult;
 import org.chromium.content_public.browser.test.NativeLibraryTestUtils;
 import org.chromium.mojo.MojoTestRule;
+import org.chromium.mojo_base.mojom.ReadOnlyFile;
 
 import java.util.Map;
 
@@ -88,6 +94,11 @@
     private GetUniqueNameLookupTable_Response mGetUniqueNameLookupTableCallback;
     @Mock
     private MatchLocalFontByUniqueName_Response mMatchLocalFontByUniqueNameCallback;
+    @Mock
+    private FetchAllFontFiles_Response mFetchAllFontFilesCallback;
+
+    @Captor
+    private ArgumentCaptor<Map<String, ReadOnlyFile>> mFontMapCaptor;
 
     private AndroidFontLookupImpl mAndroidFontLookup;
 
@@ -135,6 +146,80 @@
 
     @SmallTest
     @Test
+    public void testFetchAllFontFiles_Available() throws NameNotFoundException {
+        FontInfo fontInfo = new FontInfo(URI, 0, 400, false, Columns.RESULT_CODE_OK);
+        FontFamilyResult result =
+                new FontFamilyResult(FontFamilyResult.STATUS_OK, new FontInfo[] {fontInfo});
+        whenFetchFontsWith(FONT_QUERY_1).thenReturn(result);
+        whenFetchFontsWith(FONT_QUERY_2).thenReturn(result);
+        whenFetchFontsWith(FONT_QUERY_3).thenReturn(result);
+
+        mAndroidFontLookup.fetchAllFontFiles(mFetchAllFontFilesCallback);
+
+        mMojoTestRule.runLoop(RUN_LOOP_TIMEOUT_MS);
+        verify(mFetchAllFontFilesCallback).call(mFontMapCaptor.capture());
+
+        Map<String, ReadOnlyFile> response = mFontMapCaptor.getValue();
+        assertEquals(3, response.size());
+        assertNotNull(response.get(FULL_FONT_NAME_1));
+        assertNotNull(response.get(FULL_FONT_NAME_2));
+        assertNotNull(response.get(FULL_FONT_NAME_3));
+
+        assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        AndroidFontLookupImpl.FETCH_ALL_FONT_FILES_HISTOGRAM));
+    }
+
+    @SmallTest
+    @Test
+    public void testFetchAllFontFiles_OneNotAvailable() throws NameNotFoundException {
+        FontInfo fontInfo = new FontInfo(URI, 0, 400, false, Columns.RESULT_CODE_OK);
+        FontFamilyResult result =
+                new FontFamilyResult(FontFamilyResult.STATUS_OK, new FontInfo[] {fontInfo});
+        whenFetchFontsWith(FONT_QUERY_1).thenReturn(result);
+        whenFetchFontsWith(FONT_QUERY_2).thenReturn(result);
+        whenFetchFontsWith(FONT_QUERY_3)
+                .thenReturn(new FontFamilyResult(
+                        FontFamilyResult.STATUS_UNEXPECTED_DATA_PROVIDED, null));
+
+        mAndroidFontLookup.fetchAllFontFiles(mFetchAllFontFilesCallback);
+
+        mMojoTestRule.runLoop(RUN_LOOP_TIMEOUT_MS);
+        verify(mFetchAllFontFilesCallback).call(mFontMapCaptor.capture());
+
+        Map<String, ReadOnlyFile> response = mFontMapCaptor.getValue();
+        assertEquals(2, response.size());
+        assertNotNull(response.get(FULL_FONT_NAME_1));
+        assertNotNull(response.get(FULL_FONT_NAME_2));
+
+        assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        AndroidFontLookupImpl.FETCH_ALL_FONT_FILES_HISTOGRAM));
+
+        // Verify the font was removed from the lookup table.
+        mAndroidFontLookup.getUniqueNameLookupTable(mGetUniqueNameLookupTableCallback);
+        mMojoTestRule.runLoop(RUN_LOOP_TIMEOUT_MS);
+        verify(mGetUniqueNameLookupTableCallback)
+                .call(aryEq(new String[] {FULL_FONT_NAME_2, FULL_FONT_NAME_1}));
+    }
+
+    @SmallTest
+    @Test
+    public void testFetchAllFontFiles_Empty() throws NameNotFoundException {
+        mAndroidFontLookup = new AndroidFontLookupImpl(
+                mMockContext, mMockFontsContractWrapper, ImmutableMap.of());
+
+        mAndroidFontLookup.fetchAllFontFiles(mFetchAllFontFilesCallback);
+
+        mMojoTestRule.runLoop(RUN_LOOP_TIMEOUT_MS);
+        verify(mFetchAllFontFilesCallback).call(mFontMapCaptor.capture());
+
+        Map<String, ReadOnlyFile> response = mFontMapCaptor.getValue();
+        assertTrue(response.isEmpty());
+    }
+
+    @SmallTest
+    @Test
     public void testGetUniqueNameLookupTable_MultipleFonts() throws NameNotFoundException {
         // All 3 fonts should be found in results.
         mAndroidFontLookup.getUniqueNameLookupTable(mGetUniqueNameLookupTableCallback);
diff --git a/content/public/browser/browser_thread.h b/content/public/browser/browser_thread.h
index 256c32d6..35bdc8629 100644
--- a/content/public/browser/browser_thread.h
+++ b/content/public/browser/browser_thread.h
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "base/callback.h"
+#include "base/compiler_specific.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
diff --git a/content/public/browser/per_web_ui_browser_interface_broker.h b/content/public/browser/per_web_ui_browser_interface_broker.h
index 173b00a..23ffe70a 100644
--- a/content/public/browser/per_web_ui_browser_interface_broker.h
+++ b/content/public/browser/per_web_ui_browser_interface_broker.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_PUBLIC_BROWSER_PER_WEB_UI_BROWSER_INTERFACE_BROKER_H_
 #define CONTENT_PUBLIC_BROWSER_PER_WEB_UI_BROWSER_INTERFACE_BROKER_H_
 
+#include "base/compiler_specific.h"
 #include "mojo/public/cpp/bindings/binder_map.h"
 #include "mojo/public/cpp/bindings/generic_pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
@@ -39,4 +40,4 @@
 };
 }  // namespace content
 
-#endif  // CONTENT_PUBLIC_BROWSER_PER_WEBUI_BROWSER_INTERFACE_BROKER_H_
\ No newline at end of file
+#endif  // CONTENT_PUBLIC_BROWSER_PER_WEBUI_BROWSER_INTERFACE_BROKER_H_
diff --git a/content/public/browser/site_instance.h b/content/public/browser/site_instance.h
index 84d2c20..adb4470 100644
--- a/content/public/browser/site_instance.h
+++ b/content/public/browser/site_instance.h
@@ -20,6 +20,7 @@
 namespace content {
 class BrowserContext;
 class RenderProcessHost;
+class StoragePartitionConfig;
 
 using SiteInstanceId = base::IdType32<class SiteInstanceIdTag>;
 
@@ -216,11 +217,11 @@
       const GURL& url);
 
   // Factory method to create a SiteInstance for a <webview> guest in a new
-  // BrowsingInstance.
-  // TODO(734722): Replace this method once SecurityPrincipal is available.
+  // BrowsingInstance. A guest requires a non-default StoragePartitionConfig
+  // which should be passed in via `partition_config`.
   static scoped_refptr<SiteInstance> CreateForGuest(
       BrowserContext* browser_context,
-      const GURL& guest_site_url);
+      const StoragePartitionConfig& partition_config);
 
   // Determine if a URL should "use up" a site.  URLs such as about:blank or
   // chrome-native:// leave the site unassigned.
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index ff8ffd22..909909a7a 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -113,11 +113,6 @@
 #endif
 };
 
-// Block subresource requests whose URLs contain embedded credentials (e.g.
-// `https://user:pass@example.com/resource`).
-const base::Feature kBlockCredentialedSubresources{
-    "BlockCredentialedSubresources", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // When this feature is enabled, private network requests initiated from
 // non-secure contexts in the `public` address space  are blocked.
 //
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index e80e8fc..870e7e6d 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -34,7 +34,6 @@
 CONTENT_EXPORT extern const base::Feature kBackForwardCacheSameSiteForBots;
 CONTENT_EXPORT extern const base::Feature kBackForwardCacheMemoryControls;
 CONTENT_EXPORT extern const base::Feature kBackForwardCacheMediaSessionService;
-CONTENT_EXPORT extern const base::Feature kBlockCredentialedSubresources;
 CONTENT_EXPORT extern const base::Feature kBlockInsecurePrivateNetworkRequests;
 CONTENT_EXPORT extern const base::Feature
     kBlockInsecurePrivateNetworkRequestsFromPrivate;
diff --git a/content/public/common/drop_data.h b/content/public/common/drop_data.h
index f6c90f0..75564bb 100644
--- a/content/public/common/drop_data.h
+++ b/content/public/common/drop_data.h
@@ -115,7 +115,7 @@
 
   // User is dragging an image out of the WebView.
   std::string file_contents;
-  bool file_contents_accessible_from_start_frame = false;
+  bool file_contents_image_accessible = false;
   GURL file_contents_source_url;
   base::FilePath::StringType file_contents_filename_extension;
   std::string file_contents_content_disposition;
diff --git a/content/public/test/browser_task_environment.cc b/content/public/test/browser_task_environment.cc
index 5421b5c..725e8d2 100644
--- a/content/public/test/browser_task_environment.cc
+++ b/content/public/test/browser_task_environment.cc
@@ -143,7 +143,7 @@
 
   // Run DestructionObservers before our fake threads go away to ensure
   // BrowserThread::CurrentlyOn() returns the results expected by the observers.
-  NotifyDestructionObserversAndReleaseSequenceManager();
+  DestroyTaskEnvironment();
 
 #if defined(OS_WIN)
   com_initializer_.reset();
diff --git a/content/public/test/content_browser_test_utils.h b/content/public/test/content_browser_test_utils.h
index 88bf33f..9aff7101 100644
--- a/content/public/test/content_browser_test_utils.h
+++ b/content/public/test/content_browser_test_utils.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/compiler_specific.h"
 #include "base/run_loop.h"
 #include "content/public/common/page_type.h"
 #include "ui/gfx/native_widget_types.h"
diff --git a/content/public/test/fenced_frame_test_util.cc b/content/public/test/fenced_frame_test_util.cc
index 1e79a72..59afe847 100644
--- a/content/public/test/fenced_frame_test_util.cc
+++ b/content/public/test/fenced_frame_test_util.cc
@@ -19,7 +19,6 @@
 
 constexpr char kAddFencedFrameScript[] = R"({
     const fenced_frame = document.createElement('fencedframe');
-    fenced_frame.src = $1;
     document.body.appendChild(fenced_frame);
   })";
 
@@ -60,7 +59,8 @@
 
 RenderFrameHost* FencedFrameTestHelper::CreateFencedFrame(
     RenderFrameHost* fenced_frame_parent,
-    const GURL& url) {
+    const GURL& url,
+    net::Error expected_error_code) {
   TRACE_EVENT("test", "FencedFrameTestHelper::CreateAndGetFencedFrame",
               "fenced_frame_parent", fenced_frame_parent, "url", url);
   RenderFrameHostImpl* fenced_frame_parent_rfh =
@@ -77,25 +77,20 @@
   EXPECT_EQ(previous_fenced_frame_count + 1, fenced_frames.size());
 
   FencedFrame* fenced_frame = fenced_frames.back();
-  fenced_frame->WaitForDidStopLoadingForTesting();
   // It is possible that we got the did stop loading notification because the
   // fenced frame was actually being destroyed. Check to make sure that's not
   // the case. TODO(crbug.com/1123606): Consider weakly referencing the fenced
   // frame if the removal-and-stop-loading scenario is a useful one to test.
   EXPECT_EQ(previous_fenced_frame_count + 1,
             fenced_frame_parent_rfh->GetFencedFrames().size());
-
-  // Return the main RenderFrameHost of the most-recently added fenced frame if
-  // the navigation committed successfully.
-  if (fenced_frame->GetInnerRoot()->GetLastCommittedURL() == url)
-    return fenced_frame->GetInnerRoot();
-
-  return nullptr;
+  return NavigateFrameInFencedFrameTree(fenced_frame->GetInnerRoot(), url,
+                                        expected_error_code);
 }
 
 RenderFrameHost* FencedFrameTestHelper::NavigateFrameInFencedFrameTree(
     RenderFrameHost* rfh,
-    const GURL& url) {
+    const GURL& url,
+    net::Error expected_error_code) {
   TRACE_EVENT("test", "FencedFrameTestHelper::NavigateFrameInsideFencedFrame",
               "rfh", rfh, "url", url);
   // TODO(domfarolino): Consider adding |url| to the relevant
@@ -107,14 +102,17 @@
   FrameTreeNode* target_node =
       static_cast<RenderFrameHostImpl*>(rfh)->frame_tree_node();
   EXPECT_EQ(url.spec(), EvalJs(rfh, JsReplace(kNavigateFrameScript, url)));
-  fenced_frame->WaitForDidStopLoadingForTesting();
 
-  // Return the `RenderFrameHost` that the navigation committed to, if it did
-  // indeed commit successfully. Otherwise, return `nullptr` to indicate that
-  // the navigation did not succeed, even though the old `RenderFrameHost` still
-  // exists and is still valid.
-  if (target_node->current_frame_host()->GetLastCommittedURL() != url)
-    return nullptr;
+  // TODO(crbug.com/1257133): Once this bug is fixed, we can use
+  // `TestFrameNavigationObserver` to tell us when the navigation has finished,
+  // which actually exposes net::Error codes encountered during navigation.
+  // Therefore once that bug is fixed, we can perform finer-grained error
+  // code comparisons than the crude `RenderFrameHost::IsErrorDocument()` one
+  // below.
+  fenced_frame->WaitForDidStopLoadingForTesting();
+  EXPECT_EQ(expected_error_code == net::Error::OK,
+            !target_node->current_frame_host()->IsErrorDocument());
+  EXPECT_EQ(target_node->current_frame_host()->GetLastCommittedURL(), url);
 
   return target_node->current_frame_host();
 }
diff --git a/content/public/test/fenced_frame_test_util.h b/content/public/test/fenced_frame_test_util.h
index 5f5a062..4b96b498 100644
--- a/content/public/test/fenced_frame_test_util.h
+++ b/content/public/test/fenced_frame_test_util.h
@@ -5,7 +5,9 @@
 #ifndef CONTENT_PUBLIC_TEST_FENCED_FRAME_TEST_UTIL_H_
 #define CONTENT_PUBLIC_TEST_FENCED_FRAME_TEST_UTIL_H_
 
+#include "base/compiler_specific.h"
 #include "base/test/scoped_feature_list.h"
+#include "net/base/net_errors.h"
 
 class GURL;
 
@@ -28,9 +30,12 @@
   // This method creates a new fenced frame rooted at `fenced_frame_parent` that
   // is navigated to `url`. This method waits for the navigation to `url` to
   // commit, and returns the `RenderFrameHost` that committed the navigation if
-  // it succeeded. Otherwise, it returns `nullptr`.
+  // it succeeded. Otherwise, it returns `nullptr`. See
+  // `NavigationFrameInFencedFrameTree()` documentation for the
+  // `expected_error_code` parameter.
   RenderFrameHost* CreateFencedFrame(RenderFrameHost* fenced_frame_parent,
-                                     const GURL& url) WARN_UNUSED_RESULT;
+                                     const GURL& url,
+                                     net::Error expected_error_code = net::OK);
 
   // This method provides a way to navigate frames within a fenced frame's tree,
   // and synchronously wait for the load to finish. The reason we have this
@@ -39,12 +44,15 @@
   // `TestFrameNavigationObserver`. This method returns the `RenderFrameHost`
   // that the navigation committed to if it was successful (which may be
   // different from the one that navigation started in), and `nullptr`
-  // otherwise.
+  // otherwise. It takes an `expected_error_code` in case the navigation to
+  // `url` fails, which can be detected on a per-error-code basis.
   // TODO(crbug.com/1199682): Fix the underlying reason why we cannot use
   // traditional means of waiting for a navigation to finish loading inside a
   // fenced frame tree.
-  RenderFrameHost* NavigateFrameInFencedFrameTree(RenderFrameHost* rfh,
-                                                  const GURL& url);
+  RenderFrameHost* NavigateFrameInFencedFrameTree(
+      RenderFrameHost* rfh,
+      const GURL& url,
+      net::Error expected_error_code = net::OK);
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
diff --git a/content/public/test/prerender_test_util.h b/content/public/test/prerender_test_util.h
index ed5099e4..4d3422b 100644
--- a/content/public/test/prerender_test_util.h
+++ b/content/public/test/prerender_test_util.h
@@ -6,6 +6,7 @@
 #define CONTENT_PUBLIC_TEST_PRERENDER_TEST_UTIL_H_
 
 #include "base/callback.h"
+#include "base/compiler_specific.h"
 #include "base/test/scoped_feature_list.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/test/browser_test_utils.h"
diff --git a/content/public/test/test_utils.h b/content/public/test/test_utils.h
index 1f50f3c..7723c21 100644
--- a/content/public/test/test_utils.h
+++ b/content/public/test/test_utils.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/callback.h"
+#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "base/threading/thread_checker.h"
diff --git a/content/renderer/renderer_main.cc b/content/renderer/renderer_main.cc
index 01cef342..59bec88 100644
--- a/content/renderer/renderer_main.cc
+++ b/content/renderer/renderer_main.cc
@@ -109,9 +109,7 @@
 int RendererMain(MainFunctionParams parameters) {
   // Don't use the TRACE_EVENT0 macro because the tracing infrastructure doesn't
   // expect synchronous events around the main loop of a thread.
-  TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("startup", "RendererMain",
-                                    TRACE_ID_WITH_SCOPE("RendererMain", 0),
-                                    "zygote_child", false);
+  TRACE_EVENT_INSTANT0("startup", "RendererMain", TRACE_EVENT_SCOPE_THREAD);
 
   base::trace_event::TraceLog::GetInstance()->set_process_name("Renderer");
   base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex(
@@ -236,9 +234,8 @@
     // the tracing SMB on our behalf due to the zygote sandbox.
     if (parameters.zygote_child) {
       tracing::EnableStartupTracingIfNeeded();
-      TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("startup", "RendererMain",
-                                        TRACE_ID_WITH_SCOPE("RendererMain", 0),
-                                        "zygote_child", true);
+      TRACE_EVENT_INSTANT1("startup", "RendererMain", TRACE_EVENT_SCOPE_THREAD,
+                           "zygote_child", true);
     }
 #endif  // OS_POSIX && !OS_ANDROID && !OS_MAC
 
@@ -259,15 +256,11 @@
       if (pool)
         pool->Recycle();
 #endif
-      TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
-          "toplevel", "RendererMain.START_MSG_LOOP",
-          TRACE_ID_WITH_SCOPE("RendererMain.START_MSG_LOOP", 0));
+      TRACE_EVENT_INSTANT0("toplevel", "RendererMain.START_MSG_LOOP",
+                           TRACE_EVENT_SCOPE_THREAD);
       RenderThreadImpl::current()->set_run_loop_start_time(
           base::TimeTicks::Now());
       run_loop.Run();
-      TRACE_EVENT_NESTABLE_ASYNC_END0(
-          "toplevel", "RendererMain.START_MSG_LOOP",
-          TRACE_ID_WITH_SCOPE("RendererMain.START_MSG_LOOP", 0));
     }
 
 #if defined(LEAK_SANITIZER)
@@ -277,8 +270,6 @@
 #endif
   }
   platform.PlatformUninitialize();
-  TRACE_EVENT_NESTABLE_ASYNC_END0("startup", "RendererMain",
-                                  TRACE_ID_WITH_SCOPE("RendererMain", 0));
   return 0;
 }
 
diff --git a/content/services/auction_worklet/auction_v8_devtools_agent.cc b/content/services/auction_worklet/auction_v8_devtools_agent.cc
index ee355b8..760e9094 100644
--- a/content/services/auction_worklet/auction_v8_devtools_agent.cc
+++ b/content/services/auction_worklet/auction_v8_devtools_agent.cc
@@ -107,10 +107,14 @@
 
   auto it = context_groups_.find(context_group_id);
   DCHECK(it != context_groups_.end());
+  DCHECK(!it->second.sessions.empty());
+  AuctionV8DevToolsSession* session = *it->second.sessions.begin();
 
   v8_helper_->PauseTimeoutTimer();
   paused_ = true;
-  debug_command_queue_->PauseForDebuggerAndRunCommands();
+  base::OnceClosure abort_callback = session->MakeAbortPauseCallback();
+  debug_command_queue_->PauseForDebuggerAndRunCommands(
+      context_group_id, std::move(abort_callback));
   DCHECK(paused_);
   v8_helper_->ResumeTimeoutTimer();
   paused_ = false;
diff --git a/content/services/auction_worklet/auction_v8_devtools_session.cc b/content/services/auction_worklet/auction_v8_devtools_session.cc
index 416910da0..0a61c8eb 100644
--- a/content/services/auction_worklet/auction_v8_devtools_session.cc
+++ b/content/services/auction_worklet/auction_v8_devtools_session.cc
@@ -190,6 +190,15 @@
   v8_session_.reset();
 }
 
+base::OnceClosure AuctionV8DevToolsSession::MakeAbortPauseCallback() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(v8_sequence_checker_);
+  // Note that this can be cancelled by the weak pointer only if the session
+  // got unpaused by other means, since if it's paused it's not returning
+  // control to the event loop, so Mojo won't get a chance to delete `this`.
+  return base::BindOnce(&AuctionV8DevToolsSession::AbortDebuggerPause,
+                        weak_ptr_factory_.GetWeakPtr());
+}
+
 void AuctionV8DevToolsSession::MaybeTriggerInstrumentationBreakpoint(
     const std::string& name) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(v8_sequence_checker_);
@@ -282,6 +291,13 @@
   NOTIMPLEMENTED();
 }
 
+void AuctionV8DevToolsSession::AbortDebuggerPause() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(v8_sequence_checker_);
+  // Note that if the session got resumed by other means before execution got
+  // here V8 will simply ignore this call.
+  v8_session_->resume(/*setTerminateOnResume=*/true);
+}
+
 void AuctionV8DevToolsSession::SendProtocolResponseImpl(
     int call_id,
     std::vector<uint8_t> message) {
diff --git a/content/services/auction_worklet/auction_v8_devtools_session.h b/content/services/auction_worklet/auction_v8_devtools_session.h
index b948c9f..39faca6 100644
--- a/content/services/auction_worklet/auction_v8_devtools_session.h
+++ b/content/services/auction_worklet/auction_v8_devtools_session.h
@@ -63,6 +63,10 @@
   AuctionV8DevToolsSession& operator=(const AuctionV8DevToolsSession&) = delete;
   ~AuctionV8DevToolsSession() override;
 
+  // Creates a callback that will ask V8 to exit a debugger pause and abort
+  // further execution. Bound to a weak pointer.
+  base::OnceClosure MakeAbortPauseCallback();
+
   int context_group_id() const { return context_group_id_; }
 
   // If an instrumentation breakpoint named `name` has been set, asks V8 for
@@ -103,6 +107,8 @@
   class IOSession;
   class BreakpointHandler;
 
+  void AbortDebuggerPause();
+
   void SendProtocolResponseImpl(int call_id, std::vector<uint8_t> message);
   void SendNotificationImpl(std::vector<uint8_t> message);
 
diff --git a/content/services/auction_worklet/auction_v8_helper.cc b/content/services/auction_worklet/auction_v8_helper.cc
index 25e7dca..c5f8edc 100644
--- a/content/services/auction_worklet/auction_v8_helper.cc
+++ b/content/services/auction_worklet/auction_v8_helper.cc
@@ -276,6 +276,10 @@
   v8_helper_->SetResumeCallback(context_group_id_, std::move(resume_callback));
 }
 
+void AuctionV8Helper::DebugId::AbortDebuggerPauses() {
+  v8_helper_->AbortDebuggerPauses(context_group_id_);
+}
+
 AuctionV8Helper::DebugId::~DebugId() {
   v8_helper_->FreeContextGroupId(context_group_id_);
 }
@@ -519,6 +523,10 @@
   return func_result;
 }
 
+void AuctionV8Helper::AbortDebuggerPauses(int context_group_id) {
+  debug_command_queue_->AbortPauses(context_group_id);
+}
+
 void AuctionV8Helper::MaybeTriggerInstrumentationBreakpoint(
     const DebugId& debug_id,
     const std::string& name) {
@@ -561,9 +569,12 @@
 }
 
 void AuctionV8Helper::FreeContextGroupId(int context_group_id) {
-  base::AutoLock hold_lock(context_groups_lock_);
-  size_t removed = resume_callbacks_.erase(context_group_id);
-  DCHECK_EQ(1u, removed);
+  debug_command_queue_->RecycleContextGroupId(context_group_id);
+  {
+    base::AutoLock hold_lock(context_groups_lock_);
+    size_t removed = resume_callbacks_.erase(context_group_id);
+    DCHECK_EQ(1u, removed);
+  }
 }
 
 void AuctionV8Helper::Resume(int context_group_id) {
@@ -669,7 +680,8 @@
     scoped_refptr<base::SingleThreadTaskRunner> v8_runner)
     : base::RefCountedDeleteOnSequence<AuctionV8Helper>(v8_runner),
       v8_runner_(v8_runner),
-      timer_task_runner_(base::ThreadPool::CreateSequencedTaskRunner({})) {
+      timer_task_runner_(base::ThreadPool::CreateSequencedTaskRunner({})),
+      debug_command_queue_(base::MakeRefCounted<DebugCommandQueue>(v8_runner)) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
 
   // InitV8 on main thread, to avoid races if multiple instances exist with
@@ -699,11 +711,6 @@
       gin::IsolateHolder::IsolateType::kUtility);
   FullIsolateScope v8_scope(this);
   scratch_context_.Reset(isolate(), CreateContext());
-
-  // This is mostly unneeded unless the debugger agent is in use, but having it
-  // always wil lbe helpful for preventing races if debugger is being created
-  // right as a worklet is being unloaded.
-  debug_command_queue_ = std::make_unique<DebugCommandQueue>();
 }
 
 // static
diff --git a/content/services/auction_worklet/auction_v8_helper.h b/content/services/auction_worklet/auction_v8_helper.h
index ed4dc0b..3a3538d 100644
--- a/content/services/auction_worklet/auction_v8_helper.h
+++ b/content/services/auction_worklet/auction_v8_helper.h
@@ -79,7 +79,8 @@
   };
 
   // A wrapper for identifiers used to associate V8 context's with debugging
-  // primitives.  Passed to methods like Compile and RunScript.
+  // primitives.  Passed to methods like Compile and RunScript. If one is
+  // created, AbortDebuggerPauses() must be called before its destruction.
   //
   // This class is thread-safe, except SetResumeCallback must be used from V8
   // thread.
@@ -98,6 +99,18 @@
     // mojo pipes, making its timing hard to relate to worklet lifetime.
     void SetResumeCallback(base::OnceClosure resume_callback);
 
+    // If the JS thread is currently within AuctionV8Helper::RunScript() running
+    // code with this debug id, and the execution has been paused by the
+    // debugger, aborts the execution.
+    //
+    // Always prevents further debugger pauses of code associated with this
+    // debug id.
+    //
+    // This may be called from any thread, but note that posting this to the V8
+    // thread is unlikely to work, since this method is in particular useful for
+    // the cases where the V8 thread is blocked.
+    void AbortDebuggerPauses();
+
    private:
     friend class base::RefCountedThreadSafe<DebugId>;
     ~DebugId();
@@ -309,6 +322,7 @@
   int AllocContextGroupId();
   void SetResumeCallback(int context_group_id,
                          base::OnceClosure resume_callback);
+  void AbortDebuggerPauses(int context_group_id);
   void FreeContextGroupId(int context_group_id);
 
   static std::string FormatExceptionMessage(v8::Local<v8::Context> context,
@@ -343,8 +357,7 @@
   std::map<int, base::OnceClosure> resume_callbacks_
       GUARDED_BY(context_groups_lock_);
 
-  std::unique_ptr<DebugCommandQueue> debug_command_queue_
-      GUARDED_BY_CONTEXT(sequence_checker_);
+  scoped_refptr<DebugCommandQueue> debug_command_queue_;
 
   // Destruction order between `devtools_agent_` and `v8_inspector_` is
   // relevant; see also comment in ~AuctionV8Helper().
diff --git a/content/services/auction_worklet/auction_v8_helper_unittest.cc b/content/services/auction_worklet/auction_v8_helper_unittest.cc
index d4ce77e..dd2b30a7 100644
--- a/content/services/auction_worklet/auction_v8_helper_unittest.cc
+++ b/content/services/auction_worklet/auction_v8_helper_unittest.cc
@@ -458,6 +458,7 @@
 
   // ... including after free.
   int save_id1 = id1->context_group_id();
+  id1->AbortDebuggerPauses();
   id1.reset();
   helper_->Resume(save_id1);
   ASSERT_EQ(1, resume_callback_invocations);
@@ -472,6 +473,7 @@
   EXPECT_GT(id2->context_group_id(), 0);
   ASSERT_EQ(1, resume_callback_invocations);
   int save_id2 = id2->context_group_id();
+  id2->AbortDebuggerPauses();
   id2.reset();
   helper_->Resume(save_id2);
   ASSERT_EQ(1, resume_callback_invocations);
@@ -490,6 +492,9 @@
   ASSERT_EQ(2, resume_callback_invocations);
   helper_->Resume(save_id3);
   ASSERT_EQ(3, resume_callback_invocations);
+
+  id3->AbortDebuggerPauses();
+  id4->AbortDebuggerPauses();
 }
 
 TEST_F(AuctionV8HelperTest, AllocWrap) {
@@ -501,6 +506,9 @@
   // `id2` should be positive and distinct from `id1`.
   EXPECT_GT(id2->context_group_id(), 0);
   EXPECT_NE(id1->context_group_id(), id2->context_group_id());
+
+  id1->AbortDebuggerPauses();
+  id2->AbortDebuggerPauses();
 }
 
 TEST_F(AuctionV8HelperTest, DebuggerBasics) {
@@ -569,6 +577,8 @@
       source_response.value.FindStringPath("result.scriptSource");
   ASSERT_TRUE(parsed_src);
   EXPECT_EQ(kScriptSrc, *parsed_src);
+
+  id->AbortDebuggerPauses();
 }
 
 TEST_F(AuctionV8HelperTest, DebugCompileError) {
@@ -616,6 +626,8 @@
 
   TestChannel::Event context_destroyed_event =
       channel->WaitForMethodNotification("Runtime.executionContextDestroyed");
+
+  id->AbortDebuggerPauses();
 }
 
 TEST_F(AuctionV8HelperTest, DevToolsDebuggerBasics) {
@@ -720,6 +732,8 @@
     // Produced value changed by the write to `multiplier`.
     result_run_loop.Run();
     EXPECT_EQ(30, result);
+
+    id->AbortDebuggerPauses();
   }
 }
 
@@ -839,6 +853,8 @@
       // Wait for result.
       result_run_loop.Run();
       EXPECT_EQ(42, result);
+
+      id->AbortDebuggerPauses();
     }
   }
 }
@@ -863,6 +879,8 @@
             TestDevToolsAgentClient::Channel::kMain, 1, "NoSuchThing.enable",
             R"({"id":1,"method":"NoSuchThing.enable","params":{}})");
     EXPECT_TRUE(result.value.FindDictKey("error"));
+
+    id->AbortDebuggerPauses();
   }
 }
 
@@ -883,6 +901,7 @@
                                        use_binary_protocol);
   task_environment_.RunUntilIdle();
 
+  id->AbortDebuggerPauses();
   id.reset();
   helper_.reset();
   task_environment_.RunUntilIdle();
@@ -967,6 +986,8 @@
 
   result_run_loop.Run();
   EXPECT_EQ(3, result);
+
+  id->AbortDebuggerPauses();
 }
 
 TEST_F(AuctionV8HelperTest, DebugTimeout) {
@@ -1031,6 +1052,7 @@
 
   result_run_loop.Run();
   EXPECT_EQ(-1, result);
+  id->AbortDebuggerPauses();
 }
 
 }  // namespace auction_worklet
diff --git a/content/services/auction_worklet/bidder_worklet.cc b/content/services/auction_worklet/bidder_worklet.cc
index 680e243..26597fb 100644
--- a/content/services/auction_worklet/bidder_worklet.cc
+++ b/content/services/auction_worklet/bidder_worklet.cc
@@ -185,6 +185,8 @@
   // destroyed before the BidderWorklet itself is, but makes the class safer
   // against refactors of the Mojo API.
   FailAllPendingTasks();
+
+  debug_id_->AbortDebuggerPauses();
 }
 
 int BidderWorklet::context_group_id_for_testing() const {
diff --git a/content/services/auction_worklet/bidder_worklet_unittest.cc b/content/services/auction_worklet/bidder_worklet_unittest.cc
index 6ca17fb..bffd758c 100644
--- a/content/services/auction_worklet/bidder_worklet_unittest.cc
+++ b/content/services/auction_worklet/bidder_worklet_unittest.cc
@@ -2349,5 +2349,52 @@
   run_loop.Run();
 }
 
+TEST_F(BidderWorkletTest, UnloadWhilePaused) {
+  // Make sure things are cleaned up properly if the worklet is destroyed while
+  // paused on a breakpoint.
+  const char kUrl[] = "http://example.com/bid.js";
+
+  AddJavascriptResponse(
+      &url_loader_factory_, GURL(kUrl),
+      CreateReportWinScript(R"(sendReportTo("https://foo.test"))"));
+
+  auto worklet =
+      CreateWorklet(GURL(kUrl), /*pause_for_debugger_on_start=*/true);
+  GenerateBid(worklet.get());
+
+  mojo::Remote<blink::mojom::DevToolsAgent> agent;
+  worklet->ConnectDevToolsAgent(agent.BindNewPipeAndPassReceiver());
+
+  TestDevToolsAgentClient debug(std::move(agent), "123",
+                                /*use_binary_protocol=*/true);
+
+  debug.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 1, "Runtime.enable",
+      R"({"id":1,"method":"Runtime.enable","params":{}})");
+  debug.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 2, "Debugger.enable",
+      R"({"id":2,"method":"Debugger.enable","params":{}})");
+
+  // Set an instrumentation breakpoint to get it debugger paused.
+  debug.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 3,
+      "EventBreakpoints.setInstrumentationBreakpoint",
+      MakeInstrumentationBreakpointCommand(3, "set",
+                                           "beforeBidderWorkletBiddingStart"));
+  debug.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 4,
+      "Runtime.runIfWaitingForDebugger",
+      R"({"id":4,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
+
+  // Wait for breakpoint to hit.
+  debug.WaitForMethodNotification("Debugger.paused");
+
+  // ... and destroy the worklet
+  worklet.reset();
+
+  // This won't terminate if the V8 thread is still blocked in debugger.
+  task_environment_.RunUntilIdle();
+}
+
 }  // namespace
 }  // namespace auction_worklet
diff --git a/content/services/auction_worklet/debug_command_queue.cc b/content/services/auction_worklet/debug_command_queue.cc
index af22331..e18a9f8 100644
--- a/content/services/auction_worklet/debug_command_queue.cc
+++ b/content/services/auction_worklet/debug_command_queue.cc
@@ -8,22 +8,30 @@
 
 namespace auction_worklet {
 
-DebugCommandQueue::DebugCommandQueue()
-    : v8_runner_(base::SequencedTaskRunnerHandle::Get()), wake_up_(&lock_) {
-  // Create helper for posting RunQueue here to bind it to the weak pointer on
-  // the right thread.
-  run_queue_closure_ = base::BindRepeating(&DebugCommandQueue::RunQueue,
-                                           weak_ptr_factory_.GetWeakPtr());
-}
+DebugCommandQueue::DebugCommandQueue(
+    scoped_refptr<base::SequencedTaskRunner> v8_runner)
+    : v8_runner_(std::move(v8_runner)), wake_up_(&lock_) {}
 
 DebugCommandQueue::~DebugCommandQueue() = default;
 
-void DebugCommandQueue::PauseForDebuggerAndRunCommands() {
+void DebugCommandQueue::PauseForDebuggerAndRunCommands(
+    int context_group_id,
+    base::OnceClosure abort_helper) {
   DCHECK(v8_runner_->RunsTasksInCurrentSequence());
+  DCHECK(abort_helper);
 
   base::AutoLock auto_lock(lock_);
   CHECK(!v8_thread_paused_);
+  DCHECK(!pause_abort_helper_);
+  if (aborted_context_group_ids_.find(context_group_id) !=
+      aborted_context_group_ids_.end()) {
+    // Pauses disallowed since worklet is in process of being destroyed
+    return;
+  }
+
   v8_thread_paused_ = true;
+  paused_context_group_id_ = context_group_id;
+  pause_abort_helper_ = std::move(abort_helper);
   while (true) {
     RunQueueWithLockHeld();
     if (v8_thread_paused_)
@@ -31,6 +39,25 @@
     else
       break;
   }
+  pause_abort_helper_.Reset();
+}
+
+void DebugCommandQueue::AbortPauses(int context_group_id) {
+  base::AutoLock auto_lock(lock_);
+  aborted_context_group_ids_.insert(context_group_id);
+
+  if (v8_thread_paused_ && paused_context_group_id_ == context_group_id) {
+    DCHECK(pause_abort_helper_);
+    queue_.push(std::move(pause_abort_helper_));
+    wake_up_.Signal();
+  }
+}
+
+void DebugCommandQueue::RecycleContextGroupId(int context_group_id) {
+  base::AutoLock auto_lock(lock_);
+  size_t num_erased = aborted_context_group_ids_.erase(context_group_id);
+  DCHECK_EQ(num_erased, 1u)
+      << "DebugId::AbortDebuggerPauses must be called before ~DebugId.";
 }
 
 void DebugCommandQueue::QuitPauseForDebugger() {
@@ -54,7 +81,8 @@
 
 void DebugCommandQueue::PostRunQueue() EXCLUSIVE_LOCKS_REQUIRED(lock_) {
   if (!queue_.empty()) {
-    v8_runner_->PostTask(FROM_HERE, run_queue_closure_);
+    v8_runner_->PostTask(FROM_HERE,
+                         base::BindOnce(&DebugCommandQueue::RunQueue, this));
   }
 }
 
diff --git a/content/services/auction_worklet/debug_command_queue.h b/content/services/auction_worklet/debug_command_queue.h
index 25db9a8f..b7a64c2 100644
--- a/content/services/auction_worklet/debug_command_queue.h
+++ b/content/services/auction_worklet/debug_command_queue.h
@@ -5,9 +5,12 @@
 #ifndef CONTENT_SERVICES_AUCTION_WORKLET_DEBUG_COMMAND_QUEUE_H_
 #define CONTENT_SERVICES_AUCTION_WORKLET_DEBUG_COMMAND_QUEUE_H_
 
+#include <set>
+
 #include "base/callback.h"
 #include "base/containers/queue.h"
-#include "base/memory/weak_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
 #include "base/task/sequenced_task_runner.h"
@@ -18,20 +21,43 @@
 // DebugCommandQueue helps coordinate command transfer between Session (lives on
 // V8 thread) and IOSession (lives on mojo thread), as well as blocking
 // execution of V8 thread when paused in debugger. It's owned by the
-// AuctionV8Helper
-class DebugCommandQueue {
+// AuctionV8Helper (but may extend its own lifetime a bit to keep callbacks
+// safe).
+class DebugCommandQueue : public base::RefCountedThreadSafe<DebugCommandQueue> {
  public:
-  // Must be created and destroyed on the v8 thread.
-  DebugCommandQueue();
+  // May be created and destroyed on any thread.
+  explicit DebugCommandQueue(
+      scoped_refptr<base::SequencedTaskRunner> v8_runner);
   DebugCommandQueue(const DebugCommandQueue&) = delete;
   DebugCommandQueue& operator=(const DebugCommandQueue&) = delete;
-  ~DebugCommandQueue();
 
   // Blocks the current thread until QuitPauseForDebugger() is called, executing
   // only things added via Post().
   //
+  // If AbortPauses(context_group_id) has been called, exits immediately.
+  //
+  // `abort_helper` should be a closure that, when called on the v8 thread, will
+  // eventually lead to QuitPauseForDebugger being called.
+  //
   // Called on v8 thread only.
-  void PauseForDebuggerAndRunCommands();
+  void PauseForDebuggerAndRunCommands(
+      int context_group_id,
+      base::OnceClosure abort_helper = base::OnceClosure());
+
+  // If the v8 thread is within PauseForDebuggerAndRunCommands() the
+  // `abort_helper` passed to the method will be queued for execution.
+  //
+  // Otherwise, marks `context_group_id` as requiring
+  // PauseForDebuggerAndRunCommands to exit immediately.
+  //
+  // Can be called from any thread.
+  void AbortPauses(int context_group_id);
+
+  // Notes that the meaning of `context_group_id` has changed, and so any
+  // previous calls to AbortPauses() for given value should no longer apply.
+  //
+  // Can be called from any thread.
+  void RecycleContextGroupId(int context_group_id);
 
   // Requests exit from PauseForDebuggerAndRunCommands().
   //
@@ -49,6 +75,10 @@
   void QueueTaskForV8Thread(base::OnceClosure task);
 
  private:
+  friend class base::RefCountedThreadSafe<DebugCommandQueue>;
+
+  ~DebugCommandQueue();
+
   void PostRunQueue() EXCLUSIVE_LOCKS_REQUIRED(lock_);
   void RunQueue();
   void RunQueueWithLockHeld() EXCLUSIVE_LOCKS_REQUIRED(lock_);
@@ -58,10 +88,11 @@
   base::Lock lock_;
   base::ConditionVariable wake_up_ GUARDED_BY(lock_);
   base::queue<base::OnceClosure> queue_ GUARDED_BY(lock_);
-  bool v8_thread_paused_ GUARDED_BY(lock_) = false;
+  base::OnceClosure pause_abort_helper_ GUARDED_BY(lock_);
 
-  base::RepeatingClosure run_queue_closure_;
-  base::WeakPtrFactory<DebugCommandQueue> weak_ptr_factory_{this};
+  bool v8_thread_paused_ GUARDED_BY(lock_) = false;
+  int paused_context_group_id_ GUARDED_BY(lock_);
+  std::set<int> aborted_context_group_ids_ GUARDED_BY(lock_);
 };
 
 }  // namespace auction_worklet
diff --git a/content/services/auction_worklet/debug_command_queue_unittest.cc b/content/services/auction_worklet/debug_command_queue_unittest.cc
index 61c0289..b3bfe7b9 100644
--- a/content/services/auction_worklet/debug_command_queue_unittest.cc
+++ b/content/services/auction_worklet/debug_command_queue_unittest.cc
@@ -8,7 +8,9 @@
 #include <vector>
 
 #include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
 #include "base/task/sequenced_task_runner.h"
+#include "base/test/bind.h"
 #include "base/test/task_environment.h"
 #include "base/thread_annotations.h"
 #include "base/threading/sequenced_task_runner_handle.h"
@@ -22,40 +24,23 @@
 
 class DebugCommandQueueTest : public testing::Test {
  public:
+  static const int kId = 4;
+
   DebugCommandQueueTest()
       : v8_runner_(AuctionV8Helper::CreateTaskRunner()),
-        command_queue_(nullptr, base::OnTaskRunnerDeleter(nullptr)) {
-    base::RunLoop run_loop;
-    // Create `DebugCommandQueue on `v8_runner_`.
-    v8_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(
-            [](std::unique_ptr<DebugCommandQueue, base::OnTaskRunnerDeleter>*
-                   out,
-               base::OnceClosure done) {
-              *out =
-                  std::unique_ptr<DebugCommandQueue, base::OnTaskRunnerDeleter>(
-                      new DebugCommandQueue,
-                      base::OnTaskRunnerDeleter(
-                          base::SequencedTaskRunnerHandle::Get()));
-
-              std::move(done).Run();
-            },
-            &command_queue_, run_loop.QuitClosure()));
-    run_loop.Run();
-  }
+        command_queue_(base::MakeRefCounted<DebugCommandQueue>(v8_runner_)) {}
 
   void QueueFromV8ThreadAndWait(base::OnceClosure to_post) {
     base::RunLoop run_loop;
     v8_runner_->PostTask(
         FROM_HERE,
         base::BindOnce(
-            [](DebugCommandQueue* queue, base::OnceClosure to_post,
-               base::OnceClosure done) {
+            [](scoped_refptr<DebugCommandQueue> queue,
+               base::OnceClosure to_post, base::OnceClosure done) {
               queue->QueueTaskForV8Thread(std::move(to_post));
               std::move(done).Run();
             },
-            command_queue_.get(), std::move(to_post), run_loop.QuitClosure()));
+            command_queue_, std::move(to_post), run_loop.QuitClosure()));
     run_loop.Run();
   }
 
@@ -70,10 +55,16 @@
                           std::move(msg));
   }
 
-  base::OnceClosure PauseForDebuggerAndRunCommands() {
+  base::OnceClosure PauseForDebuggerAndRunCommands(
+      base::OnceClosure abort_helper) {
     return base::BindOnce(
         &DebugCommandQueueTest::DoPauseForDebuggerAndRunCommands,
-        base::Unretained(this));
+        base::Unretained(this), std::move(abort_helper));
+  }
+
+  base::OnceClosure ShouldNotUseAbortHelper() {
+    return base::BindOnce(
+        []() { ADD_FAILURE() << "Abort helper shouldn't get used here"; });
   }
 
   base::OnceClosure QuitPauseForDebugger() {
@@ -88,9 +79,10 @@
     log_.push_back(std::move(message));
   }
 
-  void DoPauseForDebuggerAndRunCommands() {
+  void DoPauseForDebuggerAndRunCommands(base::OnceClosure abort_helper) {
     DoLog("Pause start");
-    command_queue_->PauseForDebuggerAndRunCommands();
+    command_queue_->PauseForDebuggerAndRunCommands(kId,
+                                                   std::move(abort_helper));
     DoLog("Pause end");
   }
 
@@ -101,7 +93,7 @@
 
   base::test::TaskEnvironment task_environment_;
   scoped_refptr<base::SingleThreadTaskRunner> v8_runner_;
-  std::unique_ptr<DebugCommandQueue, base::OnTaskRunnerDeleter> command_queue_;
+  scoped_refptr<DebugCommandQueue> command_queue_;
   std::vector<std::string> log_ GUARDED_BY(lock_);
   base::Lock lock_;
 };
@@ -121,7 +113,8 @@
   base::RunLoop run_loop;
   command_queue_->QueueTaskForV8Thread(LogString("1"));
   command_queue_->QueueTaskForV8Thread(LogString("2"));
-  command_queue_->QueueTaskForV8Thread(PauseForDebuggerAndRunCommands());
+  command_queue_->QueueTaskForV8Thread(
+      PauseForDebuggerAndRunCommands(ShouldNotUseAbortHelper()));
   command_queue_->QueueTaskForV8Thread(LogString("3"));
   command_queue_->QueueTaskForV8Thread(LogString("4"));
   command_queue_->QueueTaskForV8Thread(QuitPauseForDebugger());
@@ -153,7 +146,7 @@
   // A task that itself queues more tasks.
   base::RunLoop run_loop;
   command_queue_->QueueTaskForV8Thread(base::BindOnce(
-      [](DebugCommandQueue* command_queue, base::OnceClosure log1,
+      [](scoped_refptr<DebugCommandQueue> command_queue, base::OnceClosure log1,
          base::OnceClosure log2, base::OnceClosure log3,
          base::OnceClosure quit_closure) {
         std::move(log1).Run();
@@ -161,7 +154,7 @@
         command_queue->QueueTaskForV8Thread(std::move(log3));
         command_queue->QueueTaskForV8Thread(std::move(quit_closure));
       },
-      command_queue_.get(), LogString("1"), LogString("2"), LogString("3"),
+      command_queue_, LogString("1"), LogString("2"), LogString("3"),
       run_loop.QuitClosure()));
   run_loop.Run();
   EXPECT_THAT(TakeLog(), ElementsAre("1", "2", "3"));
@@ -171,9 +164,10 @@
   // A task run from within PauseForDebuggerAndRunCommands() that itself queues
   // more tasks.
   base::RunLoop run_loop;
-  command_queue_->QueueTaskForV8Thread(PauseForDebuggerAndRunCommands());
+  command_queue_->QueueTaskForV8Thread(
+      PauseForDebuggerAndRunCommands(ShouldNotUseAbortHelper()));
   command_queue_->QueueTaskForV8Thread(base::BindOnce(
-      [](DebugCommandQueue* command_queue, base::OnceClosure log1,
+      [](scoped_refptr<DebugCommandQueue> command_queue, base::OnceClosure log1,
          base::OnceClosure log2, base::OnceClosure log3,
          base::OnceClosure quit_closure) {
         std::move(log1).Run();
@@ -181,7 +175,7 @@
         command_queue->QueueTaskForV8Thread(std::move(log3));
         command_queue->QueueTaskForV8Thread(std::move(quit_closure));
       },
-      command_queue_.get(), LogString("1"), LogString("2"), LogString("3"),
+      command_queue_, LogString("1"), LogString("2"), LogString("3"),
       run_loop.QuitClosure()));
   run_loop.Run();
 
@@ -194,4 +188,70 @@
                                      "Requested pause end", "Pause end"));
 }
 
+TEST_F(DebugCommandQueueTest, AbortPausesBeforePause) {
+  // Check effect of AbortPauses before pause was even request.
+  command_queue_->AbortPauses(kId);
+
+  command_queue_->QueueTaskForV8Thread(
+      PauseForDebuggerAndRunCommands(LogString("Should not happen")));
+
+  command_queue_->QueueTaskForV8Thread(LogString("1"));
+
+  // Second attempt to pause should also be cancelled.
+  command_queue_->QueueTaskForV8Thread(
+      PauseForDebuggerAndRunCommands(LogString("Nor this")));
+
+  command_queue_->QueueTaskForV8Thread(LogString("2"));
+
+  // Wait for other thread to finish all work.
+  task_environment_.RunUntilIdle();
+
+  EXPECT_THAT(TakeLog(), ElementsAre("Pause start", "Pause end", "1",
+                                     "Pause start", "Pause end", "2"));
+
+  // Now unblock kId, ask to abort pauses for a different one.
+  command_queue_->RecycleContextGroupId(kId);
+  command_queue_->AbortPauses(kId + 1);
+
+  // This pause should happen.
+  base::RunLoop run_loop;
+  command_queue_->QueueTaskForV8Thread(
+      PauseForDebuggerAndRunCommands(LogString("Nope")));
+  command_queue_->QueueTaskForV8Thread(LogString("3"));
+  command_queue_->QueueTaskForV8Thread(QuitPauseForDebugger());
+  command_queue_->QueueTaskForV8Thread(run_loop.QuitClosure());
+  run_loop.Run();
+  EXPECT_THAT(TakeLog(), ElementsAre("Pause start", "3", "Requested pause end",
+                                     "Pause end"));
+}
+
+TEST_F(DebugCommandQueueTest, AbortPausesAfterPause) {
+  // Make sure that AbortPauses happening after pause happened with same ID
+  // actually aborts it.
+
+  base::WaitableEvent pause_happened;
+  command_queue_->QueueTaskForV8Thread(
+      PauseForDebuggerAndRunCommands(QuitPauseForDebugger()));
+  command_queue_->QueueTaskForV8Thread(LogString("1"));
+
+  // Make sure we're actually paused.
+  command_queue_->QueueTaskForV8Thread(
+      base::BindLambdaForTesting([&]() { pause_happened.Signal(); }));
+  pause_happened.Wait();
+
+  // Request exit of a different ID.
+  command_queue_->AbortPauses(kId + 1);
+  command_queue_->QueueTaskForV8Thread(LogString("2"));
+
+  // And then right one.
+  command_queue_->AbortPauses(kId);
+  command_queue_->QueueTaskForV8Thread(LogString("3"));
+
+  // Make sure the thread is unwedged.
+  task_environment_.RunUntilIdle();
+
+  EXPECT_THAT(TakeLog(), ElementsAre("Pause start", "1", "2",
+                                     "Requested pause end", "Pause end", "3"));
+}
+
 }  // namespace auction_worklet
diff --git a/content/services/auction_worklet/seller_worklet.cc b/content/services/auction_worklet/seller_worklet.cc
index 22ab312..5cada0c 100644
--- a/content/services/auction_worklet/seller_worklet.cc
+++ b/content/services/auction_worklet/seller_worklet.cc
@@ -150,6 +150,7 @@
     std::move(load_worklet_callback_)
         .Run(false /* success */, std::vector<std::string>() /* errors */);
   }
+  debug_id_->AbortDebuggerPauses();
 }
 
 int SellerWorklet::context_group_id_for_testing() const {
diff --git a/content/services/auction_worklet/seller_worklet.h b/content/services/auction_worklet/seller_worklet.h
index 3f3eae4..c1bd9c5d 100644
--- a/content/services/auction_worklet/seller_worklet.h
+++ b/content/services/auction_worklet/seller_worklet.h
@@ -156,7 +156,6 @@
       std::vector<std::string> errors);
 
   scoped_refptr<base::SequencedTaskRunner> v8_runner_;
-
   scoped_refptr<AuctionV8Helper> v8_helper_;
   scoped_refptr<AuctionV8Helper::DebugId> debug_id_;
 
diff --git a/content/services/auction_worklet/seller_worklet_unittest.cc b/content/services/auction_worklet/seller_worklet_unittest.cc
index c7cdf5d0..29a47a8 100644
--- a/content/services/auction_worklet/seller_worklet_unittest.cc
+++ b/content/services/auction_worklet/seller_worklet_unittest.cc
@@ -1285,5 +1285,61 @@
   run_loop3.Run();
 }
 
+TEST_F(SellerWorkletTest, UnloadWhilePaused) {
+  // Make sure things are cleaned up properly if the worklet is destroyed while
+  // paused on a breakpoint.
+  const char kUrl[] = "http://example.com/script.js";
+
+  std::string script_body =
+      CreateBasicSellAdScript() +
+      CreateReportToScript("1", R"(sendReportTo("https://foo.test"))");
+  AddJavascriptResponse(&url_loader_factory_, GURL(kUrl), script_body);
+
+  auto worklet =
+      CreateWorkletImpl(GURL(kUrl), /* pause_for_debugger_on_start= */ true);
+
+  mojo::Remote<blink::mojom::DevToolsAgent> agent;
+  worklet->ConnectDevToolsAgent(agent.BindNewPipeAndPassReceiver());
+
+  TestDevToolsAgentClient debug(std::move(agent), "123",
+                                /*use_binary_protocol=*/true);
+
+  debug.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 1, "Runtime.enable",
+      R"({"id":1,"method":"Runtime.enable","params":{}})");
+  debug.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 2, "Debugger.enable",
+      R"({"id":2,"method":"Debugger.enable","params":{}})");
+
+  // Set the instrumentation breakpoint.
+  debug.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 3,
+      "EventBreakpoints.setInstrumentationBreakpoint",
+      MakeInstrumentationBreakpointCommand(3, "set",
+                                           "beforeSellerWorkletScoringStart"));
+  // Resume execution of create.
+  load_script_run_loop_ = std::make_unique<base::RunLoop>();
+  debug.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 4,
+      "Runtime.runIfWaitingForDebugger",
+      R"({"id":4,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
+  load_script_run_loop_->Run();
+  EXPECT_TRUE(create_worklet_succeeded_);
+
+  // Try to run scoreAd. Should hit corresponding breakpoint.
+  RunScoreAdOnWorkletAsync(worklet.get(), 1.0, {}, base::BindOnce([]() {
+                             ADD_FAILURE()
+                                 << "scoreAd shouldn't actually get to finish.";
+                           }));
+
+  debug.WaitForMethodNotification("Debugger.paused");
+
+  // Destroy the worklet
+  worklet.reset();
+
+  // This won't terminate if the V8 thread is still blocked in debugger.
+  task_environment_.RunUntilIdle();
+}
+
 }  // namespace
 }  // namespace auction_worklet
diff --git a/content/services/auction_worklet/worklet_loader_unittest.cc b/content/services/auction_worklet/worklet_loader_unittest.cc
index 85de8de..effad57 100644
--- a/content/services/auction_worklet/worklet_loader_unittest.cc
+++ b/content/services/auction_worklet/worklet_loader_unittest.cc
@@ -112,6 +112,8 @@
   run_loop_.Run();
   EXPECT_FALSE(load_succeeded_);
   channel->WaitForMethodNotification("Debugger.scriptFailedToParse");
+
+  id->AbortDebuggerPauses();
 }
 
 TEST_F(WorkletLoaderTest, Success) {
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 432330f..b418f5e 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1084,6 +1084,7 @@
     "../browser/attribution_reporting/trigger_registration_browsertest.cc",
     "../browser/back_forward_cache_browsertest.cc",
     "../browser/back_forward_cache_browsertest.h",
+    "../browser/back_forward_cache_basics_browsertest.cc",
     "../browser/back_forward_cache_features_browsertest.cc",
     "../browser/back_forward_cache_internal_browsertest.cc",
     "../browser/back_forward_cache_network_request_browsertest.cc",
@@ -2610,8 +2611,10 @@
         "//third_party/libyuv",
         "//third_party/webrtc_overrides:webrtc_component",
       ]
-      sources +=
-          [ "../browser/media/capture/desktop_capture_device_unittest.cc" ]
+      sources += [
+        "../browser/media/capture/desktop_capture_device_unittest.cc",
+        "../browser/renderer_host/media/crop_id_web_contents_helper_unittest.cc",
+      ]
     }
   }
 
diff --git a/content/test/data/accessibility/css/marker-crash-expected-blink.txt b/content/test/data/accessibility/css/marker-crash-expected-blink.txt
index 5e555ab..b7b0263 100644
--- a/content/test/data/accessibility/css/marker-crash-expected-blink.txt
+++ b/content/test/data/accessibility/css/marker-crash-expected-blink.txt
@@ -3,5 +3,6 @@
 ++++genericContainer ignored
 ++++++group
 ++++++++listMarker name='%E2%80%A2 '
+++++++++++staticText ignored name='%E2%80%A2 '
 ++++++genericContainer ignored
 ++++++++genericContainer ignored
diff --git a/content/test/data/accessibility/css/marker-crash-without-layout-ng-block-frag-expected-blink.txt b/content/test/data/accessibility/css/marker-crash-without-layout-ng-block-frag-expected-blink.txt
new file mode 100644
index 0000000..5e555ab
--- /dev/null
+++ b/content/test/data/accessibility/css/marker-crash-without-layout-ng-block-frag-expected-blink.txt
@@ -0,0 +1,7 @@
+rootWebArea
+++genericContainer ignored
+++++genericContainer ignored
+++++++group
+++++++++listMarker name='%E2%80%A2 '
+++++++genericContainer ignored
+++++++++genericContainer ignored
diff --git a/content/test/data/accessibility/css/marker-crash-without-layout-ng-block-frag.html b/content/test/data/accessibility/css/marker-crash-without-layout-ng-block-frag.html
new file mode 100644
index 0000000..259ccac
--- /dev/null
+++ b/content/test/data/accessibility/css/marker-crash-without-layout-ng-block-frag.html
@@ -0,0 +1,7 @@
+<!-- Avoid a crash caused by adding pseudo element content in two places.
+     See AXNodeObject::CanAddLayoutChild(). https://crbug.com/1172038 -->
+<style>
+span:before { display: inherit; content: ""; -webkit-column-count: 1; }
+</style>
+<span role="group" style="display: list-item"></span>
+<span class="empty"></span>
diff --git a/content/test/data/accessibility/html/p-expected-blink.txt b/content/test/data/accessibility/html/p-expected-blink.txt
index be2268d..0a22052 100644
--- a/content/test/data/accessibility/html/p-expected-blink.txt
+++ b/content/test/data/accessibility/html/p-expected-blink.txt
@@ -1,10 +1,10 @@
-rootWebArea
-++genericContainer ignored
-++++genericContainer ignored
-++++++staticText name='Before'
+rootWebArea wordStarts=0 wordEnds=20
+++genericContainer ignored wordStarts=0 wordEnds=20
+++++genericContainer ignored wordStarts=0 wordEnds=20
+++++++staticText name='Before' wordStarts=0 wordEnds=6
 ++++++++inlineTextBox name='Before' wordStarts=0 wordEnds=6
-++++++paragraph
-++++++++staticText name='Paragraph'
+++++++paragraph wordStarts=0 wordEnds=9
+++++++++staticText name='Paragraph' wordStarts=0 wordEnds=9
 ++++++++++inlineTextBox name='Paragraph' wordStarts=0 wordEnds=9
-++++++staticText name='After'
+++++++staticText name='After' wordStarts=0 wordEnds=5
 ++++++++inlineTextBox name='After' wordStarts=0 wordEnds=5
diff --git a/content/test/data/accessibility/mac/attributes/ax-required-expected.txt b/content/test/data/accessibility/mac/attributes/ax-required-expected.txt
new file mode 100644
index 0000000..8bb3a0f
--- /dev/null
+++ b/content/test/data/accessibility/mac/attributes/ax-required-expected.txt
@@ -0,0 +1,10 @@
+input.AXRequired=0
+input_required.AXRequired=1
+input_aria_required.AXRequired=0
+input_aria_required_true.AXRequired=1
+input_aria_required_false.AXRequired=0
+combobox.AXRequired=n/a
+combobox_aria_required_true.AXRequired=n/a
+combobox_aria_required_false.AXRequired=n/a
+not_applicable.AXRequired=n/a
+not_applicable_aria.AXRequired=n/a
diff --git a/content/test/data/accessibility/mac/attributes/ax-required.html b/content/test/data/accessibility/mac/attributes/ax-required.html
new file mode 100644
index 0000000..e81b467d
--- /dev/null
+++ b/content/test/data/accessibility/mac/attributes/ax-required.html
@@ -0,0 +1,24 @@
+<!--
+@SCRIPT:
+  input.AXRequired
+  input_required.AXRequired
+  input_aria_required.AXRequired
+  input_aria_required_true.AXRequired
+  input_aria_required_false.AXRequired
+  combobox.AXRequired
+  combobox_aria_required_true.AXRequired
+  combobox_aria_required_false.AXRequired
+  not_applicable.AXRequired
+  not_applicable_aria.AXRequired
+-->
+<!DOCTYPE html>
+<input id="input">
+<input id="input_required" required>
+<input id="input_aria_required" aria-required>
+<input id="input_aria_required_true" aria-required="true">
+<input id="input_aria_required_false" aria-required="false">
+<div id="combobox" role="combobox">
+<div id="combobox_aria_required_true" role="combobox" aria-required="true">
+<div id="combobox_aria_required_false" role="combobox" aria-required="false">
+<div id="not_applicable" required>
+<div id="not_applicable_aria" aria-required="true">
diff --git a/content/test/data/android/fenced_frames/title1.html b/content/test/data/android/fenced_frames/title1.html
new file mode 100644
index 0000000..d930ea6
--- /dev/null
+++ b/content/test/data/android/fenced_frames/title1.html
@@ -0,0 +1,5 @@
+<html>
+<head></head>
+<body>This page has no title.</body>
+</html>
+
diff --git a/content/test/data/android/fenced_frames/title1.html.mock-http-headers b/content/test/data/android/fenced_frames/title1.html.mock-http-headers
new file mode 100644
index 0000000..27f34d2
--- /dev/null
+++ b/content/test/data/android/fenced_frames/title1.html.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Supports-Loading-Mode: fenced-frame
diff --git a/content/test/data/fenced_frames/basic.html.mock-http-headers b/content/test/data/fenced_frames/basic.html.mock-http-headers
new file mode 100644
index 0000000..263e89c4
--- /dev/null
+++ b/content/test/data/fenced_frames/basic.html.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Supports-Loading-Mode: fenced-frame
\ No newline at end of file
diff --git a/chrome/renderer/resources/default_300_percent/DELETE_ME b/content/test/data/fenced_frames/empty.html
similarity index 100%
rename from chrome/renderer/resources/default_300_percent/DELETE_ME
rename to content/test/data/fenced_frames/empty.html
diff --git a/content/test/data/fenced_frames/empty.html.mock-http-headers b/content/test/data/fenced_frames/empty.html.mock-http-headers
new file mode 100644
index 0000000..263e89c4
--- /dev/null
+++ b/content/test/data/fenced_frames/empty.html.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Supports-Loading-Mode: fenced-frame
\ No newline at end of file
diff --git a/content/test/data/gpu/pixel_webgpu_import_video_frame.html b/content/test/data/gpu/pixel_webgpu_import_video_frame.html
new file mode 100644
index 0000000..f3b432a
--- /dev/null
+++ b/content/test/data/gpu/pixel_webgpu_import_video_frame.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>WebGPU importExternalTexture videoFrame test</title>
+  <style type="text/css">
+  .nomargin {
+    margin: 0px auto;
+  }
+  </style>
+  <script type="text/javascript" src="pixel_webgpu_util.js"></script>
+  <script type="text/javascript" src="webcodecs/webcodecs_common.js"></script>
+  <script type="text/javascript">
+    var g_swapsBeforeAck = 15;
+
+    async function main() {
+      let cnv = document.getElementById('canvas_2d');
+      let ctx = cnv.getContext('2d');
+      const gpuCanvas = document.getElementById('canvas_webgpu');
+      const [gpuDevice, gpuContext] = await webGpuUtils.init(gpuCanvas);
+
+      if (!gpuDevice || !gpuContext) {
+        console.error("Failed to initialize WebGPU - skipping test");
+        domAutomationController.send("FAILURE");
+        return;
+      }
+
+      let source = await createFrameSource("hw_decoder", cnv.width, cnv.height);
+      if (!source) {
+        console.error("Cannot get valid video frame - skipping test");
+        domAutomationController.send("FAILURE");
+        return;
+      }
+
+      let frame = await source.getNextFrame();
+      ctx.drawImage(frame, 0, 0, cnv.width, cnv.height);
+
+      const renderCallback = function() {
+        webGpuUtils.importExternalTextureTest(gpuDevice, gpuContext, frame);
+        waitForFinish();
+      };
+
+      window.requestAnimationFrame(renderCallback);
+    }
+
+    function waitForFinish() {
+      if (g_swapsBeforeAck == 0) {
+        frame.close();
+        domAutomationController.send("SUCCESS");
+      } else {
+        g_swapsBeforeAck--;
+        window.requestAnimationFrame(waitForFinish);
+      }
+    }
+  </script>
+</head>
+<body onload="main()">
+  <canvas id="canvas_2d" width="200" height="200" class="nomargin"></canvas>
+  <canvas id="canvas_webgpu" width="200" height="200" class="nomargin"></canvas>
+</body>
+</html>
diff --git a/content/test/data/gpu/pixel_webgpu_util.js b/content/test/data/gpu/pixel_webgpu_util.js
index cc84961a..d3885f4b 100644
--- a/content/test/data/gpu/pixel_webgpu_util.js
+++ b/content/test/data/gpu/pixel_webgpu_util.js
@@ -49,6 +49,16 @@
   return vec4<f32>(1.0, 1.0, 1.0, 1.0);
 }
 `,
+
+    fragmentImport: `
+[[binding(0), group(0)]] var mySampler: sampler;
+[[binding(1), group(0)]] var myTexture: texture_external;
+
+[[stage(fragment)]]
+fn main([[location(0)]] fragUV : vec2<f32>) -> [[location(0)]] vec4<f32> {
+  return textureSampleLevel(myTexture, mySampler, fragUV);
+}
+`,
   };
 
   return {
@@ -80,6 +90,74 @@
       return [device, context];
     },
 
+    importExternalTextureTest: function(
+      device, context, video) {
+        const blitPipeline = device.createRenderPipeline({
+          vertex: {
+            module: device.createShaderModule({
+              code: wgslShaders.vertex,
+            }),
+            entryPoint: 'main',
+          },
+          fragment: {
+            module: device.createShaderModule({
+              code: wgslShaders.fragmentImport,
+            }),
+            entryPoint: 'main',
+            targets: [
+              {
+                format: outputFormat,
+              },
+            ],
+          },
+          primitive: {
+            topology: 'triangle-strip',
+            stripIndexFormat: 'uint16',
+          },
+        });
+
+        const sampler = device.createSampler({
+          magFilter: 'linear',
+          minFilter: 'linear',
+        });
+        const externalTextureDescriptor = { source: video };
+        const externalTexture =
+            device.importExternalTexture(externalTextureDescriptor);
+
+        const bindGroup = device.createBindGroup({
+          layout: blitPipeline.getBindGroupLayout(0),
+          entries: [
+            {
+              binding: 0,
+              resource: sampler,
+            },
+            {
+              binding: 1,
+              resource: externalTexture,
+            },
+          ],
+        });
+
+        const renderPassDescriptor = {
+          colorAttachments: [
+            {
+              view: context.getCurrentTexture().createView(),
+              loadValue: {r: 0.0, g: 0.0, b: 0.0, a: 1.0},
+            },
+          ],
+        };
+
+        const commandEncoder = device.createCommandEncoder();
+        const passEncoder =
+            commandEncoder.beginRenderPass(renderPassDescriptor);
+        passEncoder.setPipeline(blitPipeline);
+        passEncoder.setBindGroup(0, bindGroup);
+        passEncoder.draw(4, 1, 0, 0);
+        passEncoder.endPass();
+
+        device.queue.submit([commandEncoder.finish()]);
+    },
+
     uploadToGPUTextureTest: function(
       device, context, canvasImageSource, options) {
       const blitPipeline = device.createRenderPipeline({
diff --git a/content/test/data/gpu/webcodecs/encode-color-space.html b/content/test/data/gpu/webcodecs/encode-color-space.html
new file mode 100644
index 0000000..c5aa3fd
--- /dev/null
+++ b/content/test/data/gpu/webcodecs/encode-color-space.html
@@ -0,0 +1,172 @@
+<!DOCTYPE html>
+<!--
+Encodes two RGB frames and checks that output color space is changed to Rec601.
+Then encodes two I420 frame w/ Rec709 colors and checks that the output color
+space is changed to Rec709, and that a key frame is generated alongside the
+change.
+
+The spec doesn't mandate any particular output color space, so this just checks
+that our internal behvaior is surfaced correctly. A key frame is expected when
+color space changes to mirror the our decoder requirement to provide a key frame
+whenever VideoDecoderConfig changes.
+-->
+<html>
+
+<head>
+  <title>Encode color space test</title>
+  <script src="webcodecs_common.js"></script>
+  <script type="text/javascript">
+    'use strict';
+
+    // Use 16x16 aligned resolution since some platforms require that.
+    // See https://crbug.com/1084702.
+    // Also, some platforms require a resolution that isn't tiny (e.g. 160) to
+    // use hardware acceleration.
+    const FRAME_WIDTH = 640;
+    const FRAME_HEIGHT = 480;
+
+    function isRec709(colorSpace) {
+      return colorSpace.primaries === 'bt709'
+        && colorSpace.transfer === 'bt709'
+        && colorSpace.matrix === 'bt709'
+        && colorSpace.fullRange === false;
+    }
+
+    function isSRGB(colorSpace) {
+      return colorSpace.primaries === 'bt709'
+        && colorSpace.transfer === 'iec61966-2-1'
+        && colorSpace.matrix === 'rgb'
+        && colorSpace.fullRange === true;
+    }
+
+    function isRec601(colorSpace) {
+      return colorSpace.primaries === 'smpte170m'
+        && colorSpace.transfer === 'smpte170m'
+        && colorSpace.matrix === 'smpte170m'
+        && colorSpace.fullRange === false;
+    }
+
+    function makePixelArray(byteLength) {
+      let data = new Uint8Array(byteLength);
+      for (let i = 0; i < byteLength; i++) {
+        data[i] = i;
+      }
+      return data;
+    }
+
+    function makeFrame(type, timestamp) {
+      let init = {
+        format: 'RGBA',
+        timestamp: timestamp,
+        codedWidth: FRAME_WIDTH,
+        codedHeight: FRAME_HEIGHT
+      };
+      switch (type) {
+        case 'I420': {
+          const yuvByteLength = 1.5 * FRAME_WIDTH * FRAME_HEIGHT;
+          let data = makePixelArray(yuvByteLength);
+          return new VideoFrame(data, {...init, format: 'I420'});
+        }
+        case 'RGBA': {
+          const rgbaByteLength = 4 * FRAME_WIDTH * FRAME_HEIGHT;
+          let data = makePixelArray(rgbaByteLength);
+          return new VideoFrame(data, {...init, format: 'RGBA'});
+        }
+      }
+    }
+
+    async function main(arg) {
+      const encoderConfig = {
+        codec: arg.codec,
+        hardwareAcceleration: arg.acceleration,
+        width: FRAME_WIDTH,
+        height: FRAME_HEIGHT,
+      };
+
+      let support = await VideoEncoder.isConfigSupported(encoderConfig);
+      if (!support.supported) {
+        TEST.log('Skipping unsupported codec: ' + arg.codec);
+        return;
+      }
+
+      const frameDuration = 16666;
+      let inputFrames = [makeFrame('RGBA', 0 * frameDuration),
+                         makeFrame('RGBA', 1 * frameDuration),
+                         makeFrame('I420', 2 * frameDuration),
+                         makeFrame('I420', 3 * frameDuration)];
+      let outputChunks = [];
+      let outputMetadatas = [];
+      let errors = 0;
+
+      const init = {
+        output(chunk, metadata) {
+          outputChunks.push(chunk);
+          outputMetadatas.push(metadata);
+        },
+        error(e) {
+          errors++;
+          TEST.log(e);
+        }
+      };
+
+      let encoder = new VideoEncoder(init);
+      encoder.configure(encoderConfig);
+
+      for (let frame of inputFrames) {
+        encoder.encode(frame);
+        await waitForNextFrame();
+      }
+      await encoder.flush();
+      encoder.close();
+
+      TEST.assert(errors == 0, 'Encoding errors occurred during the test');
+      TEST.assert(outputChunks.length == 4, 'Unexpected number of outputs');
+      TEST.assert(outputMetadatas.length == 4, 'Unexpected number of output metadatas');
+
+      // First output should be a key frame and have acompanying metadata.
+      // Corresponding input RGBA sRGB, so we expect encoder will have used
+      // libYUV to convert to I420 rec601.
+      TEST.assert(inputFrames[0].format == 'RGBA', 'inputs[0] is RGBA');
+      TEST.assert(isSRGB(inputFrames[0].colorSpace), 'inputs[0] is sRGB');
+      TEST.assert(outputChunks[0].type == 'key', 'outputs[0] is key');
+      TEST.assert('decoderConfig' in outputMetadatas[0], 'metdatas[0] has decoderConfig');
+      TEST.assert(isRec601(outputMetadatas[0].decoderConfig.colorSpace), 'metdatas[0] is rec601');
+
+      // Second outupt may or may not be a key frame w/ metadata (up to
+      // encoder). Corresponding input is still RGBA sRGB, so if metadata is
+      // given, we expect same colorSpace as for the previous frame.
+      TEST.assert(inputFrames[1].format == 'RGBA', 'inputs[1] is RGBA');
+      TEST.assert(isSRGB(inputFrames[1].colorSpace), 'inputs[1] is sRGB');
+      if('decoderConfig' in outputMetadatas[1]) {
+        TEST.assert(isRec601(outputMetadatas[1].decoderConfig.colorSpace), 'metdatas[1] is rec601');
+      }
+
+      // Third output should be a key frame and have acompanying metadata
+      // because the correpsonding input format changed to I420, which means
+      // we passthrough without libYUV conversion and a new decoderConfig
+      // should reflect that.
+      TEST.assert(inputFrames[2].format == 'I420', 'inputs[2] is I420');
+      TEST.assert(isRec709(inputFrames[2].colorSpace), 'inputs[2] is rec709');
+      // TODO(https://crbug.com/1241448): Uncomment the line below once android
+      // reliably produces a key frame at the appropriate time. For now this
+      // is covered by a DCHECK (excluding android) in video_encoder.cc.
+      // TEST.assert(outputChunks[2].type == 'key', 'outputs[2] is key');
+      TEST.assert('decoderConfig' in outputMetadatas[2], 'metadatas[2] has decoderConfig');
+      TEST.assert(isRec709(outputMetadatas[2].decoderConfig.colorSpace), 'metadatas[2] is rec709');
+
+      // Fourth outupt may or may not be a key frame w/ metadata (up to
+      // encoder). Corresponding input is still I420 rec709, so if metadata is
+      // given, we expect same colorSpace as for the previous frame.
+      TEST.assert(inputFrames[3].format == 'I420', 'inputs[3] is I420');
+      TEST.assert(isRec709(inputFrames[3].colorSpace, 'inputs[3] is rec709'));
+      if('decoderConfig' in outputMetadatas[3]) {
+        TEST.assert(isRec709(outputMetadatas[3].decoderConfig.colorSpace), 'metadatas[3] is rec709');
+      }
+    }
+  </script>
+</head>
+
+<body>
+</body>
+
+</html>
diff --git a/content/test/data/site_isolation/appcached_cross_origin_resource.html b/content/test/data/site_isolation/appcached_cross_origin_resource.html
deleted file mode 100644
index 22eab3c..0000000
--- a/content/test/data/site_isolation/appcached_cross_origin_resource.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<html manifest="appcached_cross_origin_resource.manifest">
-<head>
-  <title>OK</title>
-  <script type="text/javascript">
-    window.applicationCache.addEventListener('cached', onCachedEvent, false);
-
-    function onCachedEvent() {
-      window.document.title = "AppCache updated";
-    }
-
-    function onLoad() {
-      window.applicationCache.addEventListener('cached', onCachedEvent, false);
-    }
-  </script>
-</head>
-
-<body onload="onLoad()">
-  Basic AppCache test. The manifest for this page is specified in the
-  appcached_cross_origin_resource.manifest file. The title of the page is set
-  to AppCache updated if the cache is successfully updated.
-</body>
-</html>
diff --git a/content/test/data/site_isolation/appcached_cross_origin_resource.manifest b/content/test/data/site_isolation/appcached_cross_origin_resource.manifest
deleted file mode 100644
index 49b8aa6..0000000
--- a/content/test/data/site_isolation/appcached_cross_origin_resource.manifest
+++ /dev/null
@@ -1,5 +0,0 @@
-CACHE MANIFEST
-http://cross-origin.com/site_isolation/nosniff.json
-
-NETWORK:
-*
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py
index 8b1c04cc..428fec6a 100644
--- a/content/test/gpu/gpu_tests/pixel_test_pages.py
+++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -359,6 +359,10 @@
                       base_name + '_WebGPUImportWebGPUCanvas',
                       test_rect=[0, 0, 400, 200],
                       browser_args=webgpu_args),
+        PixelTestPage('pixel_webgpu_import_video_frame.html',
+                      base_name + '_WebGPUImportVideoFrame',
+                      test_rect=[0, 0, 400, 200],
+                      browser_args=webgpu_args),
         PixelTestPage('pixel_webgpu_webgl_teximage2d.html',
                       base_name + '_WebGPUWebGLTexImage2D',
                       test_rect=[0, 0, 400, 200],
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
index 72de1213..8d9fce1 100644
--- a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/depth_capture_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/depth_capture_expectations.txt
index db53ac0..21332b40 100644
--- a/content/test/gpu/gpu_tests/test_expectations/depth_capture_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/depth_capture_expectations.txt
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
index 3f6cec8..e1f7255c 100644
--- a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt
index ba54937..3c7e4929 100644
--- a/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/info_collection_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/info_collection_expectations.txt
index e5ba5f4..4e3f6bb 100644
--- a/content/test/gpu/gpu_tests/test_expectations/info_collection_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/info_collection_expectations.txt
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/maps_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/maps_expectations.txt
index ba54937..3c7e4929 100644
--- a/content/test/gpu/gpu_tests/test_expectations/maps_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/maps_expectations.txt
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/mediapipe_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/mediapipe_expectations.txt
index 4fa3005..46d9875 100644
--- a/content/test/gpu/gpu_tests/test_expectations/mediapipe_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/mediapipe_expectations.txt
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index 608c3ba..62dbe1f 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
@@ -429,6 +429,7 @@
 
 # Flaky hang.
 crbug.com/1218288 [ fuchsia-board-astro ] Pixel_PrecisionRoundedCorner [ Failure ]
+crbug.com/1218288 [ fuchsia-board-sherlock ] Pixel_PrecisionRoundedCorner [ Failure ]
 crbug.com/1136875 [ fuchsia-board-qemu-x64 ] Pixel_PrecisionRoundedCorner [ RetryOnFailure ]
 
 # Still fails on Nexus 5 after all other Pixel_CanvasLowLatency* pass.
@@ -473,6 +474,13 @@
 # WebGPU pixel tests flakily hang in the metal shader compiler on Mac.
 crbug.com/1268120 [ mac ] Pixel_WebGPUToDataURL [ Failure ]
 
+# NVIDIA Quadro P400 GPU has problem to generate correct rendering results.
+crbug.com/1238570 [ win nvidia-0x1cb3 ] Pixel_WebGPUImportVideoFrame [ Failure ]
+
+# Failures on Sherlock
+# Pixel_BackgroundImage causes a crash on Swarming. Skipping so that we have a signal for other tests.
+crbug.com/1268144 [ fuchsia fuchsia-board-sherlock skia-renderer-vulkan ] Pixel_BackgroundImage [ Skip ]
+
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
 #######################################################################
diff --git a/content/test/gpu/gpu_tests/test_expectations/power_measurement_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/power_measurement_expectations.txt
index 0a98c6c..20932bf 100644
--- a/content/test/gpu/gpu_tests/test_expectations/power_measurement_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/power_measurement_expectations.txt
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt
index 4d9d331..0d33d18 100644
--- a/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
index 2fcc8d5..d43080f 100644
--- a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
@@ -204,6 +204,9 @@
 # Flakes on linux-rel.
 crbug.com/1216377 [ linux ] TraceTest_Video_Media_Stream_Incompatible_Stride [ RetryOnFailure ]
 
+# Cannot generate correct rendering results on windows.
+crbug.com/1238570 [ win ] TraceTest_WebGPUImportVideoFrame [ Failure ]
+
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
 #######################################################################
diff --git a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
index 80015c691..2eac27c 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index 41c1c1c0..0bf0466a 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
@@ -429,6 +429,10 @@
 crbug.com/angleproject/6430 [ mac passthrough angle-metal amd ] deqp/functional/gles3/texturespecification/texstorage2d_format_depth_stencil.html [ Failure ]
 crbug.com/angleproject/6430 [ mac passthrough angle-metal amd ] deqp/functional/gles3/uniformbuffers/random.html [ Failure ]
 
+# Metal AMD ASAN
+crbug.com/1270755 [ mac amd-0x6821 angle-metal passthrough asan ] deqp/functional/gles3/fborender/shared_colorbuffer_01.html [ RetryOnFailure ]
+crbug.com/1272108 [ mac amd-0x6821 angle-metal passthrough asan ] deqp/functional/gles3/texturefiltering/2d_array_combinations_05.html [ Skip ]
+
 # Metal Intel
 crbug.com/angleproject/6430 [ mac passthrough angle-metal intel ] conformance/limits/gl-max-texture-dimensions.html [ Failure ]
 crbug.com/angleproject/6430 [ mac passthrough angle-metal intel ] conformance/textures/misc/texture-size.html [ Failure ]
@@ -520,7 +524,6 @@
 crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] conformance2/textures/canvas_sub_rectangle/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html [ Failure ]
 crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] conformance2/textures/canvas_sub_rectangle/tex-3d-srgb8-rgb-unsigned_byte.html [ Failure ]
 crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] conformance2/textures/misc/tex-storage-compressed-formats.html [ Failure ]
-crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/clipping.html [ RetryOnFailure ]
 crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/draw/draw_elements_instanced.html [ RetryOnFailure ]
 crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/fboinvalidate/default.html [ Failure ]
 crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/framebufferblit/rect_03.html [ Failure ]
@@ -544,6 +547,15 @@
 crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/texturefiltering/cube_sizes_04.html [ Failure ]
 crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/texturespecification/basic_copyteximage2d.html [ Failure ]
 crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/texturespecification/basic_copytexsubimage2d.html [ Failure ]
+# Post Python 3 conversion: crbug.com/1266604
+crbug.com/1271941 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] conformance/ogles/GL/* [ RetryOnFailure ]
+crbug.com/1271941 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] conformance/textures/canvas_sub_rectangle/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ RetryOnFailure ]
+crbug.com/1271941 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/clipping.html [ Failure ]
+crbug.com/1271941 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/fborender/shared_colorbuffer_00.html [ Failure ]
+crbug.com/1271941 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/fborender/shared_colorbuffer_01.html [ Failure ]
+crbug.com/1271941 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/fborender/shared_colorbuffer_02.html [ Failure ]
+crbug.com/1271941 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/fborender/shared_colorbuffer_clear.html [ Failure ]
+crbug.com/1271941 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/fragdepth.html [ Failure ]
 
 ######################################################################
 # Mac failures (mainly OpenGL; some need to be reevaluated on Metal) #
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 2fcfbbd0..ba327e2 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
@@ -12,7 +12,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
@@ -172,7 +172,9 @@
 [ fuchsia ] WebglExtension_EXT_shader_texture_lod [ Skip ]
 [ fuchsia ] WebglExtension_EXT_texture_compression_bptc [ Skip ]
 [ fuchsia fuchsia-board-astro ] WebglExtension_WEBGL_compressed_texture_s3tc [ Skip ]
+[ fuchsia fuchsia-board-sherlock ] WebglExtension_WEBGL_compressed_texture_s3tc [ Skip ]
 [ fuchsia fuchsia-board-astro no-swiftshader-gl ] WebglExtension_EXT_texture_compression_rgtc [ Skip ]
+[ fuchsia fuchsia-board-sherlock no-swiftshader-gl ] WebglExtension_EXT_texture_compression_rgtc [ Skip ]
 
 # This test uses H.264 and the ChromeOS and Fuchsia bots aren't compiled with
 # proprietary codecs.
@@ -367,6 +369,7 @@
 crbug.com/1146483 [ fuchsia fuchsia-board-astro ] conformance/textures/video/tex-2d-alpha-alpha-unsigned_byte.html [ Failure ]
 # Flaky tests
 [ fuchsia fuchsia-board-astro ] WebglExtension_EXT_float_blend [ Failure ]
+[ fuchsia fuchsia-board-sherlock ] WebglExtension_EXT_float_blend [ Failure ]
 [ fuchsia fuchsia-board-astro ] conformance/rendering/rendering-stencil-large-viewport.html [ Failure ]
 [ 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 ]
@@ -379,14 +382,28 @@
 crbug.com/1210953 [ fuchsia fuchsia-board-astro ] conformance/textures/canvas/tex-2d-luminance-luminance-unsigned_byte.html [ RetryOnFailure ]
 
 # Flaky tests
-crbug.com/1136414 [ fuchsia ] conformance/glsl/functions/glsl-function* [ Failure ]
-crbug.com/1136414 [ fuchsia ] conformance/ogles/GL/fract/fract_001_to_006.html [ Failure ]
-crbug.com/1136414 [ fuchsia ] conformance/ogles/GL/build/build_009_to_016.html [ Failure ]
-crbug.com/1136414 [ fuchsia ] conformance/ogles/GL/mat/mat_009_to_016.html [ Failure ]
+crbug.com/1136414 [ fuchsia fuchsia-board-qemu-x64 ] conformance/glsl/functions/glsl-function* [ Failure ]
+crbug.com/1136414 [ fuchsia fuchsia-board-qemu-x64 ] conformance/ogles/GL/fract/fract_001_to_006.html [ Failure ]
+crbug.com/1136414 [ fuchsia fuchsia-board-qemu-x64 ] conformance/ogles/GL/build/build_009_to_016.html [ Failure ]
+crbug.com/1136414 [ fuchsia fuchsia-board-qemu-x64 ] conformance/ogles/GL/mat/mat_009_to_016.html [ Failure ]
 
 # Anti-aliasing disabled on Fuchsia
 [ fuchsia ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ]
 
+# Sherlock failures
+crbug.com/1268138 [ fuchsia fuchsia-board-sherlock skia-renderer-vulkan ] conformance/context/context-attribute-preserve-drawing-buffer.html [ Failure ]
+crbug.com/1268138 [ fuchsia fuchsia-board-sherlock skia-renderer-vulkan ] conformance/context/context-no-alpha-fbo-with-alpha.html [ Failure ]
+crbug.com/1145858 [ fuchsia fuchsia-board-sherlock skia-renderer-vulkan ] conformance/extensions/ext-disjoint-timer-query.html [ Failure ]
+crbug.com/1145861 [ fuchsia fuchsia-board-sherlock skia-renderer-vulkan ] conformance/extensions/oes-texture-float-with-video.html [ Failure ]
+crbug.com/1145861 [ fuchsia fuchsia-board-sherlock skia-renderer-vulkan ] conformance/extensions/oes-texture-half-float-with-video.html [ Failure ]
+crbug.com/1268138 [ fuchsia fuchsia-board-sherlock skia-renderer-vulkan ] conformance/rendering/color-mask-preserved-during-implicit-clears.html [ Failure ]
+crbug.com/1145861 [ fuchsia fuchsia-board-sherlock skia-renderer-vulkan ] conformance/textures/image_bitmap_from_video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ]
+crbug.com/1145861 [ fuchsia fuchsia-board-sherlock skia-renderer-vulkan ] conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_byte.html [ Failure ]
+crbug.com/1145861 [ fuchsia fuchsia-board-sherlock skia-renderer-vulkan ] conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_short_5_6_5.html [ Failure ]
+crbug.com/1145861 [ fuchsia fuchsia-board-sherlock skia-renderer-vulkan ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ Failure ]
+crbug.com/1268138 [ fuchsia fuchsia-board-sherlock skia-renderer-vulkan ] conformance/textures/video/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ]
+crbug.com/1268138 [ fuchsia fuchsia-board-sherlock skia-renderer-vulkan ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ Failure ]
+
 ####################
 # Win failures     #
 ####################
@@ -607,6 +624,8 @@
 crbug.com/angleproject/5505 [ mac apple-angle-metal-renderer:-apple-m1 angle-metal ] conformance/rendering/multisample-corruption.html [ Failure ]
 # No active browser window, but no crash stack.
 crbug.com/1240443 [ mac apple-apple-m1 passthrough angle-opengl ] conformance/renderbuffers/stencil-renderbuffer-initialization.html [ RetryOnFailure ]
+# After converting to Python 3: crbug.com/1266604
+crbug.com/1271941 [ mac apple-apple-m1 angle-metal ] conformance/ogles/GL/* [ RetryOnFailure ]
 
 ####################
 # Linux failures   #
diff --git a/content/test/gpu/gpu_tests/webcodecs_integration_test.py b/content/test/gpu/gpu_tests/webcodecs_integration_test.py
index 7e16979..2b4e9ed 100644
--- a/content/test/gpu/gpu_tests/webcodecs_integration_test.py
+++ b/content/test/gpu/gpu_tests/webcodecs_integration_test.py
@@ -85,6 +85,15 @@
             layers
         }))
 
+    for codec in codecs:
+      for acc in accelerations:
+        args = (codec, acc)
+        yield ('WebCodecs_EncodeColorSpace_%s_%s' % args,
+               'encode-color-space.html', ({
+                   "codec": codec,
+                   "acceleration": acc
+               }))
+
   def RunActualGpuTest(self, test_path, *args):
     url = self.UrlOfStaticFilePath(html_path + '/' + test_path)
     tab = self.tab
diff --git a/content/test/gpu/validate_tag_consistency.py b/content/test/gpu/validate_tag_consistency.py
index e72e842..f7b04325 100755
--- a/content/test/gpu/validate_tag_consistency.py
+++ b/content/test/gpu/validate_tag_consistency.py
@@ -25,7 +25,7 @@
 # tags: [ android-nexus-5 android-nexus-5x android-nexus-9 android-pixel-2
 #             android-pixel-4 android-shield-android-tv
 #         chromeos-board-amd64-generic chromeos-board-kevin chromeos-board-eve
-#         fuchsia-board-astro fuchsia-board-qemu-x64 ]
+#         fuchsia-board-astro fuchsia-board-sherlock fuchsia-board-qemu-x64 ]
 # Platform
 # tags: [ desktop
 #         mobile ]
diff --git a/courgette/application.png b/courgette/application.png
new file mode 100644
index 0000000..97fe870
--- /dev/null
+++ b/courgette/application.png
Binary files differ
diff --git a/courgette/generation.png b/courgette/generation.png
new file mode 100644
index 0000000..5f58a6d2
--- /dev/null
+++ b/courgette/generation.png
Binary files differ
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn
index 4727fa60..53d71c57 100644
--- a/device/bluetooth/BUILD.gn
+++ b/device/bluetooth/BUILD.gn
@@ -9,7 +9,7 @@
   import("//build/config/android/rules.gni")  # For generate_jni().
 }
 if (is_chromeos_ash) {
-  import("//chromeos/dbus/use_real_dbus_clients.gni")
+  import("//chromeos/dbus/config/use_real_dbus_clients.gni")
 } else if (use_bluez) {
   use_real_dbus_clients = false
 }
@@ -452,7 +452,7 @@
         "floss/floss_manager_client.h",
       ]
       if (is_chromeos_ash) {
-        configs += [ "//chromeos/dbus:use_real_dbus_clients_config" ]
+        configs += [ "//chromeos/dbus/config:use_real_dbus_clients_config" ]
         sources += [
           "chromeos/bluetooth_connection_logger.cc",
           "chromeos/bluetooth_connection_logger.h",
diff --git a/device/fido/cbor_extract.h b/device/fido/cbor_extract.h
index 10289e55..afb88d4 100644
--- a/device/fido/cbor_extract.h
+++ b/device/fido/cbor_extract.h
@@ -8,7 +8,6 @@
 #include "base/callback_forward.h"
 #include "base/component_export.h"
 #include "base/containers/span.h"
-#include "base/memory/raw_ptr.h"
 #include "components/cbor/values.h"
 
 namespace device {
@@ -218,13 +217,6 @@
 
 template <typename S>
 constexpr StepOrByte<S> Element(const Is required,
-                                raw_ptr<const std::vector<uint8_t>> S::*member,
-                                uintptr_t offset) {
-  return ElementImpl<S>(required, offset, internal::Type::kBytestring);
-}
-
-template <typename S>
-constexpr StepOrByte<S> Element(const Is required,
                                 const std::string* S::*member,
                                 uintptr_t offset) {
   return ElementImpl<S>(required, offset, internal::Type::kString);
@@ -232,13 +224,6 @@
 
 template <typename S>
 constexpr StepOrByte<S> Element(const Is required,
-                                raw_ptr<const std::string> S::*member,
-                                uintptr_t offset) {
-  return ElementImpl<S>(required, offset, internal::Type::kString);
-}
-
-template <typename S>
-constexpr StepOrByte<S> Element(const Is required,
                                 const int64_t* S::*member,
                                 uintptr_t offset) {
   return ElementImpl<S>(required, offset, internal::Type::kInt);
@@ -246,27 +231,12 @@
 
 template <typename S>
 constexpr StepOrByte<S> Element(const Is required,
-                                raw_ptr<const int64_t> S::*member,
-                                uintptr_t offset) {
-  return ElementImpl<S>(required, offset, internal::Type::kInt);
-}
-
-template <typename S>
-constexpr StepOrByte<S> Element(const Is required,
                                 const std::vector<cbor::Value>* S::*member,
                                 uintptr_t offset) {
   return ElementImpl<S>(required, offset, internal::Type::kArray);
 }
 
 template <typename S>
-constexpr StepOrByte<S> Element(
-    const Is required,
-    raw_ptr<const std::vector<cbor::Value>> S::*member,
-    uintptr_t offset) {
-  return ElementImpl<S>(required, offset, internal::Type::kArray);
-}
-
-template <typename S>
 constexpr StepOrByte<S> Element(const Is required,
                                 const cbor::Value* S::*member,
                                 uintptr_t offset) {
@@ -275,25 +245,11 @@
 
 template <typename S>
 constexpr StepOrByte<S> Element(const Is required,
-                                raw_ptr<const cbor::Value> S::*member,
-                                uintptr_t offset) {
-  return ElementImpl<S>(required, offset, internal::Type::kValue);
-}
-
-template <typename S>
-constexpr StepOrByte<S> Element(const Is required,
                                 const bool* S::*member,
                                 uintptr_t offset) {
   return ElementImpl<S>(required, offset, internal::Type::kBoolean);
 }
 
-template <typename S>
-constexpr StepOrByte<S> Element(const Is required,
-                                raw_ptr<const bool> S::*member,
-                                uintptr_t offset) {
-  return ElementImpl<S>(required, offset, internal::Type::kBoolean);
-}
-
 COMPONENT_EXPORT(DEVICE_FIDO)
 bool Extract(base::span<const void*> outputs,
              base::span<const StepOrByte<void>> steps,
diff --git a/docs/infra/new_builder.md b/docs/infra/new_builder.md
index 74a93cd..b2f0f9e 100644
--- a/docs/infra/new_builder.md
+++ b/docs/infra/new_builder.md
@@ -399,6 +399,11 @@
 
 To add a builder to the CQ, add a `tryjob` value to the builder definition.
 
+This will add the builder to all CQ attempts (except for CLs that only contain
+files in some particular directories).
+
+###### Regular (non-Orchestrator) CQ builders
+
 ```starlark
 try_.chromium_linux_builder(
     name = '$BUILDER_NAME',
@@ -406,8 +411,56 @@
 )
 ```
 
-This will add the builder to all CQ attempts (except for CLs that only contain
-files in some particular directories).
+###### Orchestrator CQ Builders
+The Orchestrator pattern is an optimization from the old chromium_trybot CQ
+builders, where compiles are triggered to run on separate beefier machines.
+It consists of the chromium/orchestrator.py and chromium/compilator.py recipes.
+
+Builders using the Orchestrator pattern use a dedicated pool of machines to run
+their builds (often called builderful). The
+Orchestrator builder uses 2 or 4 core bots and the Compilator builder uses a
+beefier >=16 core bot. The Compilator builder name should always be the
+orchestrator name + "-compilator", like linux-rel and linux-rel-compilator.
+
+In chromium/src/infra/config/subprojects/chromium/try.star:
+```starlark
+try_.chromium_linux_orchestrator_pair(
+    name = "linux-rel",
+    branch_selector = branches.STANDARD_MILESTONE,
+    main_list_view = "try",
+    use_clang_coverage = True,
+    coverage_test_types = ["unit", "overall"],
+    orchestrator_cores = 2,
+    orchestrator_tryjob = try_.job(),
+    compilator_cores = 16,
+    compilator_goma_jobs = goma.jobs.J150,
+    compilator_name = "linux-rel-compilator",
+)
+```
+
+In infradata/config/configs/chromium-swarm/bots/chromium/chromium.star:
+(In the [infradata/config](https://chrome-internal.googlesource.com/infradata/config/) repo)
+```starlark
+try_bots({
+    "linux-rel": chrome.gce_bionic(
+        prefix = "linux-rel-orchestrator-2-core",
+        zone = "us-central1-b",
+        machine_type = "n1-standard-2",
+        lifetime = time.week,
+        amount = 80,
+    ),
+    "linux-rel-compilator": chrome.gce_bionic(
+        prefix = "linux-rel-compilator-ssd-16-core",
+        zone = "us-central1-b",
+        machine_type = "n1-standard-16",
+        lifetime = time.week,
+        amount = 25,
+        disk_gb = 100,
+        // This enables local ssd usage for this bot
+        scratch_disks = chrome.scratch_disks(count = 1, interface = "NVME"),
+    ),
+})
+```
 
 ###### Experimental CQ builders
 
diff --git a/docs/security/service-worker-security-faq.md b/docs/security/service-worker-security-faq.md
index 37f50f2c..56610d1 100644
--- a/docs/security/service-worker-security-faq.md
+++ b/docs/security/service-worker-security-faq.md
@@ -217,7 +217,7 @@
 mic, geo-location, and so on). But we avoid asking questions about resource-use
 (caching, persistence, CPU, and so on). We’re better prepared to make those
 types of resource decisions automatically. (Consider, for example, that the HTTP
-cache, AppCache, and even [Google
+cache, and even [Google
 Gears](https://en.wikipedia.org/wiki/Gears_(software)) also do not/did not
 prompt the user.)
 
diff --git a/extensions/browser/extension_navigation_throttle.cc b/extensions/browser/extension_navigation_throttle.cc
index b9988f8..9ab13b0 100644
--- a/extensions/browser/extension_navigation_throttle.cc
+++ b/extensions/browser/extension_navigation_throttle.cc
@@ -229,10 +229,9 @@
         content::StoragePartitionConfig::CreateDefault(browser_context);
     bool is_guest = navigation_handle()->GetStartingSiteInstance()->IsGuest();
     if (is_guest) {
-      is_guest = WebViewGuest::GetGuestPartitionConfigForSite(
-          browser_context,
-          navigation_handle()->GetStartingSiteInstance()->GetSiteURL(),
-          &storage_partition_config);
+      storage_partition_config = navigation_handle()
+                                     ->GetStartingSiteInstance()
+                                     ->GetStoragePartitionConfig();
     }
     CHECK_EQ(is_guest,
              navigation_handle()->GetStartingSiteInstance()->IsGuest());
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index ceee1be..cbd3215 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -65,7 +65,6 @@
 #include "extensions/common/manifest_constants.h"
 #include "extensions/strings/grit/extensions_strings.h"
 #include "ipc/ipc_message_macros.h"
-#include "net/base/escape.h"
 #include "net/base/net_errors.h"
 #include "net/cookies/canonical_cookie.h"
 #include "third_party/blink/public/common/logging/logging_utils.h"
@@ -90,11 +89,6 @@
 
 namespace {
 
-// Strings used to encode blob url fallback mode in site URLs.
-constexpr char kNoFallback[] = "nofallback";
-constexpr char kInMemoryFallback[] = "inmemoryfallback";
-constexpr char kOnDiskFallback[] = "ondiskfallback";
-
 // Returns storage partition removal mask from web_view clearData mask. Note
 // that storage partition mask is a subset of webview's data removal mask.
 uint32_t GetStoragePartitionRemovalMask(uint32_t web_view_removal_mask) {
@@ -276,87 +270,6 @@
 }
 
 // static
-bool WebViewGuest::GetGuestPartitionConfigForSite(
-    content::BrowserContext* browser_context,
-    const GURL& site,
-    content::StoragePartitionConfig* storage_partition_config) {
-  if (!site.SchemeIs(content::kGuestScheme))
-    return false;
-
-  // The partition name is user supplied value, which we have encoded when the
-  // URL was created, so it needs to be decoded. Since it was created via
-  // EscapeQueryParamValue(), it should have no path separators or control codes
-  // when unescaped, but safest to check for that and fail if it does.
-  std::string partition_name;
-  if (!net::UnescapeBinaryURLComponentSafe(site.query_piece(),
-                                           true /* fail_on_path_separators */,
-                                           &partition_name)) {
-    return false;
-  }
-
-  // Since guest URLs are only used for packaged apps, there must be an app
-  // id in the URL.
-  CHECK(site.has_host());
-  // Since persistence is optional, the path must either be empty or the
-  // literal string.
-  bool in_memory = (site.path() != "/persist");
-
-  *storage_partition_config = content::StoragePartitionConfig::Create(
-      browser_context, site.host(), partition_name, in_memory);
-  // A <webview> inside a chrome app needs to be able to resolve Blob URLs that
-  // were created by the chrome app. The chrome app has the same
-  // partition_domain but empty partition_name. Setting this flag on the
-  // partition config causes it to be used as fallback for the purpose of
-  // resolving blob URLs.
-
-  // Default to having the fallback partition on disk, as that matches most
-  // closely what we would have done before fallback behavior started being
-  // encoded in the site URL.
-  content::StoragePartitionConfig::FallbackMode fallback_mode =
-      content::StoragePartitionConfig::FallbackMode::kFallbackPartitionOnDisk;
-  if (site.ref() == kNoFallback) {
-    fallback_mode = content::StoragePartitionConfig::FallbackMode::kNone;
-  } else if (site.ref() == kInMemoryFallback) {
-    fallback_mode = content::StoragePartitionConfig::FallbackMode::
-        kFallbackPartitionInMemory;
-  } else if (site.ref() == kOnDiskFallback) {
-    fallback_mode =
-        content::StoragePartitionConfig::FallbackMode::kFallbackPartitionOnDisk;
-  }
-
-  storage_partition_config->set_fallback_to_partition_domain_for_blob_urls(
-      fallback_mode);
-  return true;
-}
-
-// static
-GURL WebViewGuest::GetSiteForGuestPartitionConfig(
-    const content::StoragePartitionConfig& storage_partition_config) {
-  std::string url_encoded_partition = net::EscapeQueryParamValue(
-      storage_partition_config.partition_name(), false);
-  const char* fallback = "";
-  switch (
-      storage_partition_config.fallback_to_partition_domain_for_blob_urls()) {
-    case content::StoragePartitionConfig::FallbackMode::kNone:
-      fallback = kNoFallback;
-      break;
-    case content::StoragePartitionConfig::FallbackMode::
-        kFallbackPartitionOnDisk:
-      fallback = kOnDiskFallback;
-      break;
-    case content::StoragePartitionConfig::FallbackMode::
-        kFallbackPartitionInMemory:
-      fallback = kInMemoryFallback;
-      break;
-  }
-  return GURL(
-      base::StringPrintf("%s://%s/%s?%s#%s", content::kGuestScheme,
-                         storage_partition_config.partition_domain().c_str(),
-                         storage_partition_config.in_memory() ? "" : "persist",
-                         url_encoded_partition.c_str(), fallback));
-}
-
-// static
 std::string WebViewGuest::GetPartitionID(
     RenderProcessHost* render_process_host) {
   WebViewRendererState* renderer_state = WebViewRendererState::GetInstance();
@@ -434,8 +347,6 @@
     }
   }
 
-  GURL guest_site = GetSiteForGuestPartitionConfig(partition_config);
-
   // If we already have a webview tag in the same app using the same storage
   // partition, we should use the same SiteInstance so the existing tag and
   // the new tag can script each other.
@@ -447,8 +358,8 @@
     // Create the SiteInstance in a new BrowsingInstance, which will ensure
     // that webview tags are also not allowed to send messages across
     // different partitions.
-    guest_site_instance =
-        content::SiteInstance::CreateForGuest(browser_context(), guest_site);
+    guest_site_instance = content::SiteInstance::CreateForGuest(
+        browser_context(), partition_config);
   }
   WebContents::CreateParams params(browser_context(),
                                    std::move(guest_site_instance));
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.h b/extensions/browser/guest_view/web_view/web_view_guest.h
index dbc21342..049a363 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.h
+++ b/extensions/browser/guest_view/web_view/web_view_guest.h
@@ -23,10 +23,6 @@
 #include "extensions/common/mojom/frame.mojom.h"
 #include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
 
-namespace content {
-class StoragePartitionConfig;
-}  // namespace content
-
 namespace extensions {
 
 class WebViewInternalFindFunction;
@@ -50,24 +46,6 @@
 
   static GuestViewBase* Create(content::WebContents* owner_web_contents);
 
-  // For WebViewGuest, we create special guest processes, which host the
-  // tag content separately from the main application that embeds the tag.
-  // A <webview> can specify both the partition name and whether the storage
-  // for that partition should be persisted. Each tag gets a SiteInstance with
-  // a specially formatted URL, based on the application it is hosted by and
-  // the partition requested by it. The format for that URL is:
-  // chrome-guest://partition_domain/persist?partition_name
-  static bool GetGuestPartitionConfigForSite(
-      content::BrowserContext* browser_context,
-      const GURL& site,
-      content::StoragePartitionConfig* storage_partition_config);
-
-  // Opposite of GetGuestPartitionConfigForSite: Creates a specially formatted
-  // URL used by the SiteInstance associated with the WebViewGuest. See
-  // GetGuestPartitionConfigForSite for the URL format.
-  static GURL GetSiteForGuestPartitionConfig(
-      const content::StoragePartitionConfig& storage_partition_config);
-
   // Returns the WebView partition ID associated with the render process
   // represented by |render_process_host|, if any. Otherwise, an empty string is
   // returned.
diff --git a/extensions/browser/process_manager.cc b/extensions/browser/process_manager.cc
index 88dfc20..406727c 100644
--- a/extensions/browser/process_manager.cc
+++ b/extensions/browser/process_manager.cc
@@ -96,18 +96,17 @@
 
 std::string GetExtensionIdForSiteInstance(
     content::SiteInstance* site_instance) {
-  if (!site_instance)
-    return std::string();
+  // <webview> guests always store the ExtensionId in the partition domain.
+  if (site_instance->IsGuest())
+    return site_instance->GetStoragePartitionConfig().partition_domain();
 
   // This works for both apps and extensions because the site has been
   // normalized to the extension URL for hosted apps.
   const GURL& site_url = site_instance->GetSiteURL();
+  if (site_url.SchemeIs(kExtensionScheme))
+    return site_url.host();
 
-  if (!site_url.SchemeIs(kExtensionScheme) &&
-      !site_url.SchemeIs(content::kGuestScheme))
-    return std::string();
-
-  return site_url.host();
+  return std::string();
 }
 
 std::string GetExtensionID(content::RenderFrameHost* render_frame_host) {
diff --git a/extensions/docs/security_faq.md b/extensions/docs/security_faq.md
index 39167fac..692fc2a 100644
--- a/extensions/docs/security_faq.md
+++ b/extensions/docs/security_faq.md
@@ -252,6 +252,16 @@
 of extensions, such as tab and session managers, bookmark managers, and history
 managers.
 
+### Why do we not allow extensions to open or close chrome-untrusted:-scheme pages?
+
+The chrome-untrusted:-scheme (such as chrome-untrusted://terminal) is generally
+used for Chrome OS System Web Apps. Some of these apps such as Terminal which
+starts the Linux VM can perform operations on startup, or start other systems
+which may have security vulnerabilities. We
+[intentionally](../../security/chromeos_security_whitepaper.md#principles-of-chrome-os-security)
+disallow auto-start to avoid
+[persistent attacks](https://chromium.googlesource.com/chromiumos/docs/+/HEAD/containers_and_vms.md#security-persistence).
+
 ### Why are extensions allowed to bypass a web page's Content Security Policy?
 
 Extensions are considered more privileged than the web pages they are allowed to
diff --git a/extensions/renderer/api/automation/automation_internal_custom_bindings.cc b/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
index 40bea26..2017213 100644
--- a/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
+++ b/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
@@ -880,7 +880,7 @@
       [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
          AutomationAXTreeWrapper* tree_wrapper, ui::AXNode* node) {
         const std::vector<int> line_starts =
-            node->GetOrComputeLineStartOffsets();
+            node->GetIntListAttribute(ax::mojom::IntListAttribute::kLineStarts);
         v8::Local<v8::Context> context = isolate->GetCurrentContext();
         v8::Local<v8::Array> array_result(
             v8::Array::New(isolate, line_starts.size()));
diff --git a/extensions/renderer/bindings/api_binding_unittest.cc b/extensions/renderer/bindings/api_binding_unittest.cc
index 26e4aed..8889f03b 100644
--- a/extensions/renderer/bindings/api_binding_unittest.cc
+++ b/extensions/renderer/bindings/api_binding_unittest.cc
@@ -1977,8 +1977,7 @@
   const char kRegisterHook[] = R"(
       (function(hooks) {
         hooks.setCustomCallback('supportsPromises',
-                                (name, callback, response) => {
-          this.methodName = name;
+                                (callback, response) => {
           this.response = response;
           this.resolveCallback = callback;
           if (response == 'resolveNow')
@@ -2012,9 +2011,6 @@
                                        std::string());
     // The promise should still be unfulfilled until the callback is invoked.
     EXPECT_EQ(v8::Promise::kPending, promise->State());
-    EXPECT_EQ(
-        R"("test.supportsPromises")",
-        GetStringPropertyFromObject(context->Global(), context, "methodName"));
     v8::Local<v8::Function> resolve_callback;
     ASSERT_TRUE(GetPropertyFromObjectAs(context->Global(), context,
                                         "resolveCallback", &resolve_callback));
diff --git a/extensions/renderer/bindings/api_bindings_system_unittest.cc b/extensions/renderer/bindings/api_bindings_system_unittest.cc
index cd6aed3..93511d7 100644
--- a/extensions/renderer/bindings/api_bindings_system_unittest.cc
+++ b/extensions/renderer/bindings/api_bindings_system_unittest.cc
@@ -98,9 +98,8 @@
 const char kCustomCallbackHook[] = R"(
     (function(hooks) {
       hooks.setCustomCallback(
-          'functionWithCallback', (name, originalCallback,
+          'functionWithCallback', (originalCallback,
                                    firstResult, secondResult) => {
-        this.methodName = name;
         this.results = [firstResult, secondResult];
         originalCallback(secondResult);
       });
@@ -439,9 +438,6 @@
   bindings_system()->CompleteRequest(last_request()->request_id, *response,
                                      std::string());
 
-  EXPECT_EQ(
-      R"("alpha.functionWithCallback")",
-      GetStringPropertyFromObject(context->Global(), context, "methodName"));
   EXPECT_EQ(R"(["alpha","beta"])",
             GetStringPropertyFromObject(context->Global(), context, "results"));
   EXPECT_EQ(R"(["beta"])",
@@ -480,9 +476,6 @@
   bindings_system()->CompleteRequest(last_request()->request_id, *response,
                                      std::string());
 
-  EXPECT_EQ(
-      R"("alpha.functionWithCallback")",
-      GetStringPropertyFromObject(context->Global(), context, "methodName"));
   EXPECT_EQ(R"(["gamma","delta"])",
             GetStringPropertyFromObject(context->Global(), context, "results"));
   EXPECT_EQ(v8::Promise::kFulfilled, promise->State());
diff --git a/extensions/renderer/bindings/api_request_handler.cc b/extensions/renderer/bindings/api_request_handler.cc
index 8edaa872..77c0b48 100644
--- a/extensions/renderer/bindings/api_request_handler.cc
+++ b/extensions/renderer/bindings/api_request_handler.cc
@@ -99,8 +99,7 @@
   void ResolveRequest(v8::Local<v8::Context> context,
                       APILastError* last_error,
                       const std::vector<v8::Local<v8::Value>>& response_args,
-                      const std::string& error,
-                      const std::string& method_name);
+                      const std::string& error);
 
   // Returns true if the request handler is using a custom callback.
   bool has_custom_callback() const { return !custom_callback_.IsEmpty(); }
@@ -128,8 +127,7 @@
   void CallCustomCallback(
       v8::Local<v8::Context> context,
       const std::vector<v8::Local<v8::Value>>& response_args,
-      const std::string& error,
-      const std::string& method_name);
+      const std::string& error);
 
   // Callback-based handlers. Mutually exclusive with promise-based handlers.
   v8::Global<v8::Function> callback_;
@@ -170,8 +168,7 @@
     v8::Local<v8::Context> context,
     APILastError* last_error,
     const std::vector<v8::Local<v8::Value>>& response_args,
-    const std::string& error,
-    const std::string& method_name) {
+    const std::string& error) {
   v8::Isolate* isolate = context->GetIsolate();
 
   // Set runtime.lastError if there is an error and this isn't a promise-based
@@ -185,7 +182,7 @@
     // Custom callback case; the custom callback will invoke a curried-in
     // callback, which will trigger the response in the extension (either
     // promise or callback).
-    CallCustomCallback(context, response_args, error, method_name);
+    CallCustomCallback(context, response_args, error);
   } else if (!promise_resolver_.IsEmpty()) {  // Promise-based request.
     DCHECK(callback_.IsEmpty());
     ResolvePromise(context, response_args, error,
@@ -277,8 +274,7 @@
 void APIRequestHandler::AsyncResultHandler::CallCustomCallback(
     v8::Local<v8::Context> context,
     const std::vector<v8::Local<v8::Value>>& response_args,
-    const std::string& error,
-    const std::string& method_name) {
+    const std::string& error) {
   v8::Isolate* isolate = context->GetIsolate();
 
   v8::Local<v8::Value> callback_to_pass = v8::Undefined(isolate);
@@ -303,10 +299,9 @@
   }
 
   // Custom callbacks in the JS bindings are called with the arguments of the
-  // method name, callback function, and the response from the API.
+  // callback function and the response from the API.
   std::vector<v8::Local<v8::Value>> custom_callback_args;
-  custom_callback_args.reserve(2 + response_args.size());
-  custom_callback_args.push_back(gin::StringToSymbol(isolate, method_name));
+  custom_callback_args.reserve(1 + response_args.size());
   custom_callback_args.push_back(callback_to_pass);
   custom_callback_args.insert(custom_callback_args.end(), response_args.begin(),
                               response_args.end());
@@ -554,8 +549,8 @@
 
   v8::TryCatch try_catch(isolate);
 
-  pending_request.async_handler->ResolveRequest(
-      context, &last_error_, response_args, error, pending_request.method_name);
+  pending_request.async_handler->ResolveRequest(context, &last_error_,
+                                                response_args, error);
 
   // Since arbitrary JS has ran, the context may have been invalidated. If it
   // was, bail.
diff --git a/extensions/renderer/bindings/api_request_handler_unittest.cc b/extensions/renderer/bindings/api_request_handler_unittest.cc
index d3695f9..88b6906 100644
--- a/extensions/renderer/bindings/api_request_handler_unittest.cc
+++ b/extensions/renderer/bindings/api_request_handler_unittest.cc
@@ -245,11 +245,10 @@
       GetPropertyFromObjectAs(context->Global(), context, "result", &result));
   ArgumentList args;
   ASSERT_TRUE(gin::Converter<ArgumentList>::FromV8(isolate(), result, &args));
-  ASSERT_EQ(4u, args.size());
-  EXPECT_EQ(R"("method")", V8ToString(args[0], context));
-  EXPECT_TRUE(args[1]->IsFunction());
-  EXPECT_EQ(R"("response")", V8ToString(args[2], context));
-  EXPECT_EQ(R"("arguments")", V8ToString(args[3], context));
+  ASSERT_EQ(3u, args.size());
+  EXPECT_TRUE(args[0]->IsFunction());
+  EXPECT_EQ(R"("response")", V8ToString(args[1], context));
+  EXPECT_EQ(R"("arguments")", V8ToString(args[2], context));
 
   EXPECT_TRUE(request_handler->GetPendingRequestIdsForTesting().empty());
 
@@ -260,7 +259,7 @@
       GetPropertyFromObject(context->Global(), context, "callbackCalled")
           ->IsUndefined());
   v8::Local<v8::Value> callback_args[] = {gin::StringToV8(isolate(), "foo")};
-  RunFunctionOnGlobal(args[1].As<v8::Function>(), context, 1, callback_args);
+  RunFunctionOnGlobal(args[0].As<v8::Function>(), context, 1, callback_args);
 
   EXPECT_EQ(R"("foo")", GetStringPropertyFromObject(context->Global(), context,
                                                     "callbackCalled"));
@@ -298,21 +297,20 @@
       GetPropertyFromObjectAs(context->Global(), context, "result", &result));
   ArgumentList args;
   ASSERT_TRUE(gin::Converter<ArgumentList>::FromV8(isolate(), result, &args));
-  ASSERT_EQ(4u, args.size());
-  EXPECT_EQ(R"("method")", V8ToString(args[0], context));
+  ASSERT_EQ(3u, args.size());
   // Even though this is a promise based request the custom callbacks expect a
   // function argument to be passed to them, hence why we get a function here.
   // Invoking the callback however, should still result in the promise being
   // resolved.
-  EXPECT_TRUE(args[1]->IsFunction());
-  EXPECT_EQ(R"("response")", V8ToString(args[2], context));
-  EXPECT_EQ(R"("arguments")", V8ToString(args[3], context));
+  EXPECT_TRUE(args[0]->IsFunction());
+  EXPECT_EQ(R"("response")", V8ToString(args[1], context));
+  EXPECT_EQ(R"("arguments")", V8ToString(args[2], context));
 
   EXPECT_TRUE(request_handler->GetPendingRequestIdsForTesting().empty());
 
   EXPECT_EQ(v8::Promise::kPending, promise->State());
   v8::Local<v8::Value> callback_args[] = {gin::StringToV8(isolate(), "foo")};
-  RunFunctionOnGlobal(args[1].As<v8::Function>(), context, 1, callback_args);
+  RunFunctionOnGlobal(args[0].As<v8::Function>(), context, 1, callback_args);
   EXPECT_EQ(v8::Promise::kFulfilled, promise->State());
   EXPECT_EQ(R"("foo")", V8ToString(promise->Result(), context));
 }
@@ -346,9 +344,8 @@
       GetPropertyFromObjectAs(context->Global(), context, "result", &result));
   ArgumentList args;
   ASSERT_TRUE(gin::Converter<ArgumentList>::FromV8(isolate(), result, &args));
-  ASSERT_EQ(2u, args.size());
-  EXPECT_EQ("\"method\"", V8ToString(args[0], context));
-  EXPECT_TRUE(args[1]->IsUndefined());
+  ASSERT_EQ(1u, args.size());
+  EXPECT_TRUE(args[0]->IsUndefined());
 
   EXPECT_TRUE(request_handler->GetPendingRequestIdsForTesting().empty());
 }
diff --git a/extensions/renderer/resources/app_window_custom_bindings.js b/extensions/renderer/resources/app_window_custom_bindings.js
index a83ae45..8a05256ea 100644
--- a/extensions/renderer/resources/app_window_custom_bindings.js
+++ b/extensions/renderer/resources/app_window_custom_bindings.js
@@ -111,7 +111,7 @@
   var apiFunctions = bindingsAPI.apiFunctions;
 
   apiFunctions.setCustomCallback('create',
-      function(name, callback, windowParams) {
+      function(callback, windowParams) {
     // |callback| is optional.
     let maybeCallback = callback || function() {};
 
diff --git a/extensions/renderer/resources/file_entry_binding_util.js b/extensions/renderer/resources/file_entry_binding_util.js
index 654227d6..da88eaa9 100644
--- a/extensions/renderer/resources/file_entry_binding_util.js
+++ b/extensions/renderer/resources/file_entry_binding_util.js
@@ -40,7 +40,7 @@
   if (WINDOW == backgroundPage) {
     var bindFileEntryCallback = function(functionName, apiFunctions) {
       apiFunctions.setCustomCallback(functionName,
-          function(name, callback, response) {
+          function(callback, response) {
         if (callback) {
           if (!response) {
             callback();
@@ -138,7 +138,7 @@
   // context as their own. This allows them to be used from other windows
   // (including the background page) after the original window is closed.
   if (WINDOW == backgroundPage) {
-    return function(name, callback, response) {
+    return function(callback, response) {
       if (callback) {
         if (!response) {
           callback();
diff --git a/extensions/renderer/resources/file_system_custom_bindings.js b/extensions/renderer/resources/file_system_custom_bindings.js
index 657b70c..7a8a5e53 100644
--- a/extensions/renderer/resources/file_system_custom_bindings.js
+++ b/extensions/renderer/resources/file_system_custom_bindings.js
@@ -72,7 +72,7 @@
   });
 
   apiFunctions.setCustomCallback('requestFileSystem',
-      function(name, callback, response) {
+      function(callback, response) {
     var fileSystem;
     if (response && response.file_system_id) {
       fileSystem = fileSystemNatives.GetIsolatedFileSystem(
diff --git a/extensions/renderer/resources/permissions_custom_bindings.js b/extensions/renderer/resources/permissions_custom_bindings.js
index 1b16b38..a795f93 100644
--- a/extensions/renderer/resources/permissions_custom_bindings.js
+++ b/extensions/renderer/resources/permissions_custom_bindings.js
@@ -68,7 +68,7 @@
 
   // Convert complex permissions back to objects
   apiFunctions.setCustomCallback('getAll',
-      function(name, callback, response) {
+      function(callback, response) {
         for (var i = 0; i < response.permissions.length; i += 1) {
           response.permissions[i] =
               maybeConvertToObject(response.permissions[i]);
diff --git a/gin/v8_platform_page_allocator.cc b/gin/v8_platform_page_allocator.cc
index 216fde4cc..49b3ca6 100644
--- a/gin/v8_platform_page_allocator.cc
+++ b/gin/v8_platform_page_allocator.cc
@@ -25,9 +25,13 @@
       // projects may still be using non-bti compliant code.
       return base::PageReadWriteExecute;
     case v8::PageAllocator::Permission::kReadExecute:
+#if defined(__ARM_FEATURE_BTI_DEFAULT)
       return base::CPU::GetInstanceNoAllocation().has_bti()
                  ? base::PageReadExecuteProtected
                  : base::PageReadExecute;
+#else
+      return base::PageReadExecute;
+#endif
     case v8::PageAllocator::Permission::kNoAccessWillJitLater:
       // We could use this information to conditionally set the MAP_JIT flag
       // on Mac-arm64; however this permissions value is intended to be a
diff --git a/gin/v8_platform_page_allocator_unittest.cc b/gin/v8_platform_page_allocator_unittest.cc
index 455845b8..c5c0a25 100644
--- a/gin/v8_platform_page_allocator_unittest.cc
+++ b/gin/v8_platform_page_allocator_unittest.cc
@@ -33,10 +33,17 @@
            base::PageReadWrite);
   CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kReadWriteExecute),
            base::PageReadWriteExecute);
+
+#if defined(__ARM_FEATURE_BTI_DEFAULT)
   CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kReadExecute),
            base::CPU::GetInstanceNoAllocation().has_bti()
                ? base::PageReadExecuteProtected
                : base::PageReadExecute);
+#else
+  CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kReadExecute),
+           base::PageReadExecute);
+#endif
+
   CHECK_EQ(
       sut.GetPageConfigForTesting(v8::PageAllocator::kNoAccessWillJitLater),
       base::PageInaccessible);
diff --git a/gpu/command_buffer/service/external_vk_image_backing.cc b/gpu/command_buffer/service/external_vk_image_backing.cc
index 1fa68192..531e6aa 100644
--- a/gpu/command_buffer/service/external_vk_image_backing.cc
+++ b/gpu/command_buffer/service/external_vk_image_backing.cc
@@ -225,6 +225,9 @@
   if (!pixel_data.empty()) {
     size_t stride = BitsPerPixel(format) / 8 * size.width();
     backing->WritePixelsWithData(pixel_data, stride);
+
+    // Mark the backing as cleared.
+    backing->SetCleared();
   }
 
   return backing;
diff --git a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
index b524830f..0e787292 100644
--- a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
+++ b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "build/build_config.h"
 #include "components/viz/test/test_gpu_service_holder.h"
 #include "gpu/command_buffer/client/shared_image_interface.h"
 #include "gpu/command_buffer/client/webgpu_implementation.h"
@@ -13,6 +14,11 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/color_space.h"
 
+#if defined(OS_MAC)
+#include "gpu/command_buffer/tests/gl_manager.h"
+#include "ui/gl/gl_context.h"
+#endif
+
 namespace gpu {
 namespace {
 
@@ -46,8 +52,21 @@
 class WebGPUMailboxTest : public WebGPUTest {
  protected:
   void SetUp() override {
+#if defined(OS_MAC)
+    // Crashing on Mac M1. Currently missing stack trace. crbug.com/1271926
+    // This must be checked before WebGPUTest::Initialize otherwise context
+    // switched is locked and we cannot temporarily have this GLContext.
+    GLManager gl_manager;
+    gl_manager.Initialize(GLManager::Options());
+    std::string renderer(gl_manager.context()->GetGLRenderer());
+    if (renderer.find("Apple M1") != std::string::npos)
+      mac_m1_ = true;
+    gl_manager.Destroy();
+#endif
+
     WebGPUTest::SetUp();
     Initialize(WebGPUTest::Options());
+
     mock_buffer_map_callback =
         std::make_unique<testing::StrictMock<MockBufferMapCallback>>();
     mock_device_error_callback =
@@ -86,6 +105,10 @@
                                ComputeNumEntries(sizeof(cmd) + data_size),
                                &entries_processed);
   }
+
+#if defined(OS_MAC)
+  bool mac_m1_ = false;
+#endif
 };
 
 TEST_F(WebGPUMailboxTest, AssociateMailboxCmd) {
@@ -532,6 +555,12 @@
     return;
   }
 
+#if defined(OS_MAC)
+  // Crashing on Mac M1. Currently missing stack trace. crbug.com/1271926
+  if (mac_m1_)
+    return;
+#endif
+
   // Create a the shared images.
   SharedImageInterface* sii = GetSharedImageInterface();
   Mailbox mailbox_a = sii->CreateSharedImage(
diff --git a/gpu/command_buffer/tests/webgpu_test.cc b/gpu/command_buffer/tests/webgpu_test.cc
index 9b05b63..adef21b2 100644
--- a/gpu/command_buffer/tests/webgpu_test.cc
+++ b/gpu/command_buffer/tests/webgpu_test.cc
@@ -19,6 +19,11 @@
 #include "gpu/ipc/webgpu_in_process_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_MAC)
+#include "gpu/command_buffer/tests/gl_manager.h"
+#include "ui/gl/gl_context.h"
+#endif
+
 namespace gpu {
 
 namespace {
@@ -299,6 +304,20 @@
     return;
   }
 
+#if defined(OS_MAC)
+  // Crashing on Mac M1. Currently missing stack trace. crbug.com/1271926
+  // This must be checked before WebGPUTest::Initialize otherwise context
+  // switched is locked and we cannot temporarily have this GLContext.
+  GLManager gl_manager;
+  gl_manager.Initialize(GLManager::Options());
+  std::string renderer(gl_manager.context()->GetGLRenderer());
+  if (renderer.find("Apple M1") != std::string::npos) {
+    gl_manager.Destroy();
+    return;
+  }
+  gl_manager.Destroy();
+#endif
+
   Initialize(WebGPUTest::Options());
 
   // Create device with unsupported features, expect to fail to create and
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index ec9591b..88b12ff 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -799,12 +799,8 @@
     // Disable robust resource initialization for raster decoder and compositor.
     // TODO(crbug.com/1192632): disable robust_resource_initialization for
     // SwANGLE.
-    // TODO(crbug.com/1116174): Currently disabling robust initialization is
-    // breaking some tests with OOP canvas. Once that's fixed remove check for
-    // kCanvasOopRasterization feature.
     if (gl::GLSurfaceEGL::GetDisplayType() != gl::ANGLE_SWIFTSHADER &&
-        features::IsUsingSkiaRenderer() &&
-        !base::FeatureList::IsEnabled(features::kCanvasOopRasterization)) {
+        features::IsUsingSkiaRenderer()) {
       attribs.robust_resource_initialization = false;
     }
 
diff --git a/headless/test/data/protocol/sanity/universal-network-access-expected.txt b/headless/test/data/protocol/sanity/universal-network-access-expected.txt
new file mode 100644
index 0000000..38d3596
--- /dev/null
+++ b/headless/test/data/protocol/sanity/universal-network-access-expected.txt
@@ -0,0 +1,3 @@
+Tests handling of originsWithUniversalNetworkAccess
+PASS: <html> <body>Page with body</body> </html>
+PASS: request failed
\ No newline at end of file
diff --git a/headless/test/data/protocol/sanity/universal-network-access.js b/headless/test/data/protocol/sanity/universal-network-access.js
new file mode 100644
index 0000000..0e1419e2
--- /dev/null
+++ b/headless/test/data/protocol/sanity/universal-network-access.js
@@ -0,0 +1,36 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function(testRunner) {
+  const resourcePath = 'protocol/sanity/resources/body.html';
+  const port = window.location.port;
+  const privilegedPageURL = `http://site1.test:${port}/${resourcePath}`;
+  const nonprivilegedPageURL = `http://site2.test:${port}/${resourcePath}`;
+  const fetchURL = `http://site3.test:${port}/${resourcePath}`;
+  const options = {
+    createContextOptions: {
+      originsWithUniversalNetworkAccess: [new URL(privilegedPageURL).origin]
+    }
+  }
+  const {page, session, dp} = await testRunner.startURL(
+      privilegedPageURL,
+      'Tests handling of originsWithUniversalNetworkAccess',
+      options);
+
+  const fetchInPrivilegedPage = await session.evaluateAsync(`
+    fetch('${fetchURL}')
+        .then(response => response.text())
+        .then(text => 'PASS: ' + text.replace(/\\s+/mg, ' '))
+        .catch(exception => 'FAIL: ' + exception.toString())
+  `);
+  testRunner.log(fetchInPrivilegedPage);
+  await session.navigate(nonprivilegedPageURL);
+  const fetchInNonPrivilegedPage = await session.evaluateAsync(`
+    fetch('${fetchURL}')
+        .then('FAIL: request succeeded')
+        .catch(exception => 'PASS: request failed')
+  `);
+  testRunner.log(fetchInNonPrivilegedPage);
+  testRunner.completeTest();
+})
diff --git a/headless/test/headless_protocol_browsertest.cc b/headless/test/headless_protocol_browsertest.cc
index 9fd0a98..41d3e790 100644
--- a/headless/test/headless_protocol_browsertest.cc
+++ b/headless/test/headless_protocol_browsertest.cc
@@ -285,6 +285,9 @@
 HEADLESS_PROTOCOL_TEST(BrowserSetInitialProxyConfig,
                        "sanity/browser-set-initial-proxy-config.js")
 
+HEADLESS_PROTOCOL_TEST(BrowserUniversalNetworkAccess,
+                       "sanity/universal-network-access.js")
+
 class HeadlessProtocolBrowserTestWithProxy
     : public HeadlessProtocolBrowserTest {
  public:
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 7e3a9411..309e10e 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -535,7 +535,7 @@
         Search bar is now easier to reach
       </message>
       <message name="IDS_IOS_CAMERA_USAGE_DESCRIPTION" desc="Specifies the reason for accessing the user's camera while the app is in use [Length: unlimited] [iOS only].">
-        This lets you take and upload photos.
+        This lets you take and upload photos, as well as scan QR codes.
       </message>
       <message name="IDS_IOS_CARD_STACK_SCROLLED_NOTIFICATION" desc="The accessibility description for page scrolled notification [iOS only]">
         <ph name="INCOGNITO">$1<ex>Incognito</ex></ph> Tabs <ph name="FIRST_VISIBLE_TAB">$2<ex>3</ex></ph> through <ph name="LAST_VISIBLE_TAB">$3<ex>5</ex></ph> of <ph name="NUMBER_OF_OPEN_TABS">$4<ex>12</ex></ph>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CAMERA_USAGE_DESCRIPTION.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CAMERA_USAGE_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..f60dbaf
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CAMERA_USAGE_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+dbaef238f389d466ee0ce5677a892be2368eaf42
\ No newline at end of file
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 5772095b6..54e122c 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -942,7 +942,6 @@
     [testing_policies addEntriesFromDictionary:@{
       restrict_key : @[ restriction_pattern ]
     }];
-    [allowed_experimental_policies addObject:restrict_key];
   }
 
   // If the sign-in policy is set (not "None"), add the policy key to the list
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index cf351cc8..8fdb73b 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -2691,7 +2691,8 @@
   self.view.backgroundColor = UIColor.clearColor;
 
   CGRect webStateViewFrame = self.contentArea.bounds;
-  if (self.thumbStripPanHandler.currentState == ViewRevealState::Revealed) {
+  if (self.thumbStripPanHandler.currentState == ViewRevealState::Revealed ||
+      self.thumbStripPanHandler.currentState == ViewRevealState::Fullscreen) {
     CGFloat toolbarHeight = [self expandedTopToolbarHeight];
     webStateViewFrame = UIEdgeInsetsInsetRect(
         webStateViewFrame, UIEdgeInsetsMake(toolbarHeight, 0, 0, 0));
@@ -2842,7 +2843,8 @@
   }
 
   // Close all keyboards if the thumb strip is transitioning to the tab grid.
-  if (nextViewRevealState == ViewRevealState::Revealed) {
+  if (nextViewRevealState == ViewRevealState::Revealed ||
+      nextViewRevealState == ViewRevealState::Fullscreen) {
     [self.view endEditing:YES];
   }
 
@@ -2881,6 +2883,7 @@
       }
       break;
     case ViewRevealState::Revealed:
+    case ViewRevealState::Fullscreen:
       self.view.transform = CGAffineTransformMakeTranslation(0, -hideHeight);
       if (!base::FeatureList::IsEnabled(kModernTabStrip)) {
         CGAffineTransform transform =
@@ -2894,7 +2897,8 @@
 
 - (void)didAnimateViewReveal:(ViewRevealState)viewRevealState {
   [self.tabStripSnapshot removeFromSuperview];
-  self.bottomPosition = (viewRevealState == ViewRevealState::Revealed);
+  self.bottomPosition = (viewRevealState == ViewRevealState::Revealed ||
+                         viewRevealState == ViewRevealState::Fullscreen);
 
   if (viewRevealState == ViewRevealState::Hidden) {
     // Stop disabling fullscreen.
diff --git a/ios/chrome/browser/ui/browser_view/hider/browser_view_hider_view_controller.mm b/ios/chrome/browser/ui/browser_view/hider/browser_view_hider_view_controller.mm
index 58d8bd5..009ae31 100644
--- a/ios/chrome/browser/ui/browser_view/hider/browser_view_hider_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/hider/browser_view_hider_view_controller.mm
@@ -109,7 +109,11 @@
 
 - (void)willAnimateViewRevealFromState:(ViewRevealState)currentViewRevealState
                                toState:(ViewRevealState)nextViewRevealState {
-  self.view.alpha = currentViewRevealState == ViewRevealState::Revealed ? 1 : 0;
+  self.view.alpha =
+      currentViewRevealState == ViewRevealState::Revealed ||
+              currentViewRevealState == ViewRevealState::Fullscreen
+          ? 1
+          : 0;
   self.view.hidden = NO;
 }
 
@@ -122,13 +126,15 @@
       self.view.alpha = 0;
       break;
     case ViewRevealState::Revealed:
+    case ViewRevealState::Fullscreen:
       self.view.alpha = 1;
       break;
   }
 }
 
 - (void)didAnimateViewReveal:(ViewRevealState)viewRevealState {
-  self.view.hidden = viewRevealState != ViewRevealState::Revealed;
+  self.view.hidden = viewRevealState != ViewRevealState::Revealed &&
+                     viewRevealState != ViewRevealState::Fullscreen;
 }
 
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
index a57309e6..92be2ca 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
@@ -60,9 +60,6 @@
 // Height for the shrunk logo frame.
 // TODO(crbug.com/1170491): clean up post-launch.
 const CGFloat kGoogleSearchLogoShrunkHeight = 36;
-
-// Height for the doodle frame when Google is not the default search engine.
-const CGFloat kNonGoogleSearchDoodleHeight = 60;
 }
 
 namespace content_suggestions {
@@ -74,8 +71,9 @@
 CGFloat doodleHeight(BOOL logoIsShowing,
                      BOOL doodleIsShowing,
                      UITraitCollection* traitCollection) {
+  // For users with non-Google default search engine, there is no doodle.
   if (!IsRegularXRegularSizeClass(traitCollection) && !logoIsShowing) {
-    return kNonGoogleSearchDoodleHeight;
+    return 0;
   }
 
   if (ShouldShrinkLogoForStartSurface() && logoIsShowing) {
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm
index 815096f1..239ac5c0 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm
@@ -20,6 +20,7 @@
 namespace content_suggestions {
 
 CGFloat kTopInset = 20;
+CGFloat kDoodleHeightNoLogo = 0;
 
 class ContentSuggestionsCollectionUtilsTest : public PlatformTest {
  public:
@@ -73,7 +74,7 @@
 
   // Test.
   EXPECT_EQ(120, heightLogo);
-  EXPECT_EQ(60, heightNoLogo);
+  EXPECT_EQ(kDoodleHeightNoLogo, heightNoLogo);
   EXPECT_EQ(58 + kTopInset, topMargin);
 }
 
@@ -86,7 +87,7 @@
 
   // Test.
   EXPECT_EQ(120, heightLogo);
-  EXPECT_EQ(60, heightNoLogo);
+  EXPECT_EQ(kDoodleHeightNoLogo, heightNoLogo);
   EXPECT_EQ(kTopInset, topMargin);
 }
 
@@ -189,7 +190,7 @@
   CGFloat topMarginLandscape =
       doodleTopMargin(YES, kTopInset, IPhoneLandscapeTraitCollection());
   EXPECT_EQ(68, heightLogoLandscape);
-  EXPECT_EQ(60, heightNoLogoLandscape);
+  EXPECT_EQ(kDoodleHeightNoLogo, heightNoLogoLandscape);
   EXPECT_EQ(78, topMarginLandscape);
 
   // Portrait
@@ -200,7 +201,7 @@
   CGFloat topMarginPortrait =
       doodleTopMargin(YES, kTopInset, IPhonePortraitTraitCollection());
   EXPECT_EQ(68, heightLogoPortrait);
-  EXPECT_EQ(60, heightNoLogoPortrait);
+  EXPECT_EQ(kDoodleHeightNoLogo, heightNoLogoPortrait);
   EXPECT_EQ(95, topMarginPortrait);
 }
 
diff --git a/ios/chrome/browser/ui/gestures/view_revealing_animatee.h b/ios/chrome/browser/ui/gestures/view_revealing_animatee.h
index 2f1eeb19..6a7f8667 100644
--- a/ios/chrome/browser/ui/gestures/view_revealing_animatee.h
+++ b/ios/chrome/browser/ui/gestures/view_revealing_animatee.h
@@ -8,9 +8,10 @@
 // The 3 stages or steps of the transitions handled by the view revealing
 // vertical pan handler class.
 enum class ViewRevealState {
-  Hidden,    // The view is not revealed.
-  Peeked,    // The view is only partially revealed.
-  Revealed,  // The view is completely revealed.
+  Hidden,      // The view is not revealed.
+  Peeked,      // The view is only partially revealed.
+  Revealed,    // The view is mostly revealed.
+  Fullscreen,  // The view is fully revealed - under software control only.
 };
 
 // Protocol defining an interface to handle animations from the view revealing
diff --git a/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.mm b/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.mm
index 8c684bd..c26a6a1 100644
--- a/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.mm
+++ b/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.mm
@@ -64,8 +64,7 @@
 // The progress of the animator.
 @property(nonatomic, assign) CGFloat progressWhenInterrupted;
 // Set of UI elements which are animated during view reveal transitions.
-@property(nonatomic, strong)
-    NSMutableOrderedSet<id<ViewRevealingAnimatee>>* animatees;
+@property(nonatomic, strong) NSHashTable<id<ViewRevealingAnimatee>>* animatees;
 // The current state tracking whether the revealed view is undergoing a
 // transition of layout. This is |::Inactive| initially. It is set to |::Active|
 // when the transition layout is created.  It is set to |::Finishing| when the
@@ -106,7 +105,7 @@
     _revealedHeight = baseViewHeight - revealedCoverHeight;
     _remainingHeight = _revealedHeight - peekedHeight;
     _currentState = initialState;
-    _animatees = [[NSMutableOrderedSet alloc] init];
+    _animatees = [NSHashTable weakObjectsHashTable];
     _layoutTransitionState = LayoutTransitionState::Inactive;
   }
   return self;
@@ -250,9 +249,11 @@
     return;
   }
 
-  if (self.nextState == ViewRevealState::Revealed) {
+  if (self.nextState == ViewRevealState::Revealed ||
+      self.nextState == ViewRevealState::Fullscreen) {
     [self willTransitionToLayout:LayoutSwitcherState::Grid];
-  } else if (self.currentState == ViewRevealState::Revealed &&
+  } else if ((self.currentState == ViewRevealState::Revealed ||
+              self.currentState == ViewRevealState::Fullscreen) &&
              (self.nextState == ViewRevealState::Peeked ||
               self.nextState == ViewRevealState::Hidden)) {
     [self willTransitionToLayout:LayoutSwitcherState::Horizontal];
@@ -377,6 +378,9 @@
         return ViewRevealState::Revealed;
       }
       return self.currentState;
+    case ViewRevealState::Fullscreen:
+      NOTREACHED();
+      return ViewRevealState::Fullscreen;
   }
 }
 
@@ -398,6 +402,9 @@
     case ViewRevealState::Revealed:
       progress = translation / (-self.remainingHeight);
       break;
+    case ViewRevealState::Fullscreen:
+      progress = translation / (self.baseViewHeight - self.revealedHeight);
+      break;
   }
 
   progress += self.progressWhenInterrupted;
@@ -535,6 +542,7 @@
       break;
     }
     case ViewRevealState::Revealed:
+    case ViewRevealState::Fullscreen:
       // The scroll views should be covered in Revealed state, so should not
       // be able to be scrolled.
       NOTREACHED();
diff --git a/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler_unittest.mm b/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler_unittest.mm
index 54fb6274..b194f7f 100644
--- a/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler_unittest.mm
+++ b/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler_unittest.mm
@@ -235,6 +235,19 @@
   [pan_handler setNextState:ViewRevealState::Hidden animated:NO];
   EXPECT_EQ(ViewRevealState::Hidden, fake_animatee.state);
   EXPECT_EQ(LayoutSwitcherState::Horizontal, fake_layout_switcher.state);
+
+  // Now try with going Fullscreen and back to Hidden.
+  [pan_handler setNextState:ViewRevealState::Revealed animated:NO];
+  EXPECT_EQ(ViewRevealState::Revealed, fake_animatee.state);
+  EXPECT_EQ(LayoutSwitcherState::Grid, fake_layout_switcher.state);
+
+  [pan_handler setNextState:ViewRevealState::Fullscreen animated:NO];
+  EXPECT_EQ(ViewRevealState::Fullscreen, fake_animatee.state);
+  EXPECT_EQ(LayoutSwitcherState::Grid, fake_layout_switcher.state);
+
+  [pan_handler setNextState:ViewRevealState::Hidden animated:NO];
+  EXPECT_EQ(ViewRevealState::Hidden, fake_animatee.state);
+  EXPECT_EQ(LayoutSwitcherState::Horizontal, fake_layout_switcher.state);
 }
 
 // Tests that a second gesture does not interrupt the first gesture.
diff --git a/ios/chrome/browser/ui/main/bvc_container_view_controller.mm b/ios/chrome/browser/ui/main/bvc_container_view_controller.mm
index 04aa0126..987eb5e 100644
--- a/ios/chrome/browser/ui/main/bvc_container_view_controller.mm
+++ b/ios/chrome/browser/ui/main/bvc_container_view_controller.mm
@@ -113,6 +113,10 @@
     if (self.thumbStripPanHandler.currentState == ViewRevealState::Revealed) {
       self.view.transform = CGAffineTransformMakeTranslation(
           0, self.thumbStripPanHandler.revealedHeight);
+    } else if (self.thumbStripPanHandler.currentState ==
+               ViewRevealState::Fullscreen) {
+      self.view.transform = CGAffineTransformMakeTranslation(
+          0, self.thumbStripPanHandler.baseViewHeight);
     }
   }
 }
@@ -157,6 +161,10 @@
       self.view.transform = CGAffineTransformMakeTranslation(
           0, self.thumbStripPanHandler.revealedHeight);
       break;
+    case ViewRevealState::Fullscreen:
+      self.view.transform = CGAffineTransformMakeTranslation(
+          0, self.thumbStripPanHandler.baseViewHeight);
+      break;
   }
 }
 
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_unittest.mm b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_unittest.mm
index 1da48d7..66c38d5 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_unittest.mm
@@ -6,6 +6,7 @@
 
 #include "base/strings/sys_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
@@ -64,7 +65,8 @@
                        cardNumber:@"4111111111111112"  // This is invalid
                                                        // Card number.
                   expirationMonth:@"11"
-                   expirationYear:@"2030"
+                   expirationYear:base::SysUTF8ToNSString(
+                                      autofill::test::NextYear())
                      cardNickname:@""];
 
   waiter.Wait();  // Wait for completion of the asynchronous operation.
@@ -93,7 +95,8 @@
       addCreditCardWithHolderName:@"Test"
                        cardNumber:@"4111111111111111"
                   expirationMonth:@"15"  // This is invalid month.
-                   expirationYear:@"2030"
+                   expirationYear:base::SysUTF8ToNSString(
+                                      autofill::test::NextYear())
                      cardNickname:@""];
 
   waiter.Wait();  // Wait for completion of the asynchronous operation.
@@ -120,7 +123,9 @@
       addCreditCardWithHolderName:@"Test"
                        cardNumber:@"4111111111111111"
                   expirationMonth:@"11"
-                   expirationYear:@"2010"  // This is invalid year.
+                   expirationYear:
+                       base::SysUTF8ToNSString(
+                           autofill::test::LastYear())  // This is invalid year.
                      cardNickname:@""];
 
   waiter.Wait();  // Wait for completion of the asynchronous operation.
@@ -148,7 +153,8 @@
       addCreditCardWithHolderName:@"Test"
                        cardNumber:@"4111111111111111"
                   expirationMonth:@"11"
-                   expirationYear:@"2030"
+                   expirationYear:base::SysUTF8ToNSString(
+                                      autofill::test::NextYear())
                      cardNickname:@"cvc123"];  // This is an invalid nickname.
 
   waiter.Wait();  // Wait for completion of the asynchronous operation.
@@ -170,12 +176,14 @@
   OCMExpect([add_credit_card_mediator_delegate_mock_
       creditCardMediatorDidFinish:[OCMArg any]]);
 
-  [add_credit_card_mediator_ addCreditCardViewController:nil
-                             addCreditCardWithHolderName:@"Test"
-                                              cardNumber:@"4111111111111111"
-                                         expirationMonth:@"11"
-                                          expirationYear:@"2030"
-                                            cardNickname:@"nickname"];
+  [add_credit_card_mediator_
+      addCreditCardViewController:nil
+      addCreditCardWithHolderName:@"Test"
+                       cardNumber:@"4111111111111111"
+                  expirationMonth:@"11"
+                   expirationYear:base::SysUTF8ToNSString(
+                                      autofill::test::NextYear())
+                     cardNickname:@"nickname"];
 
   waiter.Wait();  // Wait for completion of the asynchronous operation.
 
@@ -196,11 +204,12 @@
   OCMExpect([add_credit_card_mediator_delegate_mock_
       creditCardMediatorDidFinish:[OCMArg any]]);
 
+  NSString* year = base::SysUTF8ToNSString(autofill::test::NextYear());
   [add_credit_card_mediator_ addCreditCardViewController:nil
                              addCreditCardWithHolderName:@"Test2"
                                               cardNumber:@"4111111111111111"
                                          expirationMonth:@"12"
-                                          expirationYear:@"2030"
+                                          expirationYear:year
                                             cardNickname:@"nickname"];
 
   waiter.Wait();  // Wait for completion of the asynchronous operation.
@@ -223,7 +232,7 @@
             base::SysNSStringToUTF16(@"12"));
 
   EXPECT_EQ(savedCreditCard->Expiration4DigitYearAsString(),
-            base::SysNSStringToUTF16(@"2030"));
+            base::SysNSStringToUTF16(year));
 
   EXPECT_TRUE(savedCreditCard->HasNonEmptyValidNickname());
 
diff --git a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/BUILD.gn b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/BUILD.gn
index 2961445..4797231 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/BUILD.gn
@@ -15,6 +15,7 @@
     "//base",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/settings/utils",
+    "//ios/public/provider/chrome/browser/password_auto_fill:password_auto_fill_api",
   ]
 }
 
@@ -41,6 +42,7 @@
     "//ios/chrome/common",
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/util",
+    "//ios/public/provider/chrome/browser/password_auto_fill:password_auto_fill_api",
     "//ui/base",
   ]
 }
diff --git a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_mediator.mm b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_mediator.mm
index 4cfa07f1..5147f2ed 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_mediator.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_mediator.mm
@@ -8,6 +8,7 @@
 
 #include "base/check.h"
 #import "ios/chrome/browser/ui/settings/utils/password_auto_fill_status_manager.h"
+#import "ios/public/provider/chrome/browser/password_auto_fill/password_auto_fill_api.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -39,11 +40,7 @@
 #pragma mark - PasswordsInOtherAppsViewControllerDelegate
 
 - (void)openApplicationSettings {
-  // TODO(crbug.com/1269843): The current URL used is a placeholder.
-  [[UIApplication sharedApplication]
-                openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]
-                options:@{}
-      completionHandler:nil];
+  ios::provider::PasswordsInOtherAppsOpensSettings();
 }
 
 @end
diff --git a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_view_controller.mm b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_view_controller.mm
index 1273b03..634d87d 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_in_other_apps/passwords_in_other_apps_view_controller.mm
@@ -18,6 +18,7 @@
 #import "ios/chrome/common/ui/util/pointer_interaction_util.h"
 #include "ios/chrome/grit/ios_google_chrome_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
+#import "ios/public/provider/chrome/browser/password_auto_fill/password_auto_fill_api.h"
 #import "ui/base/device_form_factor.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -38,11 +39,10 @@
 @interface PasswordsInOtherAppsViewController ()
 
 // Properties set on initialization.
-@property(nonatomic, copy) NSString* titleText;
-@property(nonatomic, copy) NSString* subtitleText;
-@property(nonatomic, strong) UIImage* bannerImage;
-@property(nonatomic, copy) NSString* actionString;
-@property(nonatomic, strong) NSArray<NSString*>* steps;
+@property(nonatomic, copy, readonly) NSString* titleText;
+@property(nonatomic, copy, readonly) NSString* subtitleText;
+@property(nonatomic, strong, readonly) UIImage* bannerImage;
+@property(nonatomic, copy, readonly) NSString* actionString;
 
 // Visible UI components.
 @property(nonatomic, strong) UIImageView* imageView;
@@ -59,6 +59,8 @@
 @property(nonatomic, strong) UIView* specificContentView;
 
 // Helper properties.
+@property(nonatomic, assign, readonly) BOOL useShortInstruction;
+@property(nonatomic, strong, readonly) NSArray<NSString*>* steps;
 @property(nonatomic, strong)
     NSArray<NSLayoutConstraint*>* turnOnInstructionViewConstraints;
 @property(nonatomic, strong)
@@ -83,27 +85,6 @@
     _bannerImage =
         [UIImage imageNamed:@"settings_passwords_in_other_apps_banner"];
     _actionString = l10n_util::GetNSString(IDS_IOS_OPEN_SETTINGS);
-
-    NSArray<NSString*>* shortInstruction = @[
-      l10n_util::GetNSString(
-          IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_SHORTENED_STEP_1),
-      l10n_util::GetNSString(
-          IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_SHORTENED_STEP_2)
-    ];
-    NSArray<NSString*>* longInstruction = @[
-      ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET
-          ? l10n_util::GetNSString(
-                IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_1_IPAD)
-          : l10n_util::GetNSString(
-                IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_1_IPHONE),
-      l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_2),
-      l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_3),
-      l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_4)
-    ];
-    _steps = base::FeatureList::IsEnabled(
-                 kEnableShortenedPasswordAutoFillInstruction)
-                 ? shortInstruction
-                 : longInstruction;
   }
   return self;
 }
@@ -433,10 +414,8 @@
 - (UIView*)turnOnInstructionView {
   if (!_turnOnInstructionView) {
     UIImage* icon = [UIImage imageNamed:@"settings"];
-    NSArray<UIImage*>* icons = base::FeatureList::IsEnabled(
-                                   kEnableShortenedPasswordAutoFillInstruction)
-                                   ? nil
-                                   : @[ icon, icon, icon, icon ];
+    NSArray<UIImage*>* icons =
+        self.useShortInstruction ? nil : @[ icon, icon, icon, icon ];
     InstructionView* instruction =
         [[InstructionView alloc] initWithList:self.steps
                                         style:InstructionViewStyleGrayscale
@@ -493,8 +472,7 @@
     // if the view will contain an action button, place action button at the
     // bottom and instruction right above it; otherwise, place the instruction
     // at the bottom.
-    if (base::FeatureList::IsEnabled(
-            kEnableShortenedPasswordAutoFillInstruction)) {
+    if (self.useShortInstruction) {
       [_turnOnInstructionView addSubview:self.actionButton];
       [constraints addObjectsFromArray:@[
         [self.actionButton.widthAnchor
@@ -598,6 +576,33 @@
   }
 }
 
+- (BOOL)useShortInstruction {
+  return ios::provider::SupportShortenedInstructionForPasswordAutoFill() &&
+         base::FeatureList::IsEnabled(
+             kEnableShortenedPasswordAutoFillInstruction);
+}
+
+- (NSArray<NSString*>*)steps {
+  if (self.useShortInstruction) {
+    return @[
+      l10n_util::GetNSString(
+          IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_SHORTENED_STEP_1),
+      l10n_util::GetNSString(
+          IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_SHORTENED_STEP_2)
+    ];
+  }
+  return @[
+    ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET
+        ? l10n_util::GetNSString(
+              IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_1_IPAD)
+        : l10n_util::GetNSString(
+              IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_1_IPHONE),
+    l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_2),
+    l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_3),
+    l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_IN_OTHER_APPS_STEP_4)
+  ];
+}
+
 #pragma mark - UITextViewDelegate
 
 - (BOOL)textView:(UITextView*)textView
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.h
index 5540c89..bd38a4b 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.h
@@ -41,12 +41,17 @@
 @property(nonatomic, copy) NSString* title;
 @property(nonatomic, assign) BOOL titleHidden;
 @property(nonatomic, readonly) UIDragPreviewParameters* dragPreviewParameters;
+// Sets to update and keep cell alpha in sync.
+@property(nonatomic, assign) CGFloat opacity;
 // The current state which the cell should display.
 @property(nonatomic, assign) GridCellState state;
 @property(nonatomic, weak) PriceCardView* priceCardView;
 
 // Sets the price drop and displays the PriceViewCard.
 - (void)setPriceDrop:(NSString*)price previousPrice:(NSString*)previousPrice;
+
+// Fade in a new snapshot.
+- (void)fadeInSnapshot:(UIImage*)snapshot;
 @end
 
 // A GridCell for use in animated transitions that only shows selection state
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.mm
index 6ec5043..a7de53f 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.mm
@@ -118,6 +118,7 @@
     _snapshotView = snapshotView;
     _closeTapTargetButton = closeTapTargetButton;
     _priceCardView = priceCardView;
+    _opacity = 1.0;
 
     self.contentView.backgroundColor = [UIColor colorNamed:kBackgroundColor];
     self.snapshotView.backgroundColor = [UIColor colorNamed:kBackgroundColor];
@@ -160,7 +161,11 @@
                            constant:kGridCellPriceDropTopSpacing],
         [priceCardView.leadingAnchor
             constraintEqualToAnchor:snapshotView.leadingAnchor
-                           constant:kGridCellPriceDropLeadingSpacing]
+                           constant:kGridCellPriceDropLeadingSpacing],
+        [priceCardView.trailingAnchor
+            constraintLessThanOrEqualToAnchor:snapshotView.trailingAnchor
+                                     constant:-
+                                              kGridCellPriceDropTrailingSpacing]
       ]];
     }
     [NSLayoutConstraint activateConstraints:constraints];
@@ -198,6 +203,7 @@
   self.snapshot = nil;
   self.selected = NO;
   self.priceCardView.hidden = YES;
+  self.opacity = 1.0;
 }
 
 #pragma mark - UIAccessibility
@@ -264,6 +270,17 @@
   _snapshot = snapshot;
 }
 
+- (void)fadeInSnapshot:(UIImage*)snapshot {
+  [UIView transitionWithView:self.snapshotView
+                    duration:0.2f
+                     options:UIViewAnimationOptionTransitionCrossDissolve
+                  animations:^{
+                    self.snapshotView.image = snapshot;
+                  }
+                  completion:nil];
+  _snapshot = snapshot;
+}
+
 - (void)setPriceDrop:(NSString*)price previousPrice:(NSString*)previousPrice {
   [self.priceCardView setPriceDrop:price previousPrice:previousPrice];
   // Only append PriceCardView accessibility text if it doesn't already exist in
@@ -297,6 +314,16 @@
   return params;
 }
 
+- (void)setOpacity:(CGFloat)opacity {
+  _opacity = opacity;
+  self.alpha = opacity;
+}
+
+- (void)setAlpha:(CGFloat)alpha {
+  // Make sure alpha is synchronized with opacity.
+  super.alpha = _opacity;
+}
+
 #pragma mark - Private
 
 // Sets up the top bar with icon, title, and close button.
@@ -552,6 +579,7 @@
   proxy.selected = YES;
   proxy.theme = cell.theme;
   proxy.contentView.hidden = YES;
+  proxy.opacity = cell.opacity;
   return proxy;
 }
 
@@ -576,6 +604,7 @@
   proxy.title = cell.title;
   proxy.titleHidden = cell.titleHidden;
   proxy.priceCardView = cell.priceCardView;
+  proxy.opacity = cell.opacity;
   return proxy;
 }
 #pragma mark - GridToTabTransitionView properties.
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h
index 2ebc9bb6..461cb8c7 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h
@@ -97,6 +97,7 @@
 // PriceCardView constants
 extern const CGFloat kGridCellPriceDropTopSpacing;
 extern const CGFloat kGridCellPriceDropLeadingSpacing;
+extern const CGFloat kGridCellPriceDropTrailingSpacing;
 
 // Horizontal distance from the center of the plus sign image to the trailing of
 // the tab grid.
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.mm
index c31af73..f371561 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.mm
@@ -90,6 +90,7 @@
 
 const CGFloat kGridCellPriceDropTopSpacing = 10.0f;
 const CGFloat kGridCellPriceDropLeadingSpacing = 10.0f;
+const CGFloat kGridCellPriceDropTrailingSpacing = 10.0f;
 
 const CGFloat kPlusSignImageTrailingCenterDistance = 55.5;
 // The threshold is set so that the hide transition starts at the moment the
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.h
index bae9ae48..d224f76 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.h
@@ -127,6 +127,9 @@
 // TabGridModeSelection.
 @property(nonatomic, readonly) BOOL allItemsSelectedForEditing;
 
+// Opacity of grid cells that are not the selected tab.
+@property(nonatomic, assign) CGFloat notSelectedTabCellOpacity;
+
 // Returns the layout of the grid for use in an animated transition.
 - (GridTransitionLayout*)transitionLayout;
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm
index f74fcb5..76a0a31 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm
@@ -140,6 +140,7 @@
     _selectedEditingItemIDs = [[NSMutableSet<NSString*> alloc] init];
     _selectedSharableEditingItemIDs = [[NSMutableSet<NSString*> alloc] init];
     _showsSelectionUpdates = YES;
+    _notSelectedTabCellOpacity = 1.0;
     _mode = TabGridModeNormal;
   }
   return self;
@@ -759,6 +760,7 @@
     self.selectedItemID = selectedItemID;
     self.lastInsertedItemID = item.identifier;
     [self.delegate gridViewController:self didChangeItemCount:self.items.count];
+    [self updateVisibleCellsOpacity];
   };
   auto collectionViewUpdates = ^{
     [self removeEmptyStateAnimated:YES];
@@ -800,6 +802,7 @@
     self.selectedItemID = selectedItemID;
     [self deselectItemWithIDForEditing:removedItemID];
     [self.delegate gridViewController:self didChangeItemCount:self.items.count];
+    [self updateVisibleCellsOpacity];
   };
   auto collectionViewUpdates = ^{
     [self.collectionView deleteItemsAtIndexPaths:@[ CreateIndexPath(index) ]];
@@ -838,6 +841,7 @@
       selectItemAtIndexPath:CreateIndexPath(self.selectedIndex)
                    animated:YES
              scrollPosition:UICollectionViewScrollPositionNone];
+  [self updateVisibleCellsOpacity];
 }
 
 - (void)replaceItemID:(NSString*)itemID withItem:(TabSwitcherItem*)item {
@@ -1075,8 +1079,14 @@
                                    completion:^(UIImage* snapshot) {
                                      // Only update the icon if the cell is not
                                      // already reused for another item.
-                                     if (cell.itemIdentifier == itemIdentifier)
-                                       cell.snapshot = snapshot;
+                                     if (cell.itemIdentifier ==
+                                         itemIdentifier) {
+                                       if (self.thumbStripEnabled) {
+                                         [cell fadeInSnapshot:snapshot];
+                                       } else {
+                                         cell.snapshot = snapshot;
+                                       }
+                                     }
                                    }];
   if (IsPriceAlertsEnabled()) {
     [self.priceCardDataSource
@@ -1088,6 +1098,11 @@
                              previousPrice:priceCardItem.previousPrice];
                     }];
   }
+  if (self.thumbStripEnabled && item.identifier != self.selectedItemID) {
+    cell.opacity = self.notSelectedTabCellOpacity;
+  } else {
+    cell.opacity = 1.0f;
+  }
 }
 
 // Tells the delegate that the user tapped the item with identifier
@@ -1205,6 +1220,33 @@
   }
 }
 
+// Setter for the not selected tab opacity. This can be used inside an
+// animation block.
+- (void)setNotSelectedTabCellOpacity:(CGFloat)opacity {
+  _notSelectedTabCellOpacity = opacity;
+  [self updateVisibleCellsOpacity];
+}
+
+// Update visible cells opacity. When thumbstrip is not enabled, all are 1.0.
+// Otherwise not selected tab are |self.notSelectedTabCellOpacity|.
+- (void)updateVisibleCellsOpacity {
+  if (!self.thumbStripEnabled) {
+    return;
+  }
+  for (NSIndexPath* indexPath in self.collectionView
+           .indexPathsForVisibleItems) {
+    if ([self isIndexPathForPlusSignCell:indexPath])
+      continue;
+    GridCell* cell = base::mac::ObjCCastStrict<GridCell>(
+        [self.collectionView cellForItemAtIndexPath:indexPath]);
+    if (cell.itemIdentifier != self.selectedItemID) {
+      cell.opacity = self.notSelectedTabCellOpacity;
+    } else {
+      cell.opacity = 1.0f;
+    }
+  }
+}
+
 #pragma mark - Public Editing Mode Selection
 - (void)selectAllItemsForEditing {
   if (_mode != TabGridModeSelection) {
@@ -1283,7 +1325,8 @@
         addGestureRecognizer:self.thumbStripDismissRecognizer];
   }
 
-  if (panHandler.currentState == ViewRevealState::Revealed) {
+  if (panHandler.currentState == ViewRevealState::Revealed ||
+      panHandler.currentState == ViewRevealState::Fullscreen) {
     self.thumbStripDismissRecognizer.enabled = NO;
     collectionView.collectionViewLayout = self.gridLayout;
     self.currentLayout = self.gridLayout;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
index e3aa499..5bd3081 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
@@ -261,6 +261,7 @@
   // A modal may be presented on top of the Recent Tabs or tab grid.
   [self.baseViewController dismissModals];
   self.baseViewController.tabGridMode = TabGridModeNormal;
+  [self showFullscreen:NO];
 
   [self dismissPopovers];
 
@@ -292,8 +293,10 @@
 
 - (BOOL)isTabGridActive {
   if (self.isThumbStripEnabled) {
-    return self.thumbStripCoordinator.panHandler.currentState ==
-           ViewRevealState::Revealed;
+    ViewRevealState currentState =
+        self.thumbStripCoordinator.panHandler.currentState;
+    return currentState == ViewRevealState::Revealed ||
+           currentState == ViewRevealState::Fullscreen;
   }
   return self.bvcContainer == nil && !self.firstPresentation;
 }
@@ -896,6 +899,20 @@
   [handler openURLInNewTab:[OpenNewTabCommand commandWithURLFromChrome:URL]];
 }
 
+- (void)showFullscreen:(BOOL)fullscreen {
+  if (![self isThumbStripEnabled]) {
+    return;
+  }
+  ViewRevealingVerticalPanHandler* panHandler =
+      self.thumbStripCoordinator.panHandler;
+  if (fullscreen && panHandler.currentState == ViewRevealState::Revealed) {
+    [panHandler setNextState:ViewRevealState::Fullscreen animated:YES];
+  } else if (!fullscreen &&
+             panHandler.currentState == ViewRevealState::Fullscreen) {
+    [panHandler setNextState:ViewRevealState::Revealed animated:YES];
+  }
+}
+
 #pragma mark - RecentTabsPresentationDelegate
 
 - (void)showHistoryFromRecentTabs {
@@ -1012,6 +1029,7 @@
   base::RecordAction(
       base::UserMetricsAction("MobileTabGridTabContextMenuSelectTabs"));
   self.baseViewController.tabGridMode = TabGridModeSelection;
+  [self showFullscreen:YES];
 }
 
 - (void)removeSessionAtTableSectionWithIdentifier:(NSInteger)sectionIdentifier {
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.h
index 5fcac78..074f5dd 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.h
@@ -70,6 +70,10 @@
 // Opens a link when the user clicks on the in-text link.
 - (void)openLinkWithURL:(const GURL&)URL;
 
+// YES to go fullscreen by hiding the thumbstrip bottom fake tab. NO to bring it
+// back.
+- (void)showFullscreen:(BOOL)fullscreen;
+
 @end
 
 // View controller representing a tab switcher. The tab switcher has an
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
index 0a5e9ae..9ceb776 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
@@ -54,6 +54,9 @@
 #endif
 
 namespace {
+// Not selected tabs opacity in thumbstrip.
+const CGFloat kNotSelectedTabsOpacity = 0.8f;
+
 // Types of configurations of this view controller.
 typedef NS_ENUM(NSUInteger, TabGridConfiguration) {
   TabGridConfigurationBottomToolbar = 1,
@@ -682,6 +685,11 @@
                                toState:(ViewRevealState)nextViewRevealState {
   self.currentState = currentViewRevealState;
   self.scrollView.scrollEnabled = NO;
+  [self updateNotSelectedTabCellOpacityForState:currentViewRevealState];
+  if (nextViewRevealState != ViewRevealState::Fullscreen) {
+    // Reset tag grid mode, unless the grid is fullscreen.
+    self.tabGridMode = TabGridModeNormal;
+  }
   switch (currentViewRevealState) {
     case ViewRevealState::Hidden: {
       // If the tab grid is just showing up, make sure that the active page is
@@ -711,12 +719,14 @@
     case ViewRevealState::Peeked:
       break;
     case ViewRevealState::Revealed:
+    case ViewRevealState::Fullscreen:
       self.plusSignButton.alpha = 0;
       break;
   }
 }
 
 - (void)animateViewReveal:(ViewRevealState)nextViewRevealState {
+  [self updateNotSelectedTabCellOpacityForState:nextViewRevealState];
   GridViewController* regularViewController =
       [self gridViewControllerForPage:TabGridPageRegularTabs];
   GridViewController* incognitoViewController =
@@ -753,7 +763,8 @@
                                                 .fractionVisibleOfLastItem];
       break;
     }
-    case ViewRevealState::Revealed: {
+    case ViewRevealState::Revealed:
+    case ViewRevealState::Fullscreen: {
       self.foregroundView.alpha = 0;
       self.topToolbar.transform = CGAffineTransformIdentity;
       regularViewController.gridView.transform =
@@ -770,6 +781,7 @@
 }
 
 - (void)didAnimateViewReveal:(ViewRevealState)viewRevealState {
+  [self updateNotSelectedTabCellOpacityForState:viewRevealState];
   self.currentState = viewRevealState;
   switch (viewRevealState) {
     case ViewRevealState::Hidden:
@@ -779,12 +791,34 @@
       // No-op.
       break;
     case ViewRevealState::Revealed:
+    case ViewRevealState::Fullscreen:
       self.scrollView.scrollEnabled = YES;
       [self setInsetForRemoteTabs];
       break;
   }
 }
 
+// Sets the expected opacity level for each view revealing state.
+- (void)updateNotSelectedTabCellOpacityForState:(ViewRevealState)state {
+  GridViewController* regularViewController =
+      [self gridViewControllerForPage:TabGridPageRegularTabs];
+  GridViewController* incognitoViewController =
+      [self gridViewControllerForPage:TabGridPageIncognitoTabs];
+  switch (state) {
+    case ViewRevealState::Hidden:
+    case ViewRevealState::Peeked:
+      regularViewController.notSelectedTabCellOpacity = kNotSelectedTabsOpacity;
+      incognitoViewController.notSelectedTabCellOpacity =
+          kNotSelectedTabsOpacity;
+      break;
+    case ViewRevealState::Revealed:
+    case ViewRevealState::Fullscreen:
+      regularViewController.notSelectedTabCellOpacity = 1.0f;
+      incognitoViewController.notSelectedTabCellOpacity = 1.0f;
+      break;
+  }
+}
+
 #pragma mark - Private
 
 // Hides the thumb strip's plus sign button by translating it away and making it
@@ -1831,8 +1865,10 @@
         didChangeItemCount:(NSUInteger)count {
   if (self.tabGridMode == TabGridModeSelection) {
     // Exit selection mode if there are no more tabs.
-    if (count == 0)
+    if (count == 0) {
       self.tabGridMode = TabGridModeNormal;
+      [self.delegate showFullscreen:NO];
+    }
     [self updateSelectionModeToolbars];
   }
 
@@ -1908,6 +1944,7 @@
   // mode.
   if (self.tabGridMode == TabGridModeSelection) {
     self.tabGridMode = TabGridModeNormal;
+    [self.delegate showFullscreen:NO];
     // Records action when user exit the selection mode.
     base::RecordAction(base::UserMetricsAction("MobileTabGridSelectionDone"));
     return;
@@ -1933,6 +1970,7 @@
 
 - (void)selectTabsButtonTapped:(id)sender {
   self.tabGridMode = TabGridModeSelection;
+  [self.delegate showFullscreen:YES];
   base::RecordAction(base::UserMetricsAction("MobileTabGridSelectTabs"));
 }
 
@@ -2114,6 +2152,7 @@
     didUpdateAuthenticationRequirement:(BOOL)isRequired {
   if (isRequired) {
     self.tabGridMode = TabGridModeNormal;
+    [self.delegate showFullscreen:NO];
   }
 }
 
diff --git a/ios/chrome/browser/ui/thumb_strip/thumb_strip_mediator.mm b/ios/chrome/browser/ui/thumb_strip/thumb_strip_mediator.mm
index c38be7fe..42debb4 100644
--- a/ios/chrome/browser/ui/thumb_strip/thumb_strip_mediator.mm
+++ b/ios/chrome/browser/ui/thumb_strip/thumb_strip_mediator.mm
@@ -154,7 +154,8 @@
 
 - (void)willAnimateViewRevealFromState:(ViewRevealState)currentViewRevealState
                                toState:(ViewRevealState)nextViewRevealState {
-  if (nextViewRevealState == ViewRevealState::Revealed) {
+  if (nextViewRevealState == ViewRevealState::Revealed ||
+      nextViewRevealState == ViewRevealState::Fullscreen) {
     self.regularOverlayPresentationContext->SetUIDisabled(true);
     if (self.incognitoOverlayPresentationContext) {
       self.incognitoOverlayPresentationContext->SetUIDisabled(true);
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc
index 65d84d5..affaa55 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.cc
+++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -75,7 +75,7 @@
 
 const base::Feature kEnableShortenedPasswordAutoFillInstruction{
     "EnableShortenedPasswordAutoFillInstruction",
-    base::FEATURE_DISABLED_BY_DEFAULT};
+    base::FEATURE_ENABLED_BY_DEFAULT};
 
 bool IsContextMenuActionsRefreshEnabled() {
   return base::FeatureList::IsEnabled(kContextMenuActionsRefresh);
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 1269b467..a7575e8 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-e8dac9ffd91084624d559f5fe177d4b06f23eee9
\ No newline at end of file
+427c387d0ac06df49291ba6940297407ab95a99b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 87fde24..19cb7fb 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-d1b07f28175e9585551bc569ad4dadd70041ec43
\ No newline at end of file
+57b0ae9c0d7f939a78ee3624e9eef8f423b957ef
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index b0691b9..c6e27660 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-6e4b73a34437bd9358edf6b0185d8f6f10a1632d
\ No newline at end of file
+fdac7bdb87c95cb5593f627b8ab3dc2c3ed12248
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index 3e2f5ff..81c41de 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-9d298ae0267f8a533f975c27c31f5b9a7fb7a7a8
\ No newline at end of file
+9a40ef885221158dc78fbed59aa1cf313f5f7dbf
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
index bb3c2177..0dfab268 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-d0f13a96ae528b85783e001b82be8b27f3bbd107
\ No newline at end of file
+894b44b2434abdc06bc537e7780561d070d5ceb8
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
index f4b00f5..48631acb 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-e957391a82885c99d392eadf4e0859c982e280c8
\ No newline at end of file
+2568a09ddce5eeaf7ea09ba8f3808f73f0270efa
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index c9e4a70..99ff9ac 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-60f355cfd35b1af0bf7c1a73224c2b144e1c800b
\ No newline at end of file
+ef08127a8425f3d23b16cec28b33e7783ff1009d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 63ff913e..a6924084 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-82bd1bde09f630d8f379811fa0eaa81e69b116f1
\ No newline at end of file
+cce7713ac8f52cc30b4306e7e6e35c029496f4bc
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 1a669bb4..72ca18ed 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-826d8e147c7b1bfce295b132eaa8763221738e89
\ No newline at end of file
+e0307feb92ad91f5aa02e190525740d11887c007
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index e4e04c7..609e605 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-bac6df57a087e2692a151f1255b26387ced22a34
\ No newline at end of file
+f546874447dd76d4d265965392e2faab1dae3b38
\ No newline at end of file
diff --git a/ios/public/provider/chrome/browser/password_auto_fill/BUILD.gn b/ios/public/provider/chrome/browser/password_auto_fill/BUILD.gn
index 014c8fdf..1755e23 100644
--- a/ios/public/provider/chrome/browser/password_auto_fill/BUILD.gn
+++ b/ios/public/provider/chrome/browser/password_auto_fill/BUILD.gn
@@ -9,7 +9,6 @@
 }
 
 source_set("test_password_auto_fill") {
-  testonly = true
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [ "test_password_auto_fill.mm" ]
   deps = [ ":password_auto_fill_api" ]
diff --git a/media/base/win/dxgi_device_manager.cc b/media/base/win/dxgi_device_manager.cc
index 921669b..9f2f2a5 100644
--- a/media/base/win/dxgi_device_manager.cc
+++ b/media/base/win/dxgi_device_manager.cc
@@ -5,8 +5,11 @@
 #include "media/base/win/dxgi_device_manager.h"
 
 #include <mfcaptureengine.h>
+#include <mferror.h>
 #include <mfreadwrite.h>
 
+#include "base/check.h"
+#include "base/logging.h"
 #include "base/win/windows_version.h"
 #include "media/base/win/mf_helpers.h"
 
@@ -71,7 +74,10 @@
   RETURN_ON_HR_FAILURE(hr, "Failed to create MF DXGI device manager", nullptr);
   auto dxgi_device_manager = base::WrapRefCounted(new DXGIDeviceManager(
       std::move(mf_dxgi_device_manager), d3d_device_reset_token));
-  if (dxgi_device_manager && FAILED(dxgi_device_manager->ResetDevice())) {
+
+  Microsoft::WRL::ComPtr<ID3D11Device> d3d_device;
+  if (dxgi_device_manager &&
+      FAILED(dxgi_device_manager->ResetDevice(d3d_device))) {
     // If setting a device failed, ensure that an empty scoped_refptr is
     // returned as the dxgi_device_manager is not usable without a device.
     return nullptr;
@@ -87,8 +93,8 @@
 
 DXGIDeviceManager::~DXGIDeviceManager() = default;
 
-HRESULT DXGIDeviceManager::ResetDevice() {
-  Microsoft::WRL::ComPtr<ID3D11Device> d3d_device;
+HRESULT DXGIDeviceManager::ResetDevice(
+    Microsoft::WRL::ComPtr<ID3D11Device>& d3d_device) {
   constexpr uint32_t kDeviceFlags =
       D3D11_CREATE_DEVICE_VIDEO_SUPPORT | D3D11_CREATE_DEVICE_BGRA_SUPPORT;
   HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr,
@@ -113,6 +119,27 @@
   return S_OK;
 }
 
+HRESULT DXGIDeviceManager::CheckDeviceRemovedAndGetDevice(
+    Microsoft::WRL::ComPtr<ID3D11Device>* new_device) {
+  Microsoft::WRL::ComPtr<ID3D11Device> device = GetDevice();
+  HRESULT hr = device ? device->GetDeviceRemovedReason() : MF_E_UNEXPECTED;
+  if (FAILED(hr)) {
+    HRESULT reset_hr = ResetDevice(device);
+    if (FAILED(reset_hr)) {
+      LOG(ERROR) << "Failed to recreate the device: "
+                 << logging::SystemErrorCodeToString(reset_hr);
+      if (new_device) {
+        *new_device = nullptr;
+      }
+    }
+    return hr;
+  }
+  if (new_device) {
+    *new_device = device;
+  }
+  return hr;
+}
+
 HRESULT DXGIDeviceManager::RegisterInCaptureEngineAttributes(
     IMFAttributes* attributes) {
   HRESULT hr = attributes->SetUnknown(MF_CAPTURE_ENGINE_D3D_MANAGER,
diff --git a/media/base/win/dxgi_device_manager.h b/media/base/win/dxgi_device_manager.h
index 98e8301..a5e2c53c6 100644
--- a/media/base/win/dxgi_device_manager.h
+++ b/media/base/win/dxgi_device_manager.h
@@ -43,7 +43,14 @@
   static scoped_refptr<DXGIDeviceManager> Create();
 
   // Associates a new D3D device with the DXGI Device Manager
-  virtual HRESULT ResetDevice();
+  // returns it in the parameter, which can't be nullptr.
+  virtual HRESULT ResetDevice(Microsoft::WRL::ComPtr<ID3D11Device>& d3d_device);
+
+  // Checks if the local device was removed, recreates it if needed.
+  // Returns DeviceRemovedReason HRESULT value.
+  // Returns the local device in |new_device|, if it's not nullptr.
+  virtual HRESULT CheckDeviceRemovedAndGetDevice(
+      Microsoft::WRL::ComPtr<ID3D11Device>* new_device);
 
   // Registers this manager in capture engine attributes.
   HRESULT RegisterInCaptureEngineAttributes(IMFAttributes* attributes);
diff --git a/media/capture/video/chromeos/camera_device_delegate.cc b/media/capture/video/chromeos/camera_device_delegate.cc
index 08a0888..823f8d2 100644
--- a/media/capture/video/chromeos/camera_device_delegate.cc
+++ b/media/capture/video/chromeos/camera_device_delegate.cc
@@ -52,6 +52,10 @@
 constexpr int32_t kColorTemperatureStep = 100;
 constexpr int32_t kMicroToNano = 1000;
 
+constexpr char kIntelPowerMode[] = "intel.vendorCamera.powerMode";
+constexpr uint8_t kIntelPowerModeLowPower = 0;
+constexpr uint8_t kIntelPowerModeHighQuality = 1;
+
 using AwbModeTemperatureMap = std::map<uint8_t, int32_t>;
 
 const AwbModeTemperatureMap& GetAwbModeTemperatureMap() {
@@ -819,6 +823,20 @@
       std::move(callback_ops),
       base::BindOnce(&CameraDeviceDelegate::OnInitialized, GetWeakPtr()));
   request_manager_->AddResultMetadataObserver(this);
+
+  // For Intel IPU6 platform, set power mode to high quality for CCA and low
+  // power mode for others.
+  const VendorTagInfo* info =
+      camera_hal_delegate_->GetVendorTagInfoByName(kIntelPowerMode);
+  if (info != nullptr) {
+    bool is_cca =
+        CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice(
+            device_descriptor_.device_id) != nullptr;
+    uint8_t power_mode =
+        is_cca ? kIntelPowerModeHighQuality : kIntelPowerModeLowPower;
+    request_manager_->SetRepeatingCaptureMetadata(
+        info->tag, info->type, 1, std::vector<uint8_t>{power_mode});
+  }
 }
 
 void CameraDeviceDelegate::OnInitialized(int32_t result) {
diff --git a/media/capture/video/video_capture_buffer_pool_impl.cc b/media/capture/video/video_capture_buffer_pool_impl.cc
index dae889e..e567a77 100644
--- a/media/capture/video/video_capture_buffer_pool_impl.cc
+++ b/media/capture/video/video_capture_buffer_pool_impl.cc
@@ -279,8 +279,17 @@
   // Create the new tracker.
   const int new_buffer_id = next_buffer_id_++;
 
+  VideoCaptureBufferType buffer_type = buffer_type_;
+#if defined(OS_WIN)
+  // If the MediaFoundationD3D11VideoCapture path fails, a shared memory buffer
+  // is sent instead.
+  if (buffer_type == VideoCaptureBufferType::kGpuMemoryBuffer &&
+      pixel_format != PIXEL_FORMAT_NV12) {
+    buffer_type = VideoCaptureBufferType::kSharedMemory;
+  }
+#endif
   std::unique_ptr<VideoCaptureBufferTracker> tracker =
-      buffer_tracker_factory_->CreateTracker(buffer_type_);
+      buffer_tracker_factory_->CreateTracker(buffer_type);
   if (!tracker || !tracker->Init(dimensions, pixel_format, strides)) {
     DLOG(ERROR) << "Error initializing VideoCaptureBufferTracker";
     *buffer_id = kInvalidId;
diff --git a/media/capture/video/video_capture_device_client.cc b/media/capture/video/video_capture_device_client.cc
index a677188..91b170d 100644
--- a/media/capture/video/video_capture_device_client.cc
+++ b/media/capture/video/video_capture_device_client.cc
@@ -571,7 +571,16 @@
   if (!base::Contains(buffer_ids_known_by_receiver_, buffer_id)) {
     media::mojom::VideoBufferHandlePtr buffer_handle =
         media::mojom::VideoBufferHandle::New();
-    switch (target_buffer_type_) {
+    VideoCaptureBufferType target_buffer_type = target_buffer_type_;
+#if defined(OS_WIN)
+    // If MediaFoundationD3D11VideoCapture fails, a shared memory buffer may be
+    // sent instead.
+    if (target_buffer_type == VideoCaptureBufferType::kGpuMemoryBuffer &&
+        pixel_format != PIXEL_FORMAT_NV12) {
+      target_buffer_type = VideoCaptureBufferType::kSharedMemory;
+    }
+#endif
+    switch (target_buffer_type) {
       case VideoCaptureBufferType::kSharedMemory:
         buffer_handle->set_shared_buffer_handle(
             buffer_pool_->DuplicateAsMojoBuffer(buffer_id));
diff --git a/media/capture/video/win/gpu_memory_buffer_tracker.cc b/media/capture/video/win/gpu_memory_buffer_tracker.cc
index dd7f7f2..ef6caa1c 100644
--- a/media/capture/video/win/gpu_memory_buffer_tracker.cc
+++ b/media/capture/video/win/gpu_memory_buffer_tracker.cc
@@ -5,6 +5,8 @@
 #include "media/capture/video/win/gpu_memory_buffer_tracker.h"
 
 #include "base/check.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/notreached.h"
 #include "base/unguessable_token.h"
 #include "base/win/scoped_handle.h"
@@ -95,6 +97,11 @@
       CreateNV12Texture(d3d_device_.Get(), buffer_size_);
   buffer_handle.dxgi_token = gfx::DXGIHandleToken();
 
+  if (!buffer_handle.dxgi_handle.IsValid()) {
+    LOG(ERROR) << "Failed to create NV12 texture";
+    return false;
+  }
+
   buffer_ = gpu::GpuMemoryBufferImplDXGI::CreateFromHandle(
       std::move(buffer_handle), buffer_size_,
       gfx::BufferFormat::YUV_420_BIPLANAR, gfx::BufferUsage::GPU_READ,
@@ -109,26 +116,26 @@
   return true;
 }
 
-bool GpuMemoryBufferTracker::EnsureD3DDevice() {
+bool GpuMemoryBufferTracker::IsD3DDeviceChanged() {
   // Check for and handle device loss by recreating the texture
-  if (FAILED(d3d_device_->GetDeviceRemovedReason())) {
-    DVLOG(1) << "Detected device loss.";
-    dxgi_device_manager_->ResetDevice();
-    d3d_device_ = dxgi_device_manager_->GetDevice();
-    if (!d3d_device_) {
-      return false;
-    }
-
-    return CreateBufferInternal();
+  Microsoft::WRL::ComPtr<ID3D11Device> recreated_d3d_device;
+  HRESULT hr = dxgi_device_manager_->CheckDeviceRemovedAndGetDevice(
+      &recreated_d3d_device);
+  if (FAILED(hr)) {
+    LOG(ERROR) << "Detected device loss: "
+               << logging::SystemErrorCodeToString(hr);
+    base::UmaHistogramSparse("Media.VideoCapture.Win.D3DDeviceRemovedReason",
+                             hr);
   }
-  return true;
+  return recreated_d3d_device != d3d_device_;
 }
 
 bool GpuMemoryBufferTracker::IsReusableForFormat(
     const gfx::Size& dimensions,
     VideoPixelFormat format,
     const mojom::PlaneStridesPtr& strides) {
-  return (format == PIXEL_FORMAT_NV12) && (dimensions == buffer_->GetSize());
+  return !IsD3DDeviceChanged() && (format == PIXEL_FORMAT_NV12) &&
+         (dimensions == buffer_->GetSize());
 }
 
 std::unique_ptr<VideoCaptureBufferHandle>
@@ -160,7 +167,7 @@
 }
 
 gfx::GpuMemoryBufferHandle GpuMemoryBufferTracker::GetGpuMemoryBufferHandle() {
-  if (!EnsureD3DDevice()) {
+  if (IsD3DDeviceChanged()) {
     return gfx::GpuMemoryBufferHandle();
   }
   auto handle = buffer_->CloneHandle();
diff --git a/media/capture/video/win/gpu_memory_buffer_tracker.h b/media/capture/video/win/gpu_memory_buffer_tracker.h
index 5fe262b9..d788e92a 100644
--- a/media/capture/video/win/gpu_memory_buffer_tracker.h
+++ b/media/capture/video/win/gpu_memory_buffer_tracker.h
@@ -51,7 +51,7 @@
   Microsoft::WRL::ComPtr<ID3D11Texture2D> staging_texture_;
   gfx::Size buffer_size_;
   bool CreateBufferInternal();
-  bool EnsureD3DDevice();
+  bool IsD3DDeviceChanged();
 };
 
 }  // namespace media
diff --git a/media/capture/video/win/gpu_memory_buffer_tracker_unittest.cc b/media/capture/video/win/gpu_memory_buffer_tracker_unittest.cc
index 3cae858..847398cc 100644
--- a/media/capture/video/win/gpu_memory_buffer_tracker_unittest.cc
+++ b/media/capture/video/win/gpu_memory_buffer_tracker_unittest.cc
@@ -37,7 +37,22 @@
         mock_d3d_device_(new MockD3D11Device()) {}
 
   // Associates a new D3D device with the DXGI Device Manager
-  HRESULT ResetDevice() override { return S_OK; }
+  // returns it in the parameter, which can't be nullptr.
+  HRESULT ResetDevice(
+      Microsoft::WRL::ComPtr<ID3D11Device>& d3d_device) override {
+    mock_d3d_device_ = new MockD3D11Device();
+    d3d_device = mock_d3d_device_;
+    return S_OK;
+  }
+
+  // Checks if the local device was removed, recreates it if needed.
+  // Returns DeviceRemovedReason HRESULT value.
+  // Returns the local device in |new_device|, if it's not nullptr.
+  /*HRESULT CheckDeviceRemovedAndGetDevice(
+      Microsoft::WRL::ComPtr<ID3D11Device>* new_device) override {
+          *new_device = mock_d3d_device_;
+          return S_OK;
+  }*/
 
   // Directly access D3D device stored in DXGI device manager
   Microsoft::WRL::ComPtr<ID3D11Device> GetDevice() override {
@@ -116,7 +131,7 @@
             true);
 }
 
-TEST_F(GpuMemoryBufferTrackerTest, TextureRecreationOnDeviceLoss) {
+TEST_F(GpuMemoryBufferTrackerTest, InvalidateOnDeviceLoss) {
   // Verify that GpuMemoryBufferTracker recreates a D3D11 texture with the
   // correct properties when there is a device loss
   const gfx::Size expected_buffer_size = {1920, 1080};
@@ -135,8 +150,8 @@
                                       static_cast<const unsigned int>(
                                           expected_buffer_size.height())))),
                   _, _))
-      .Times(2);
-  // Mock device loss
+      .Times(1);
+  // Mock device loss.
   EXPECT_CALL(*(dxgi_device_manager_->GetMockDevice().Get()),
               OnGetDeviceRemovedReason())
       .WillOnce(Invoke([]() { return DXGI_ERROR_DEVICE_REMOVED; }));
@@ -145,8 +160,11 @@
       std::make_unique<GpuMemoryBufferTracker>(dxgi_device_manager_);
   EXPECT_EQ(tracker->Init(expected_buffer_size, PIXEL_FORMAT_NV12, nullptr),
             true);
-  // Get GpuMemoryBufferHandle (should trigger device/texture recreation)
+  // The tracker now should be invalid.
+  EXPECT_FALSE(tracker->IsReusableForFormat(expected_buffer_size,
+                                            PIXEL_FORMAT_NV12, nullptr));
   gfx::GpuMemoryBufferHandle gmb = tracker->GetGpuMemoryBufferHandle();
+  EXPECT_FALSE(gmb.dxgi_handle.IsValid());
 }
 
 TEST_F(GpuMemoryBufferTrackerTest, GetMemorySizeInBytes) {
diff --git a/media/capture/video/win/video_capture_device_mf_win.cc b/media/capture/video/win/video_capture_device_mf_win.cc
index cc47e9c..07af502d 100644
--- a/media/capture/video/win/video_capture_device_mf_win.cc
+++ b/media/capture/video/win/video_capture_device_mf_win.cc
@@ -5,6 +5,7 @@
 #include "media/capture/video/win/video_capture_device_mf_win.h"
 
 #include <d3d11_4.h>
+#include <ks.h>
 #include <mfapi.h>
 #include <mferror.h>
 #include <stddef.h>
@@ -17,6 +18,7 @@
 #include "base/bind.h"
 #include "base/compiler_specific.h"
 #include "base/location.h"
+#include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/stringprintf.h"
@@ -207,8 +209,8 @@
 }
 
 void LogError(const Location& from_here, HRESULT hr) {
-  DPLOG(ERROR) << from_here.ToString()
-               << " hr = " << logging::SystemErrorCodeToString(hr);
+  LOG(ERROR) << from_here.ToString()
+             << " hr = " << logging::SystemErrorCodeToString(hr);
 }
 
 bool GetFrameSizeFromMediaType(IMFMediaType* type, gfx::Size* frame_size) {
@@ -878,7 +880,7 @@
     ComPtr<IMFMediaSource> source,
     scoped_refptr<DXGIDeviceManager> dxgi_device_manager,
     ComPtr<IMFCaptureEngine> engine)
-    : facing_mode_(device_descriptor.facing),
+    : device_descriptor_(device_descriptor),
       create_mf_photo_callback_(base::BindRepeating(&CreateMFPhotoCallback)),
       is_initialized_(false),
       max_retry_count_(200),
@@ -934,7 +936,6 @@
       return false;
     }
   }
-
   ComPtr<IMFAttributes> attributes;
   hr = MFCreateAttributes(&attributes, 1);
   if (FAILED(hr)) {
@@ -977,6 +978,7 @@
 
   base::AutoLock lock(lock_);
 
+  params_ = params;
   client_ = std::move(client);
   DCHECK_EQ(false, is_started_);
 
@@ -1541,8 +1543,14 @@
   HRESULT hr = texture_device->GetDeviceRemovedReason();
 
   if (FAILED(hr)) {
-    DLOG(ERROR) << "Camera texture device lost.";
-    DCHECK(dxgi_device_manager_->ResetDevice());
+    // Make sure the main device is reset.
+    hr = dxgi_device_manager_->CheckDeviceRemovedAndGetDevice(nullptr);
+    LOG(ERROR) << "Camera texture device lost: "
+               << logging::SystemErrorCodeToString(hr);
+    base::UmaHistogramSparse("Media.VideoCapture.Win.D3DDeviceRemovedReason",
+                             hr);
+    // Even if device was reset successfully, we can't continue
+    // because the texture is tied to the old device.
     return hr;
   }
 
@@ -1559,13 +1567,24 @@
   auto result = client_->ReserveOutputBuffer(
       texture_size, pixel_format, kDummyFrameFeedbackId, &capture_buffer);
   if (result != VideoCaptureDevice::Client::ReserveResult::kSucceeded) {
-    DLOG(ERROR) << "Failed to reserve output capture buffer: " << (int)result;
+    LOG(ERROR) << "Failed to reserve output capture buffer: " << (int)result;
     return MF_E_UNEXPECTED;
   }
 
   auto gmb_handle = capture_buffer.handle_provider->GetGpuMemoryBufferHandle();
+  if (!gmb_handle.dxgi_handle.IsValid()) {
+    // If the device is removed and GMB tracker fails to recreate it,
+    // an empty gmb handle may be returned here.
+    return MF_E_UNEXPECTED;
+  }
   hr = CopyTextureToGpuMemoryBuffer(texture, gmb_handle.dxgi_handle.Get());
 
+  if (FAILED(hr)) {
+    LOG(ERROR) << "Failed to copy camera device texture to output texture: "
+               << logging::SystemErrorCodeToString(hr);
+    return hr;
+  }
+
   capture_buffer.is_premapped = false;
   if (last_feedback_.require_mapped_frame) {
     // Only a flag on the Buffer is set here; the region itself isn't passed
@@ -1577,12 +1596,6 @@
     }
   }
 
-  if (FAILED(hr)) {
-    DLOG(ERROR) << "Failed to copy camera device texture to output texture: "
-                << logging::SystemErrorCodeToString(hr);
-    return hr;
-  }
-
   VideoRotation frame_rotation = VIDEO_ROTATION_0;
   DCHECK(camera_rotation_.has_value());
   switch (camera_rotation_.value()) {
@@ -1636,7 +1649,7 @@
     // We always calculate camera rotation for the first frame. We also cache
     // the latest value to use when AutoRotation is turned off.
     if (!camera_rotation_.has_value() || IsAutoRotationEnabled())
-      camera_rotation_ = GetCameraRotation(facing_mode_);
+      camera_rotation_ = GetCameraRotation(device_descriptor_.facing);
 
     Microsoft::WRL::ComPtr<ID3D11Texture2D> texture;
     // Use the hardware path only if it is enabled and the selected pixel format
@@ -1659,7 +1672,7 @@
 
   ScopedBufferLock locked_buffer(buffer);
   if (!locked_buffer.data()) {
-    DLOG(ERROR) << "Locked buffer delivered nullptr";
+    LOG(ERROR) << "Locked buffer delivered nullptr";
     frame_drop_reason = VideoCaptureFrameDropReason::
         kWinMediaFoundationLockingBufferDelieveredNullptr;
     return;
@@ -1712,29 +1725,60 @@
 }
 
 void VideoCaptureDeviceMFWin::OnEvent(IMFMediaEvent* media_event) {
-  base::AutoLock lock(lock_);
+  bool need_restart = false;
+  std::unique_ptr<VideoCaptureDevice::Client> client;
+  {
+    base::AutoLock lock(lock_);
 
-  HRESULT hr;
-  GUID capture_event_guid = GUID_NULL;
+    HRESULT hr;
+    GUID capture_event_guid = GUID_NULL;
 
-  media_event->GetStatus(&hr);
-  media_event->GetExtendedType(&capture_event_guid);
-  // TODO(http://crbug.com/1093521): Add cases for Start
-  // MF_CAPTURE_ENGINE_PREVIEW_STARTED and MF_CAPTURE_ENGINE_PREVIEW_STOPPED
-  // When MF_CAPTURE_ENGINE_ERROR is returned the captureengine object is no
-  // longer valid.
-  if (capture_event_guid == MF_CAPTURE_ENGINE_ERROR || FAILED(hr)) {
-    capture_error_.Signal();
-    // There should always be a valid error
-    hr = SUCCEEDED(hr) ? E_UNEXPECTED : hr;
-  } else if (capture_event_guid == MF_CAPTURE_ENGINE_INITIALIZED) {
-    capture_initialize_.Signal();
+    media_event->GetStatus(&hr);
+    media_event->GetExtendedType(&capture_event_guid);
+
+    // TODO(http://crbug.com/1093521): Add cases for Start
+    // MF_CAPTURE_ENGINE_PREVIEW_STARTED and MF_CAPTURE_ENGINE_PREVIEW_STOPPED
+    // When MF_CAPTURE_ENGINE_ERROR is returned the captureengine object is no
+    // longer valid.
+    if (capture_event_guid == MF_CAPTURE_ENGINE_ERROR || FAILED(hr)) {
+      capture_error_.Signal();
+      // There should always be a valid error
+      hr = SUCCEEDED(hr) ? E_UNEXPECTED : hr;
+    } else if (capture_event_guid == MF_CAPTURE_ENGINE_INITIALIZED) {
+      capture_initialize_.Signal();
+    }
+
+    if (hr == DXGI_ERROR_DEVICE_REMOVED) {
+      Microsoft::WRL::ComPtr<ID3D11Device> recreated_d3d_device;
+      HRESULT removed_hr = dxgi_device_manager_->CheckDeviceRemovedAndGetDevice(
+          &recreated_d3d_device);
+      LOG(ERROR) << "OnEvent: Device was Removed. Reason: "
+                 << logging::SystemErrorCodeToString(removed_hr);
+      if (recreated_d3d_device) {
+        // successfully recreated the device.
+        hr = S_OK;
+        need_restart = true;
+        engine_ = nullptr;
+        client = std::move(client_);
+        capture_error_.Reset();
+      }
+    }
+
+    if (FAILED(hr)) {
+      base::UmaHistogramSparse("Media.VideoCapture.Win.ErrorEvent", hr);
+      OnError(VideoCaptureError::kWinMediaFoundationGetMediaEventStatusFailed,
+              FROM_HERE, hr);
+    }
   }
-
-  if (FAILED(hr)) {
-    base::UmaHistogramSparse("Media.VideoCapture.Win.ErrorEvent", hr);
-    OnError(VideoCaptureError::kWinMediaFoundationGetMediaEventStatusFailed,
-            FROM_HERE, hr);
+  if (need_restart) {
+    is_started_ = false;
+    is_initialized_ = false;
+    StopAndDeAllocate();
+    RecreateMFSource();
+    if (!Init()) {
+      LOG(ERROR) << "Failed to initialize.";
+    }
+    AllocateAndStart(params_, std::move(client));
   }
 }
 
@@ -1792,4 +1836,33 @@
   }
   return hr;
 }
+
+void VideoCaptureDeviceMFWin::RecreateMFSource() {
+  base::AutoLock lock(lock_);
+
+  const bool is_sensor_api = device_descriptor_.capture_api ==
+                             VideoCaptureApi::WIN_MEDIA_FOUNDATION_SENSOR;
+  ComPtr<IMFAttributes> attributes;
+  HRESULT hr = MFCreateAttributes(&attributes, is_sensor_api ? 3 : 2);
+  if (FAILED(hr)) {
+    LOG(ERROR) << "Failed to create attributes: "
+               << logging::SystemErrorCodeToString(hr);
+    return;
+  }
+  attributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
+                      MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
+  if (is_sensor_api) {
+    attributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_CATEGORY,
+                        KSCATEGORY_SENSOR_CAMERA);
+  }
+  attributes->SetString(
+      MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
+      base::SysUTF8ToWide(device_descriptor_.device_id).c_str());
+  hr = MFCreateDeviceSource(attributes.Get(), &source_);
+  LOG_IF(ERROR, FAILED(hr)) << "MFCreateDeviceSource failed: "
+                            << logging::SystemErrorCodeToString(hr);
+  if (SUCCEEDED(hr) && dxgi_device_manager_) {
+    dxgi_device_manager_->RegisterWithMediaSource(source_);
+  }
+}
 }  // namespace media
diff --git a/media/capture/video/win/video_capture_device_mf_win.h b/media/capture/video/win/video_capture_device_mf_win.h
index aed22f7..7a61000 100644
--- a/media/capture/video/win/video_capture_device_mf_win.h
+++ b/media/capture/video/win/video_capture_device_mf_win.h
@@ -147,8 +147,9 @@
       base::TimeTicks reference_time,
       base::TimeDelta timestamp,
       VideoCaptureFrameDropReason& frame_drop_reason);
+  void RecreateMFSource();
 
-  VideoFacingMode facing_mode_;
+  VideoCaptureDeviceDescriptor device_descriptor_;
   CreateMFPhotoCallbackCB create_mf_photo_callback_;
   scoped_refptr<MFVideoCallback> video_callback_;
   bool is_initialized_;
@@ -161,7 +162,7 @@
   base::Lock lock_;
 
   std::unique_ptr<VideoCaptureDevice::Client> client_;
-  const Microsoft::WRL::ComPtr<IMFMediaSource> source_;
+  Microsoft::WRL::ComPtr<IMFMediaSource> source_;
   Microsoft::WRL::ComPtr<IAMCameraControl> camera_control_;
   Microsoft::WRL::ComPtr<IAMVideoProcAmp> video_control_;
   Microsoft::WRL::ComPtr<IMFCaptureEngine> engine_;
@@ -179,6 +180,7 @@
   base::WaitableEvent capture_error_;
   scoped_refptr<DXGIDeviceManager> dxgi_device_manager_;
   absl::optional<int> camera_rotation_;
+  VideoCaptureParams params_;
 
   media::VideoCaptureFeedback last_feedback_;
 
diff --git a/media/gpu/chromeos/dmabuf_video_frame_pool.cc b/media/gpu/chromeos/dmabuf_video_frame_pool.cc
index 453a912..5d7a0f08e 100644
--- a/media/gpu/chromeos/dmabuf_video_frame_pool.cc
+++ b/media/gpu/chromeos/dmabuf_video_frame_pool.cc
@@ -23,4 +23,8 @@
   parent_task_runner_ = std::move(parent_task_runner);
 }
 
+PlatformVideoFramePool* DmabufVideoFramePool::AsPlatformVideoFramePool() {
+  return nullptr;
+}
+
 }  // namespace media
diff --git a/media/gpu/chromeos/dmabuf_video_frame_pool.h b/media/gpu/chromeos/dmabuf_video_frame_pool.h
index 962f98a..5bfabef 100644
--- a/media/gpu/chromeos/dmabuf_video_frame_pool.h
+++ b/media/gpu/chromeos/dmabuf_video_frame_pool.h
@@ -17,8 +17,15 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 
+namespace gpu {
+class GpuMemoryBufferFactory;
+}  // namespace gpu
+
 namespace media {
 
+// Forward declare for use in AsPlatformVideoFramePool.
+class PlatformVideoFramePool;
+
 // Interface for allocating and managing DMA-buf VideoFrame. The client should
 // set a task runner first, and guarantee both GetFrame() and the destructor are
 // executed on this task runner.
@@ -28,6 +35,16 @@
  public:
   using DmabufId = const std::vector<base::ScopedFD>*;
 
+  using CreateFrameCB =
+      base::RepeatingCallback<CroStatus::Or<scoped_refptr<VideoFrame>>(
+          gpu::GpuMemoryBufferFactory*,
+          VideoPixelFormat,
+          const gfx::Size&,
+          const gfx::Rect&,
+          const gfx::Size&,
+          bool,
+          base::TimeDelta)>;
+
   // Get the identifier of Dmabuf-backed |frame|. Calling this method with the
   // frames backed by the same Dmabuf should return the same result.
   static DmabufId GetDmabufId(const VideoFrame& frame);
@@ -41,6 +58,11 @@
   virtual void set_parent_task_runner(
       scoped_refptr<base::SequencedTaskRunner> parent_task_runner);
 
+  // Allows downcasting to an implementation of DmabufVideoFramePool safely
+  // since it has custom behavior that VaapiVideoDecoder needs to take
+  // advantage of.
+  virtual PlatformVideoFramePool* AsPlatformVideoFramePool();
+
   // Sets the parameters of allocating frames and the maximum number of frames
   // which can be allocated.
   // Returns a valid GpuBufferLayout if the initialization is successful,
diff --git a/media/gpu/chromeos/platform_video_frame_pool.cc b/media/gpu/chromeos/platform_video_frame_pool.cc
index b163c9d8..c43099b 100644
--- a/media/gpu/chromeos/platform_video_frame_pool.cc
+++ b/media/gpu/chromeos/platform_video_frame_pool.cc
@@ -20,7 +20,7 @@
 namespace {
 
 // The default method to create frames.
-scoped_refptr<VideoFrame> DefaultCreateFrame(
+CroStatus::Or<scoped_refptr<VideoFrame>> DefaultCreateFrame(
     gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
     VideoPixelFormat format,
     const gfx::Size& coded_size,
@@ -33,7 +33,10 @@
       timestamp,
       use_protected ? gfx::BufferUsage::PROTECTED_SCANOUT_VDA_WRITE
                     : gfx::BufferUsage::SCANOUT_VDA_WRITE);
-  if (frame && use_protected) {
+  if (!frame)
+    return CroStatus::Codes::kFailedToCreateVideoFrame;
+
+  if (use_protected) {
     media::VideoFrameMetadata frame_metadata;
     frame_metadata.protected_video = true;
     frame_metadata.hw_protected = true;
@@ -97,14 +100,16 @@
     // with (10, 20), 100x100 we cannot (even though it's contained in the
     // former). Hence the use of GetRectSizeFromOrigin() to calculate the
     // visible rect for |new_frame|.
-    scoped_refptr<VideoFrame> new_frame =
+    CroStatus::Or<scoped_refptr<VideoFrame>> new_frame =
         create_frame_cb_.Run(gpu_memory_buffer_factory_, format, coded_size,
                              gfx::Rect(GetRectSizeFromOrigin(visible_rect_)),
                              coded_size, use_protected_, base::TimeDelta());
-    if (!new_frame)
+    if (new_frame.has_error()) {
+      // TODO(crbug.com/c/1103510) Push the error up instead of dropping it.
       return nullptr;
+    }
 
-    InsertFreeFrame_Locked(std::move(new_frame));
+    InsertFreeFrame_Locked(std::move(new_frame).value());
   }
 
   DCHECK(!free_frames_.empty());
@@ -138,6 +143,10 @@
   return wrapped_frame;
 }
 
+PlatformVideoFramePool* PlatformVideoFramePool::AsPlatformVideoFramePool() {
+  return this;
+}
+
 CroStatus::Or<GpuBufferLayout> PlatformVideoFramePool::Initialize(
     const Fourcc& fourcc,
     const gfx::Size& coded_size,
@@ -177,28 +186,21 @@
   if (!IsSameFormat_Locked(format, coded_size, visible_rect, use_protected)) {
     DVLOGF(4) << "The video frame format is changed. Clearing the pool.";
     free_frames_.clear();
-
-    // Create a temporary frame in order to know VideoFrameLayout that
-    // VideoFrame that will be allocated in GetFrame() has.
-    auto frame = create_frame_cb_.Run(gpu_memory_buffer_factory_, format,
-                                      coded_size, visible_rect, natural_size,
-                                      use_protected, base::TimeDelta());
-    if (!frame) {
-      VLOGF(1) << "Failed to create video frame " << format << " (fourcc "
-               << fourcc.ToString() << ")";
-      return CroStatus::Codes::kFailedToCreateVideoFrame;
-    }
+    auto maybe_frame = create_frame_cb_.Run(
+        gpu_memory_buffer_factory_, format, coded_size, visible_rect,
+        natural_size, use_protected, base::TimeDelta());
+    if (maybe_frame.has_error())
+      return std::move(maybe_frame).error();
+    auto frame = std::move(maybe_frame).value();
     frame_layout_ = GpuBufferLayout::Create(fourcc, frame->coded_size(),
                                             frame->layout().planes(),
                                             frame->layout().modifier());
-    if (!frame_layout_) {
-      VLOGF(1) << "Failed to create the layout (fourcc=" << fourcc.ToString()
-               << ", coded_size=" << frame->coded_size().ToString() << ")";
+    if (!frame_layout_)
       return CroStatus::Codes::kFailedToGetFrameLayout;
-    }
   }
 
   DCHECK(frame_layout_);
+
   visible_rect_ = visible_rect;
   natural_size_ = natural_size;
   max_num_frames_ = max_num_frames;
@@ -212,6 +214,12 @@
   return *frame_layout_;
 }
 
+void PlatformVideoFramePool::SetCustomFrameAllocator(
+    DmabufVideoFramePool::CreateFrameCB allocator) {
+  base::AutoLock auto_lock(lock_);
+  create_frame_cb_ = allocator;
+}
+
 bool PlatformVideoFramePool::IsExhausted() {
   DVLOGF(4);
   base::AutoLock auto_lock(lock_);
diff --git a/media/gpu/chromeos/platform_video_frame_pool.h b/media/gpu/chromeos/platform_video_frame_pool.h
index abb1441..3b99b26 100644
--- a/media/gpu/chromeos/platform_video_frame_pool.h
+++ b/media/gpu/chromeos/platform_video_frame_pool.h
@@ -22,10 +22,6 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
-namespace gpu {
-class GpuMemoryBufferFactory;
-}  // namespace gpu
-
 namespace media {
 
 // Simple VideoFrame pool used to avoid unnecessarily allocating and destroying
@@ -51,6 +47,8 @@
   static gfx::GpuMemoryBufferId GetGpuMemoryBufferId(const VideoFrame& frame);
 
   // DmabufVideoFramePool implementation.
+  PlatformVideoFramePool* AsPlatformVideoFramePool() override;
+
   CroStatus::Or<GpuBufferLayout> Initialize(const Fourcc& fourcc,
                                             const gfx::Size& coded_size,
                                             const gfx::Rect& visible_rect,
@@ -70,6 +68,12 @@
   // Returns the number of frames in the pool for testing purposes.
   size_t GetPoolSizeForTesting();
 
+  // Allows the client to specify how to allocate buffers. |allocator| is only
+  // run during a call to Initialize() or GetFrame(), so it's guaranteed to be
+  // called in the same thread as those two methods. VaapiVideoDecoder uses this
+  // on linux to delegate dmabuf allocation to the libva driver.
+  void SetCustomFrameAllocator(DmabufVideoFramePool::CreateFrameCB allocator);
+
  private:
   friend class PlatformVideoFramePoolTest;
 
@@ -97,21 +101,13 @@
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
   bool IsExhausted_Locked() EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
-  // The function used to allocate new frames.
-  using CreateFrameCB = base::RepeatingCallback<scoped_refptr<VideoFrame>(
-      gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
-      VideoPixelFormat format,
-      const gfx::Size& coded_size,
-      const gfx::Rect& visible_rect,
-      const gfx::Size& natural_size,
-      bool use_protected,
-      base::TimeDelta timestamp)>;
-  CreateFrameCB create_frame_cb_;
-
   // Lock to protect all data members.
   // Every public method and OnFrameReleased() acquire this lock.
   base::Lock lock_;
 
+  // The function used to allocate new frames.
+  CreateFrameCB create_frame_cb_ GUARDED_BY(lock_);
+
   // Used to allocate the video frame GpuMemoryBuffers, passed directly to
   // the callback that creates video frames. Indirectly owned by GpuChildThread;
   // therefore alive as long as the GPU process is.
diff --git a/media/gpu/chromeos/platform_video_frame_pool_unittest.cc b/media/gpu/chromeos/platform_video_frame_pool_unittest.cc
index e5cf8ef..2439868c 100644
--- a/media/gpu/chromeos/platform_video_frame_pool_unittest.cc
+++ b/media/gpu/chromeos/platform_video_frame_pool_unittest.cc
@@ -24,7 +24,7 @@
 namespace {
 
 template <uint64_t modifier>
-scoped_refptr<VideoFrame> CreateGpuMemoryBufferVideoFrame(
+CroStatus::Or<scoped_refptr<VideoFrame>> CreateGpuMemoryBufferVideoFrame(
     gpu::GpuMemoryBufferFactory* factory,
     VideoPixelFormat format,
     const gfx::Size& coded_size,
@@ -93,6 +93,7 @@
   }
 
   void SetCreateFrameCB(PlatformVideoFramePool::CreateFrameCB cb) {
+    base::AutoLock auto_lock(pool_->lock_);
     pool_->create_frame_cb_ = cb;
   }
 
@@ -296,8 +297,8 @@
          const gfx::Size& coded_size, const gfx::Rect& visible_rect,
          const gfx::Size& natural_size, bool use_protected,
          base::TimeDelta timestamp) {
-        auto frame = scoped_refptr<VideoFrame>(nullptr);
-        return frame;
+        return CroStatus::Or<scoped_refptr<VideoFrame>>(
+            CroStatus::Codes::kFailedToCreateVideoFrame);
       }));
 
   EXPECT_FALSE(Initialize(fourcc.value()));
diff --git a/media/gpu/chromeos/video_decoder_pipeline.cc b/media/gpu/chromeos/video_decoder_pipeline.cc
index 2d77cd9..d896dda 100644
--- a/media/gpu/chromeos/video_decoder_pipeline.cc
+++ b/media/gpu/chromeos/video_decoder_pipeline.cc
@@ -615,7 +615,8 @@
     absl::optional<gfx::Size> output_size,
     size_t num_of_pictures,
     bool use_protected,
-    bool need_aux_frame_pool) {
+    bool need_aux_frame_pool,
+    absl::optional<DmabufVideoFramePool::CreateFrameCB> allocator) {
   DVLOGF(3);
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
 
@@ -642,6 +643,20 @@
         break;
     }
   }
+
+  if (allocator.has_value() && main_frame_pool_->AsPlatformVideoFramePool()) {
+    // The only client likely to be sending a non-nullopt allocator is linux,
+    // which is always using a PlatformVideoFramePool.
+    main_frame_pool_->AsPlatformVideoFramePool()->SetCustomFrameAllocator(
+        *allocator);
+  }
+
+#if defined(OS_LINUX)
+  // viable_candidate should always be set unless using L1 protected content,
+  // which isn't an option on linux.
+  CHECK(viable_candidate);
+#endif
+
   if (viable_candidate) {
     CroStatus::Or<GpuBufferLayout> status_or_layout =
         main_frame_pool_->Initialize(viable_candidate->fourcc,
@@ -651,7 +666,8 @@
     if (status_or_layout.has_error())
       return std::move(status_or_layout).error();
 
-#if BUILDFLAG(USE_VAAPI)
+#if BUILDFLAG(USE_VAAPI) && !defined(OS_LINUX)
+    // Linux does not check the modifiers, since it does not set any.
     const GpuBufferLayout layout(std::move(status_or_layout).value());
     if (layout.modifier() == viable_candidate->modifier) {
       return *viable_candidate;
@@ -668,7 +684,7 @@
     }
 #else
     return *viable_candidate;
-#endif
+#endif  // BUILDFLAG(USE_VAAPI) && !defined(OS_LINUX)
   }
 
   std::unique_ptr<ImageProcessor> image_processor;
@@ -704,6 +720,7 @@
     // overlays anyway.
     auxiliary_frame_pool_ = std::make_unique<PlatformVideoFramePool>(
         /*gpu_memory_buffer_factory=*/nullptr);
+
     auxiliary_frame_pool_->set_parent_task_runner(decoder_task_runner_);
     CroStatus::Or<GpuBufferLayout> status_or_layout =
         auxiliary_frame_pool_->Initialize(
diff --git a/media/gpu/chromeos/video_decoder_pipeline.h b/media/gpu/chromeos/video_decoder_pipeline.h
index c2dc3ef..f798c98 100644
--- a/media/gpu/chromeos/video_decoder_pipeline.h
+++ b/media/gpu/chromeos/video_decoder_pipeline.h
@@ -77,6 +77,8 @@
     // initialized and that pool can be obtained by calling GetVideoFramePool().
     // This pool will provide buffers consistent with the selected candidate out
     // of |candidates|. If false, the caller must allocate its own buffers.
+    // if |allocator| is not absl::nullopt, the frame pool will be set
+    // to use the allocator provided for allocating video frames.
     //
     // Note: after a call to this method, callers should assume that a pointer
     // returned by a prior call to GetVideoFramePool() is no longer valid.
@@ -88,7 +90,8 @@
         absl::optional<gfx::Size> output_size,
         size_t num_of_pictures,
         bool use_protected,
-        bool need_aux_frame_pool) = 0;
+        bool need_aux_frame_pool,
+        absl::optional<DmabufVideoFramePool::CreateFrameCB> allocator) = 0;
   };
 
   VideoDecoderMixin(
@@ -170,7 +173,8 @@
       absl::optional<gfx::Size> output_size,
       size_t num_of_pictures,
       bool use_protected,
-      bool need_aux_frame_pool) override;
+      bool need_aux_frame_pool,
+      absl::optional<DmabufVideoFramePool::CreateFrameCB> allocator) override;
 
  private:
   friend class VideoDecoderPipelineTest;
diff --git a/media/gpu/chromeos/video_decoder_pipeline_unittest.cc b/media/gpu/chromeos/video_decoder_pipeline_unittest.cc
index 56e57d8..9d74bf5 100644
--- a/media/gpu/chromeos/video_decoder_pipeline_unittest.cc
+++ b/media/gpu/chromeos/video_decoder_pipeline_unittest.cc
@@ -662,7 +662,7 @@
         test_vector.input_candidates, kVisibleRect,
         /*decoder_natural_size=*/kVisibleRect.size(),
         /*output_size=*/absl::nullopt, /*num_of_pictures=*/kMaxNumOfFrames,
-        /*use_protected=*/false, /*need_aux_frame_pool=*/false);
+        /*use_protected=*/false, /*need_aux_frame_pool=*/false, absl::nullopt);
     ASSERT_TRUE(status_or_chosen_candidate.has_value());
     const PixelLayoutCandidate chosen_candidate =
         std::move(status_or_chosen_candidate).value();
@@ -676,7 +676,10 @@
   DetachDecoderSequenceChecker();
 }
 
-#if BUILDFLAG(USE_VAAPI)
+// These tests only work on non-linux vaapi systems, since on linux, there is no
+// support for different modifiers.
+#if BUILDFLAG(USE_VAAPI) && !defined(OS_LINUX)
+
 // Verifies the algorithm for choosing formats in PickDecoderOutputFormat works
 // as expected when the pool returns linear buffers. It should allocate an image
 // processor in those cases.
@@ -716,7 +719,7 @@
       {candidate}, kVisibleRect,
       /*decoder_natural_size=*/kVisibleRect.size(),
       /*output_size=*/absl::nullopt, /*num_of_pictures=*/kMaxNumOfFrames,
-      /*use_protected=*/false, /*need_aux_frame_pool=*/false);
+      /*use_protected=*/false, /*need_aux_frame_pool=*/false, absl::nullopt);
 
   EXPECT_TRUE(status_or_chosen_candidate.has_value());
   // Main concern is that the image processor was set.
@@ -749,13 +752,14 @@
       {candidate}, kVisibleRect,
       /*decoder_natural_size=*/kVisibleRect.size(),
       /*output_size=*/absl::nullopt, /*num_of_pictures=*/kMaxNumOfFrames,
-      /*use_protected=*/false, /*need_aux_frame_pool=*/false);
+      /*use_protected=*/false, /*need_aux_frame_pool=*/false, absl::nullopt);
 
   EXPECT_TRUE(status_or_chosen_candidate.has_error());
   EXPECT_FALSE(DecoderHasImageProcessor());
   DetachDecoderSequenceChecker();
 }
-#endif
+
+#endif  // BUILDFLAG(USE_VAAPI) && !defined(OS_LINUX)
 
 // Verifies that ReleaseAllFrames is called on the frame pool when we receive
 // the kDecoderStateLost event through the waiting callback. This can occur
diff --git a/media/gpu/v4l2/v4l2_video_decoder.cc b/media/gpu/v4l2/v4l2_video_decoder.cc
index ce67ecb..c75a914 100644
--- a/media/gpu/v4l2/v4l2_video_decoder.cc
+++ b/media/gpu/v4l2/v4l2_video_decoder.cc
@@ -418,7 +418,8 @@
       client_->PickDecoderOutputFormat(
           candidates, visible_rect, aspect_ratio_.GetNaturalSize(visible_rect),
           /*output_size=*/absl::nullopt, num_output_frames_,
-          /*use+protected=*/false, /*need_aux_frame_pool=*/false);
+          /*use+protected=*/false, /*need_aux_frame_pool=*/false,
+          absl::nullopt);
   if (status_or_output_format.has_error()) {
     VLOGF(1) << "Failed to pick an output format.";
     return std::move(status_or_output_format).error().code();
diff --git a/media/gpu/vaapi/vaapi_video_decoder.cc b/media/gpu/vaapi/vaapi_video_decoder.cc
index 8e1b1cb0..aa57b073f 100644
--- a/media/gpu/vaapi/vaapi_video_decoder.cc
+++ b/media/gpu/vaapi/vaapi_video_decoder.cc
@@ -4,6 +4,8 @@
 
 #include "media/gpu/vaapi/vaapi_video_decoder.h"
 
+#include <vulkan/vulkan.h>
+
 #include <limits>
 #include <vector>
 
@@ -15,7 +17,9 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
+#include "gpu/ipc/common/gpu_memory_buffer_support.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/format_utils.h"
 #include "media/base/media_log.h"
@@ -762,6 +766,17 @@
 
   const gfx::Size decoder_natural_size =
       aspect_ratio_.GetNaturalSize(decoder_visible_rect);
+
+#if defined(OS_LINUX)
+  absl::optional<DmabufVideoFramePool::CreateFrameCB> allocator =
+      base::BindRepeating(&AllocateCustomFrameProxy, weak_this_);
+  std::vector<ImageProcessor::PixelLayoutCandidate> candidates = {
+      {.fourcc = *format_fourcc,
+       .size = decoder_pic_size,
+       .modifier = gfx::NativePixmapHandle::kNoModifier}};
+#else
+  absl::optional<DmabufVideoFramePool::CreateFrameCB> allocator = absl::nullopt;
+
   // TODO(b/203240043): We assume that the |dummy_frame|'s modifier matches the
   // buffer returned by the video frame pool. We should create a test to make
   // sure this assumption is never violated.
@@ -778,18 +793,21 @@
     return;
   }
 
-  ImageProcessor::PixelLayoutCandidate candidate{
-      .fourcc = *format_fourcc,
-      .size = decoder_pic_size,
-      .modifier = dummy_frame->layout().modifier()};
+  std::vector<ImageProcessor::PixelLayoutCandidate> candidates = {
+      {.fourcc = *format_fourcc,
+       .size = decoder_pic_size,
+       .modifier = dummy_frame->layout().modifier()}};
+#endif  // defined(OS_LINUX)
+
   auto status_or_layout = client_->PickDecoderOutputFormat(
-      {candidate}, decoder_visible_rect, decoder_natural_size,
+      candidates, decoder_visible_rect, decoder_natural_size,
       output_visible_rect.size(), decoder_->GetRequiredNumOfPictures(),
       /*use_protected=*/!!cdm_context_ref_,
-      /*need_aux_frame_pool=*/true);
+      /*need_aux_frame_pool=*/true, std::move(allocator));
+
   if (status_or_layout.has_error()) {
-    if (status_or_layout.code() == CroStatus::Codes::kResetRequired) {
-      DVLOGF(2) << "The frame pool initialization is aborted.";
+    if (status_or_layout == CroStatus::Codes::kResetRequired) {
+      DVLOGF(2) << "The frame pool initialization is aborted";
       SetState(State::kExpectingReset);
     } else {
       // TODO(crbug/1103510): don't drop the error on the floor here.
@@ -806,6 +824,93 @@
       base::BindOnce(&VaapiVideoDecoder::HandleDecodeTask, weak_this_));
 }
 
+// Static
+CroStatus::Or<scoped_refptr<VideoFrame>>
+VaapiVideoDecoder::AllocateCustomFrameProxy(
+    base::WeakPtr<VaapiVideoDecoder> decoder,
+    gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
+    VideoPixelFormat format,
+    const gfx::Size& coded_size,
+    const gfx::Rect& visible_rect,
+    const gfx::Size& natural_size,
+    bool use_protected,
+    base::TimeDelta timestamp) {
+  if (!decoder)
+    return CroStatus::Codes::kFailedToCreateVideoFrame;
+  return decoder->AllocateCustomFrame(gpu_memory_buffer_factory, format,
+                                      coded_size, visible_rect, natural_size,
+                                      use_protected, timestamp);
+}
+
+CroStatus::Or<scoped_refptr<VideoFrame>> VaapiVideoDecoder::AllocateCustomFrame(
+    gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
+    VideoPixelFormat format,
+    const gfx::Size& coded_size,
+    const gfx::Rect& visible_rect,
+    const gfx::Size& natural_size,
+    bool use_protected,
+    base::TimeDelta timestamp) {
+  DVLOGF(2);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(state_ == State::kChangingResolution || state_ == State::kDecoding);
+  if (format != PIXEL_FORMAT_NV12)
+    return CroStatus::Codes::kFailedToCreateVideoFrame;
+
+  auto surface = vaapi_wrapper_->CreateVASurfaceWithUsageHints(
+      VA_RT_FORMAT_YUV420, coded_size,
+      {VaapiWrapper::SurfaceUsageHint::kVideoDecoder});
+  if (!surface)
+    return CroStatus::Codes::kFailedToCreateVideoFrame;
+  auto pixmap_and_info =
+      vaapi_wrapper_->ExportVASurfaceAsNativePixmapDmaBuf(*surface);
+  if (!pixmap_and_info)
+    return CroStatus::Codes::kFailedToCreateVideoFrame;
+
+  // Increase this one every time this method is called.
+  static int gmb_id = 0;
+  CHECK_LT(gmb_id, std::numeric_limits<int>::max());
+  gfx::GpuMemoryBufferHandle gmb_handle;
+  auto handle_id = gfx::GpuMemoryBufferId(gmb_id++);
+  gmb_handle.id = handle_id;
+  gmb_handle.type = gfx::GpuMemoryBufferType::NATIVE_PIXMAP;
+  gmb_handle.native_pixmap_handle = pixmap_and_info->pixmap->ExportHandle();
+
+  if (gmb_handle.native_pixmap_handle.planes.empty())
+    return CroStatus::Codes::kFailedToCreateVideoFrame;
+
+  gpu::GpuMemoryBufferSupport gmb_support;
+  auto gmb = gmb_support.CreateGpuMemoryBufferImplFromHandle(
+      std::move(gmb_handle), pixmap_and_info->pixmap->GetBufferSize(),
+      pixmap_and_info->pixmap->GetBufferFormat(),
+      gfx::BufferUsage::SCANOUT_VDA_WRITE, base::NullCallback());
+  if (!gmb)
+    return CroStatus::Codes::kFailedToCreateVideoFrame;
+  const gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes] = {};
+  auto frame = VideoFrame::WrapExternalGpuMemoryBuffer(
+      visible_rect, natural_size, std::move(gmb), mailbox_holders,
+      base::NullCallback(), timestamp);
+
+  if (!frame)
+    return CroStatus::Codes::kFailedToCreateVideoFrame;
+
+  frame->set_ycbcr_info(gpu::VulkanYCbCrInfo(
+      /*image_format=*/VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
+      /*external_format=*/0,
+      /*suggested_ycbcr_model=*/VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709,
+      /*suggested_ycbcr_range=*/VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
+      /*suggested_xchroma_offset=*/VK_CHROMA_LOCATION_COSITED_EVEN,
+      /*suggested_ychroma_offset=*/VK_CHROMA_LOCATION_COSITED_EVEN,
+      /*format_features=*/VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
+          VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
+          VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
+          VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
+          VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
+          VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT));
+  allocated_va_surfaces_[handle_id] = surface;
+
+  return frame;
+}
+
 bool VaapiVideoDecoder::NeedsBitstreamConversion() const {
   DCHECK(output_cb_) << "VaapiVideoDecoder hasn't been initialized";
   NOTREACHED();
diff --git a/media/gpu/vaapi/vaapi_video_decoder.h b/media/gpu/vaapi/vaapi_video_decoder.h
index bb0223c..d6bdb19 100644
--- a/media/gpu/vaapi/vaapi_video_decoder.h
+++ b/media/gpu/vaapi/vaapi_video_decoder.h
@@ -36,6 +36,10 @@
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/hdr_metadata.h"
 
+namespace gpu {
+class GpuMemoryBufferFactory;
+}  // namespace gpu
+
 namespace media {
 
 class AcceleratedVideoDecoder;
@@ -169,6 +173,29 @@
   void ApplyResolutionChangeWithScreenSizes(
       const std::vector<gfx::Size>& screen_resolution);
 
+  // Private static helper to allow using weak ptr instead of an unretained ptr.
+  static CroStatus::Or<scoped_refptr<VideoFrame>> AllocateCustomFrameProxy(
+      base::WeakPtr<VaapiVideoDecoder> decoder,
+      gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
+      VideoPixelFormat format,
+      const gfx::Size& coded_size,
+      const gfx::Rect& visible_rect,
+      const gfx::Size& natural_size,
+      bool use_protected,
+      base::TimeDelta timestamp);
+
+  // Allocates a new VideoFrame using a new VASurface directly. Since this is
+  // only used on linux, it also sets the required YCbCr information for the
+  // frame it creates.
+  CroStatus::Or<scoped_refptr<VideoFrame>> AllocateCustomFrame(
+      gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
+      VideoPixelFormat format,
+      const gfx::Size& coded_size,
+      const gfx::Rect& visible_rect,
+      const gfx::Size& natural_size,
+      bool use_protected,
+      base::TimeDelta timestamp);
+
   // Having too many decoder instances at once may cause us to run out of FDs
   // and subsequently crash (b/181264362). To avoid that, we limit the maximum
   // number of decoder instances that can exist at once. |num_instances_| tracks
diff --git a/media/gpu/vaapi/vaapi_wrapper.cc b/media/gpu/vaapi/vaapi_wrapper.cc
index 0cef2f89..cedaf3e 100644
--- a/media/gpu/vaapi/vaapi_wrapper.cc
+++ b/media/gpu/vaapi/vaapi_wrapper.cc
@@ -692,28 +692,6 @@
 
   if (!InitializeVaDisplay_Locked() || !InitializeVaDriver_Locked())
     return false;
-
-#if BUILDFLAG(USE_VAAPI_X11)
-  if (gl::GetGLImplementation() == gl::kGLImplementationEGLANGLE &&
-      implementation_type_ == VAImplementation::kIntelIHD) {
-    constexpr char libva_driver_impl_env[] = "LIBVA_DRIVER_NAME";
-    // TODO(crbug/1116703) The libva intel-media driver has a known segfault in
-    // vaPutSurface, so until this is fixed, fall back to the i965 driver. There
-    // is discussion of the issue here:
-    // https://github.com/intel/media-driver/issues/818
-    if (!env->HasVar(libva_driver_impl_env))
-      env->SetVar(libva_driver_impl_env, "i965");
-
-    // Re-initialize with the new driver.
-    va_display_ = nullptr;
-    va_initialized_ = false;
-    implementation_type_ = VAImplementation::kInvalid;
-
-    if (!InitializeVaDisplay_Locked() || !InitializeVaDriver_Locked())
-      return false;
-  }
-#endif  // BUILDFLAG(USE_VAAPI_X11)
-
   return true;
 }
 
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
index eaa692d..8a1599c 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
@@ -21,6 +21,7 @@
 #include "base/cxx17_backports.h"
 #include "base/memory/shared_memory_mapping.h"
 #include "base/memory/unsafe_shared_memory_region.h"
+#include "base/task/thread_pool.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "base/win/scoped_co_mem.h"
@@ -186,14 +187,16 @@
       bitrate_(Bitrate::ConstantBitrate(kDefaultTargetBitrate)),
       input_required_(false),
       main_client_task_runner_(base::SequencedTaskRunnerHandle::Get()),
-      encoder_thread_("MFEncoderThread") {}
+      encoder_thread_task_runner_(
+          base::ThreadPool::CreateCOMSTATaskRunner({})) {
+  encoder_weak_ptr_ = encoder_task_weak_factory_.GetWeakPtr();
+}
 
 MediaFoundationVideoEncodeAccelerator::
     ~MediaFoundationVideoEncodeAccelerator() {
   DVLOG(3) << __func__;
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  DCHECK(!encoder_thread_.IsRunning());
   DCHECK(!encoder_task_weak_factory_.HasWeakPtrs());
 }
 
@@ -325,12 +328,6 @@
     return false;
   }
 
-  encoder_thread_.init_com_with_mta(false);
-  if (!encoder_thread_.Start()) {
-    DLOG(ERROR) << "Failed spawning encoder thread.";
-    return false;
-  }
-  encoder_thread_task_runner_ = encoder_thread_.task_runner();
   IMFActivate** pp_activate = nullptr;
   uint32_t encoder_count = EnumerateHardwareEncoders(codec_, &pp_activate);
   if (!encoder_count) {
@@ -450,8 +447,7 @@
   encoder_thread_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&MediaFoundationVideoEncodeAccelerator::EncodeTask,
-                     encoder_task_weak_factory_.GetWeakPtr(), std::move(frame),
-                     force_keyframe));
+                     encoder_weak_ptr_, std::move(frame), force_keyframe));
 }
 
 void MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBuffer(
@@ -483,7 +479,7 @@
       FROM_HERE,
       base::BindOnce(
           &MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBufferTask,
-          encoder_task_weak_factory_.GetWeakPtr(), std::move(buffer_ref)));
+          encoder_weak_ptr_, std::move(buffer_ref)));
 }
 
 void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChange(
@@ -496,8 +492,7 @@
   encoder_thread_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&MediaFoundationVideoEncodeAccelerator::
                                     RequestEncodingParametersChangeTask,
-                                encoder_task_weak_factory_.GetWeakPtr(),
-                                bitrate, framerate));
+                                encoder_weak_ptr_, bitrate, framerate));
 }
 
 void MediaFoundationVideoEncodeAccelerator::Destroy() {
@@ -507,15 +502,17 @@
   // Cancel all callbacks.
   main_client_weak_factory_.reset();
 
-  if (encoder_thread_.IsRunning()) {
-    encoder_thread_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&MediaFoundationVideoEncodeAccelerator::DestroyTask,
-                       encoder_task_weak_factory_.GetWeakPtr()));
-    encoder_thread_.Stop();
-  }
-
-  delete this;
+  // MF resources need to be cleaned up on |encoder_thread_task_runner_|,
+  // but the object itself is supposed to be deleted on this runner, so when
+  // DestroyTask() is done we schedule deletion of |this|
+  auto delete_self = [](MediaFoundationVideoEncodeAccelerator* self) {
+    delete self;
+  };
+  encoder_thread_task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(&MediaFoundationVideoEncodeAccelerator::DestroyTask,
+                     encoder_weak_ptr_),
+      base::BindOnce(delete_self, base::Unretained(this)));
 }
 
 bool MediaFoundationVideoEncodeAccelerator::IsGpuFrameResizeSupported() {
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
index 92ccfbf1..25c1591 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
@@ -201,9 +201,8 @@
   scoped_refptr<base::SequencedTaskRunner> main_client_task_runner_;
   SEQUENCE_CHECKER(sequence_checker_);
 
-  // This thread services tasks posted from the VEA API entry points by the
-  // GPU child thread and CompressionCallback() posted from device thread.
-  base::Thread encoder_thread_;
+  // This thread services tasks posted from the VEA API entry points
+  // and runs them on a thread that can do heavy work and call MF COM interface.
   scoped_refptr<base::SingleThreadTaskRunner> encoder_thread_task_runner_;
 
   // DXGI device manager for handling hardware input textures
@@ -211,6 +210,7 @@
 
   // Declared last to ensure that all weak pointers are invalidated before
   // other destructors run.
+  base::WeakPtr<MediaFoundationVideoEncodeAccelerator> encoder_weak_ptr_;
   base::WeakPtrFactory<MediaFoundationVideoEncodeAccelerator>
       encoder_task_weak_factory_{this};
 };
diff --git a/media/mojo/services/gpu_mojo_media_client.cc b/media/mojo/services/gpu_mojo_media_client.cc
index c91d9356..22688ec 100644
--- a/media/mojo/services/gpu_mojo_media_client.cc
+++ b/media/mojo/services/gpu_mojo_media_client.cc
@@ -65,6 +65,7 @@
     const gfx::ColorSpace* target_color_space,
     gpu::GpuPreferences gpu_preferences,
     gpu::GpuFeatureInfo gpu_feature_info,
+    gpu::GPUInfo gpu_info,
     const gpu::GpuDriverBugWorkarounds* gpu_workarounds,
     gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
     GetConfigCacheCB get_cached_configs_cb,
@@ -77,6 +78,7 @@
       target_color_space(target_color_space),
       gpu_preferences(gpu_preferences),
       gpu_feature_info(gpu_feature_info),
+      gpu_info(gpu_info),
       gpu_workarounds(gpu_workarounds),
       gpu_memory_buffer_factory(gpu_memory_buffer_factory),
       get_cached_configs_cb(std::move(get_cached_configs_cb)),
@@ -87,6 +89,7 @@
     const gpu::GpuPreferences& gpu_preferences,
     const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
     const gpu::GpuFeatureInfo& gpu_feature_info,
+    const gpu::GPUInfo& gpu_info,
     scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
     base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
     gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
@@ -94,6 +97,7 @@
     : gpu_preferences_(gpu_preferences),
       gpu_workarounds_(gpu_workarounds),
       gpu_feature_info_(gpu_feature_info),
+      gpu_info_(gpu_info),
       gpu_task_runner_(std::move(gpu_task_runner)),
       media_gpu_channel_manager_(std::move(media_gpu_channel_manager)),
       android_overlay_factory_cb_(std::move(android_overlay_factory_cb)),
@@ -108,14 +112,14 @@
 
 VideoDecoderType GpuMojoMediaClient::GetDecoderImplementationType() {
   return GetPlatformDecoderImplementationType(gpu_workarounds_,
-                                              gpu_preferences_);
+                                              gpu_preferences_, gpu_info_);
 }
 
 SupportedVideoDecoderConfigs
 GpuMojoMediaClient::GetSupportedVideoDecoderConfigs() {
   if (!supported_config_cache_)
     supported_config_cache_ = GetPlatformSupportedVideoDecoderConfigs(
-        gpu_workarounds_, gpu_preferences_,
+        gpu_workarounds_, gpu_preferences_, gpu_info_,
         // GetPlatformSupportedVideoDecoderConfigs runs this callback either
         // never or immediately, and will not store it, so |this| will outlive
         // the bound function.
@@ -153,7 +157,8 @@
   VideoDecoderTraits traits(
       task_runner, gpu_task_runner_, std::move(log),
       std::move(request_overlay_info_cb), &target_color_space, gpu_preferences_,
-      gpu_feature_info_, &gpu_workarounds_, gpu_memory_buffer_factory_,
+      gpu_feature_info_, gpu_info_, &gpu_workarounds_,
+      gpu_memory_buffer_factory_,
       // CreatePlatformVideoDecoder does not keep a reference to |traits|
       // so this bound method will not outlive |this|
       base::BindRepeating(&GpuMojoMediaClient::GetSupportedVideoDecoderConfigs,
diff --git a/media/mojo/services/gpu_mojo_media_client.h b/media/mojo/services/gpu_mojo_media_client.h
index 5dab4501..384cf07e 100644
--- a/media/mojo/services/gpu_mojo_media_client.h
+++ b/media/mojo/services/gpu_mojo_media_client.h
@@ -13,6 +13,7 @@
 #include "build/build_config.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "gpu/config/gpu_feature_info.h"
+#include "gpu/config/gpu_info.h"
 #include "gpu/config/gpu_preferences.h"
 #include "gpu/ipc/service/command_buffer_stub.h"
 #include "media/base/android_overlay_mojo_factory.h"
@@ -44,6 +45,7 @@
   const gfx::ColorSpace* const target_color_space;
   gpu::GpuPreferences gpu_preferences;
   gpu::GpuFeatureInfo gpu_feature_info;
+  gpu::GPUInfo gpu_info;
   const gpu::GpuDriverBugWorkarounds* const gpu_workarounds;
   gpu::GpuMemoryBufferFactory* const gpu_memory_buffer_factory;
 
@@ -63,6 +65,7 @@
       const gfx::ColorSpace* target_color_space,
       gpu::GpuPreferences gpu_preferences,
       gpu::GpuFeatureInfo gpu_feature_info,
+      gpu::GPUInfo gpu_info,
       const gpu::GpuDriverBugWorkarounds* gpu_workarounds,
       gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
       GetConfigCacheCB get_cached_configs_cb,
@@ -85,6 +88,7 @@
 GetPlatformSupportedVideoDecoderConfigs(
     gpu::GpuDriverBugWorkarounds gpu_workarounds,
     gpu::GpuPreferences gpu_preferences,
+    const gpu::GPUInfo& gpu_info,
     base::OnceCallback<SupportedVideoDecoderConfigs()> get_vda_configs);
 
 // Creates a platform-specific media::AudioDecoder. Most platforms don't do
@@ -99,7 +103,8 @@
 // Queries the platform decoder type.
 VideoDecoderType GetPlatformDecoderImplementationType(
     gpu::GpuDriverBugWorkarounds gpu_workarounds,
-    gpu::GpuPreferences gpu_preferences);
+    gpu::GpuPreferences gpu_preferences,
+    const gpu::GPUInfo& gpu_info);
 
 class GpuMojoMediaClient final : public MojoMediaClient {
  public:
@@ -109,6 +114,7 @@
       const gpu::GpuPreferences& gpu_preferences,
       const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
       const gpu::GpuFeatureInfo& gpu_feature_info,
+      const gpu::GPUInfo& gpu_info,
       scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
       base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
       gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
@@ -119,6 +125,8 @@
 
   ~GpuMojoMediaClient() final;
 
+  const gpu::GPUInfo& gpu_info() const { return gpu_info_; }
+
   // MojoMediaClient implementation.
   SupportedVideoDecoderConfigs GetSupportedVideoDecoderConfigs() final;
   VideoDecoderType GetDecoderImplementationType() final;
@@ -144,6 +152,7 @@
   gpu::GpuPreferences gpu_preferences_;
   gpu::GpuDriverBugWorkarounds gpu_workarounds_;
   gpu::GpuFeatureInfo gpu_feature_info_;
+  gpu::GPUInfo gpu_info_;
   scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
   base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager_;
   AndroidOverlayMojoFactoryCB android_overlay_factory_cb_;
diff --git a/media/mojo/services/gpu_mojo_media_client_android.cc b/media/mojo/services/gpu_mojo_media_client_android.cc
index b155d36..7491660 100644
--- a/media/mojo/services/gpu_mojo_media_client_android.cc
+++ b/media/mojo/services/gpu_mojo_media_client_android.cc
@@ -84,6 +84,7 @@
 GetPlatformSupportedVideoDecoderConfigs(
     gpu::GpuDriverBugWorkarounds gpu_workarounds,
     gpu::GpuPreferences gpu_preferences,
+    const gpu::GPUInfo& gpu_info,
     base::OnceCallback<SupportedVideoDecoderConfigs()> get_vda_configs) {
   return MediaCodecVideoDecoder::GetSupportedConfigs();
 }
@@ -102,7 +103,8 @@
 
 VideoDecoderType GetPlatformDecoderImplementationType(
     gpu::GpuDriverBugWorkarounds gpu_workarounds,
-    gpu::GpuPreferences gpu_preferences) {
+    gpu::GpuPreferences gpu_preferences,
+    const gpu::GPUInfo& gpu_info) {
   return VideoDecoderType::kMediaCodec;
 }
 
diff --git a/media/mojo/services/gpu_mojo_media_client_cros.cc b/media/mojo/services/gpu_mojo_media_client_cros.cc
index 1ae2a0d..b767da39 100644
--- a/media/mojo/services/gpu_mojo_media_client_cros.cc
+++ b/media/mojo/services/gpu_mojo_media_client_cros.cc
@@ -5,6 +5,7 @@
 #include "media/mojo/services/gpu_mojo_media_client.h"
 
 #include "media/base/audio_decoder.h"
+#include "media/base/media_switches.h"
 #include "media/gpu/chromeos/mailbox_video_frame_converter.h"
 #include "media/gpu/chromeos/platform_video_frame_pool.h"
 #include "media/gpu/chromeos/video_decoder_pipeline.h"
@@ -18,9 +19,21 @@
 namespace {
 
 bool ShouldUseChromeOSDirectVideoDecoder(
-    const gpu::GpuPreferences& gpu_preferences) {
+    const gpu::GpuPreferences& gpu_preferences,
+    const gpu::GPUInfo& gpu_info) {
 #if defined(OS_CHROMEOS)
   return gpu_preferences.enable_chromeos_direct_video_decoder;
+#elif BUILDFLAG(ENABLE_VULKAN)
+  if (!base::FeatureList::IsEnabled(kVaapiVideoDecodeLinux))
+    return false;
+  for (const auto& device : gpu_info.vulkan_info->physical_devices) {
+    if (device.properties.driverVersion < VK_MAKE_VERSION(21, 1, 5))
+      return false;
+  }
+  // CL note: Should this be a "return true if any device is >21.1.5" or
+  //                           "return false if any device is <21.1.5".
+  // It's the later right now, but I'm not sure that's right.
+  return true;
 #else
   return false;
 #endif
@@ -30,7 +43,8 @@
 
 std::unique_ptr<VideoDecoder> CreatePlatformVideoDecoder(
     const VideoDecoderTraits& traits) {
-  if (ShouldUseChromeOSDirectVideoDecoder(traits.gpu_preferences)) {
+  if (ShouldUseChromeOSDirectVideoDecoder(traits.gpu_preferences,
+                                          traits.gpu_info)) {
     auto frame_pool = std::make_unique<PlatformVideoFramePool>(
         traits.gpu_memory_buffer_factory);
     auto frame_converter = MailboxVideoFrameConverter::Create(
@@ -51,20 +65,20 @@
 GetPlatformSupportedVideoDecoderConfigs(
     gpu::GpuDriverBugWorkarounds gpu_workarounds,
     gpu::GpuPreferences gpu_preferences,
+    const gpu::GPUInfo& gpu_info,
     base::OnceCallback<SupportedVideoDecoderConfigs()> get_vda_configs) {
   SupportedVideoDecoderConfigs supported_configs;
-  if (ShouldUseChromeOSDirectVideoDecoder(gpu_preferences)) {
+  if (ShouldUseChromeOSDirectVideoDecoder(gpu_preferences, gpu_info))
     return VideoDecoderPipeline::GetSupportedConfigs(gpu_workarounds);
-  }
   return std::move(get_vda_configs).Run();
 }
 
 VideoDecoderType GetPlatformDecoderImplementationType(
     gpu::GpuDriverBugWorkarounds gpu_workarounds,
-    gpu::GpuPreferences gpu_preferences) {
-  if (ShouldUseChromeOSDirectVideoDecoder(gpu_preferences)) {
+    gpu::GpuPreferences gpu_preferences,
+    const gpu::GPUInfo& gpu_info) {
+  if (ShouldUseChromeOSDirectVideoDecoder(gpu_preferences, gpu_info))
     return VideoDecoderType::kVaapi;
-  }
   return VideoDecoderType::kVda;
 }
 
@@ -86,4 +100,4 @@
 #endif  // else defined(OS_CHROMEOS)
 }
 
-}  // namespace media
+}  // namespace media
\ No newline at end of file
diff --git a/media/mojo/services/gpu_mojo_media_client_mac.cc b/media/mojo/services/gpu_mojo_media_client_mac.cc
index fad1ca3..a5b519a2 100644
--- a/media/mojo/services/gpu_mojo_media_client_mac.cc
+++ b/media/mojo/services/gpu_mojo_media_client_mac.cc
@@ -20,6 +20,7 @@
 GetPlatformSupportedVideoDecoderConfigs(
     gpu::GpuDriverBugWorkarounds gpu_workarounds,
     gpu::GpuPreferences gpu_preferences,
+    const gpu::GPUInfo& gpu_info,
     base::OnceCallback<SupportedVideoDecoderConfigs()> get_vda_configs) {
   return std::move(get_vda_configs).Run();
 }
@@ -39,7 +40,8 @@
 
 VideoDecoderType GetPlatformDecoderImplementationType(
     gpu::GpuDriverBugWorkarounds gpu_workarounds,
-    gpu::GpuPreferences gpu_preferences) {
+    gpu::GpuPreferences gpu_preferences,
+    const gpu::GPUInfo& gpu_info) {
   return VideoDecoderType::kVda;
 }
 
diff --git a/media/mojo/services/gpu_mojo_media_client_stubs.cc b/media/mojo/services/gpu_mojo_media_client_stubs.cc
index 135bd87a..858919d6 100644
--- a/media/mojo/services/gpu_mojo_media_client_stubs.cc
+++ b/media/mojo/services/gpu_mojo_media_client_stubs.cc
@@ -17,6 +17,7 @@
 GetPlatformSupportedVideoDecoderConfigs(
     gpu::GpuDriverBugWorkarounds gpu_workarounds,
     gpu::GpuPreferences gpu_preferences,
+    const gpu::GPUInfo& gpu_info,
     base::OnceCallback<SupportedVideoDecoderConfigs()> get_vda_configs) {
   return {};
 }
@@ -36,7 +37,8 @@
 
 VideoDecoderType GetPlatformDecoderImplementationType(
     gpu::GpuDriverBugWorkarounds gpu_workarounds,
-    gpu::GpuPreferences gpu_preferences) {
+    gpu::GpuPreferences gpu_preferences,
+    const gpu::GPUInfo& gpu_info) {
   return VideoDecoderType::kUnknown;
 }
 
diff --git a/media/mojo/services/gpu_mojo_media_client_win.cc b/media/mojo/services/gpu_mojo_media_client_win.cc
index 730f5698..dfd098b 100644
--- a/media/mojo/services/gpu_mojo_media_client_win.cc
+++ b/media/mojo/services/gpu_mojo_media_client_win.cc
@@ -56,6 +56,7 @@
 GetPlatformSupportedVideoDecoderConfigs(
     gpu::GpuDriverBugWorkarounds gpu_workarounds,
     gpu::GpuPreferences gpu_preferences,
+    const gpu::GPUInfo& gpu_info,
     base::OnceCallback<SupportedVideoDecoderConfigs()> get_vda_configs) {
   SupportedVideoDecoderConfigs supported_configs;
   if (ShouldUseD3D11VideoDecoder(gpu_workarounds)) {
@@ -74,7 +75,8 @@
 
 VideoDecoderType GetPlatformDecoderImplementationType(
     gpu::GpuDriverBugWorkarounds gpu_workarounds,
-    gpu::GpuPreferences gpu_preferences) {
+    gpu::GpuPreferences gpu_preferences,
+    const gpu::GPUInfo& gpu_info) {
   if (!ShouldUseD3D11VideoDecoder(gpu_workarounds))
     return VideoDecoderType::kVda;
   return VideoDecoderType::kD3D11;
diff --git a/media/mojo/services/media_service_factory.cc b/media/mojo/services/media_service_factory.cc
index cf22105..007a592 100644
--- a/media/mojo/services/media_service_factory.cc
+++ b/media/mojo/services/media_service_factory.cc
@@ -38,14 +38,15 @@
     const gpu::GpuPreferences& gpu_preferences,
     const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
     const gpu::GpuFeatureInfo& gpu_feature_info,
+    const gpu::GPUInfo& gpu_info,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
     gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
     AndroidOverlayMojoFactoryCB android_overlay_factory_cb) {
   return std::make_unique<MediaService>(
       std::make_unique<GpuMojoMediaClient>(
-          gpu_preferences, gpu_workarounds, gpu_feature_info, task_runner,
-          media_gpu_channel_manager, gpu_memory_buffer_factory,
+          gpu_preferences, gpu_workarounds, gpu_feature_info, gpu_info,
+          task_runner, media_gpu_channel_manager, gpu_memory_buffer_factory,
           std::move(android_overlay_factory_cb)),
       std::move(receiver));
 }
diff --git a/media/mojo/services/media_service_factory.h b/media/mojo/services/media_service_factory.h
index 8a79bf5..37b0bfa 100644
--- a/media/mojo/services/media_service_factory.h
+++ b/media/mojo/services/media_service_factory.h
@@ -13,6 +13,7 @@
 #include "build/build_config.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "gpu/config/gpu_feature_info.h"
+#include "gpu/config/gpu_info.h"
 #include "gpu/config/gpu_preferences.h"
 #include "media/base/android_overlay_mojo_factory.h"
 #include "media/mojo/mojom/media_service.mojom.h"
@@ -41,6 +42,7 @@
     const gpu::GpuPreferences& gpu_preferences,
     const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
     const gpu::GpuFeatureInfo& gpu_feature_info,
+    const gpu::GPUInfo& gpu_info,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
     gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
diff --git a/media/mojo/services/mojo_video_encode_accelerator_provider.cc b/media/mojo/services/mojo_video_encode_accelerator_provider.cc
index 2e46d47..e695bd6 100644
--- a/media/mojo/services/mojo_video_encode_accelerator_provider.cc
+++ b/media/mojo/services/mojo_video_encode_accelerator_provider.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <utility>
 
-#include "base/no_destructor.h"
 #include "base/task/thread_pool.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/limits.h"
@@ -42,17 +41,10 @@
   // and creating encoder might take quite some time, and they might block
   // processing of other mojo calls if executed on the current runner.
   //
-  // This runner needs to use sync primitives (and be DEDICATED) because
-  // MediaFoundationVEA waits for the encoding thread to stop when
-  // destroyed. Since a dedicated runner is basically a separate thread, it's
-  // declared static to avoid creation of a new thread for each renderer with
-  // GPU factories.
-  static base::NoDestructor<scoped_refptr<base::SingleThreadTaskRunner>> runner(
-      base::ThreadPool::CreateSingleThreadTaskRunner(
-          {base::TaskPriority::USER_BLOCKING, base::WithBaseSyncPrimitives()},
-          base::SingleThreadTaskRunnerThreadMode::DEDICATED));
-
-  (*runner)->PostTask(
+  // MayBlock() because MF VEA can take long time running GetSupportedProfiles()
+  auto runner =
+      base::ThreadPool::CreateSingleThreadTaskRunner({base::MayBlock()});
+  runner->PostTask(
       FROM_HERE, base::BindOnce(BindVEAProvider, std::move(receiver),
                                 std::move(create_vea_callback), gpu_preferences,
                                 gpu_workarounds));
diff --git a/media/video/openh264_video_encoder.cc b/media/video/openh264_video_encoder.cc
index a20ec00..bb1218e3 100644
--- a/media/video/openh264_video_encoder.cc
+++ b/media/video/openh264_video_encoder.cc
@@ -170,10 +170,12 @@
 }
 
 Status OpenH264VideoEncoder::DrainOutputs(const SFrameBSInfo& frame_info,
-                                          base::TimeDelta timestamp) {
+                                          base::TimeDelta timestamp,
+                                          gfx::ColorSpace color_space) {
   VideoEncoderOutput result;
   result.key_frame = (frame_info.eFrameType == videoFrameTypeIDR);
   result.timestamp = timestamp;
+  result.color_space = color_space;
 
   DCHECK_GT(frame_info.iFrameSizeInBytes, 0);
   size_t total_chunk_size = frame_info.iFrameSizeInBytes;
@@ -301,6 +303,11 @@
     frame = std::move(i420_frame);
   }
 
+  if (last_frame_color_space_ != frame->ColorSpace()) {
+    last_frame_color_space_ = frame->ColorSpace();
+    key_frame = true;
+  }
+
   SSourcePicture picture = {};
   picture.iPicWidth = frame->visible_rect().width();
   picture.iPicHeight = frame->visible_rect().height();
@@ -331,7 +338,7 @@
     return;
   }
 
-  status = DrainOutputs(frame_info, frame->timestamp());
+  status = DrainOutputs(frame_info, frame->timestamp(), frame->ColorSpace());
   std::move(done_cb).Run(std::move(status));
 }
 
diff --git a/media/video/openh264_video_encoder.h b/media/video/openh264_video_encoder.h
index 11caf10..f3fb9cb 100644
--- a/media/video/openh264_video_encoder.h
+++ b/media/video/openh264_video_encoder.h
@@ -37,7 +37,8 @@
 
  private:
   Status DrainOutputs(const SFrameBSInfo& frame_info,
-                      base::TimeDelta timestamp);
+                      base::TimeDelta timestamp,
+                      gfx::ColorSpace color_space);
 
   class ISVCEncoderDeleter {
    public:
@@ -60,6 +61,7 @@
   OutputCB output_cb_;
   std::vector<uint8_t> conversion_buffer_;
   VideoFramePool frame_pool_;
+  gfx::ColorSpace last_frame_color_space_;
 
   // If |h264_converter_| is null, we output in annexb format. Otherwise, we
   // output in avc format.
diff --git a/media/video/video_encode_accelerator_adapter.cc b/media/video/video_encode_accelerator_adapter.cc
index 83c3042..43d2296f 100644
--- a/media/video/video_encode_accelerator_adapter.cc
+++ b/media/video/video_encode_accelerator_adapter.cc
@@ -321,9 +321,15 @@
 
   frame = std::move(result).value();
 
+  if (last_frame_color_space_ != frame->ColorSpace()) {
+    last_frame_color_space_ = frame->ColorSpace();
+    key_frame = true;
+  }
+
   auto active_encode = std::make_unique<PendingOp>();
   active_encode->done_callback = std::move(done_cb);
   active_encode->timestamp = frame->timestamp();
+  active_encode->color_space = frame->ColorSpace();
   active_encodes_.push_back(std::move(active_encode));
   accelerator_->Encode(frame, key_frame);
 }
@@ -531,13 +537,17 @@
   accelerator_->UseOutputBitstreamBuffer(
       BitstreamBuffer(buffer_id, region.Duplicate(), region.GetSize()));
 
+  bool erased_active_encode = false;
   for (auto it = active_encodes_.begin(); it != active_encodes_.end(); ++it) {
     if ((*it)->timestamp == result.timestamp) {
+      result.color_space = (*it)->color_space;
       std::move((*it)->done_callback).Run(Status());
       active_encodes_.erase(it);
+      erased_active_encode = true;
       break;
     }
   }
+  DCHECK(erased_active_encode);
   output_cb_.Run(std::move(result), std::move(desc));
   if (active_encodes_.empty() && !flush_support_.value()) {
     // Manually call FlushCompleted(), since |accelerator_| won't do it for us.
diff --git a/media/video/video_encode_accelerator_adapter.h b/media/video/video_encode_accelerator_adapter.h
index 47648a8..ede2cc1d 100644
--- a/media/video/video_encode_accelerator_adapter.h
+++ b/media/video/video_encode_accelerator_adapter.h
@@ -17,6 +17,7 @@
 #include "media/base/video_encoder.h"
 #include "media/video/video_encode_accelerator.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace base {
@@ -87,6 +88,7 @@
 
     StatusCB done_callback;
     base::TimeDelta timestamp;
+    gfx::ColorSpace color_space;
   };
 
   void FlushCompleted(bool success);
@@ -131,6 +133,9 @@
   // had their encoded data returned via BitstreamBufferReady().
   base::circular_deque<std::unique_ptr<PendingOp>> active_encodes_;
 
+  // Color space associated w/ the last frame sent to accelerator for encoding.
+  gfx::ColorSpace last_frame_color_space_;
+
   std::unique_ptr<PendingOp> pending_flush_;
 
   // For calling accelerator_ methods
diff --git a/net/base/cache_type.h b/net/base/cache_type.h
index afb12b4..9a9a002 100644
--- a/net/base/cache_type.h
+++ b/net/base/cache_type.h
@@ -14,7 +14,9 @@
   DISK_CACHE,                 // Disk is used as the backing storage.
   MEMORY_CACHE,               // Data is stored only in memory.
   REMOVED_MEDIA_CACHE,        // No longer in use.
-  APP_CACHE,                  // Backing store for an AppCache.
+  APP_CACHE,                  // Special case of DISK_CACHE.  Optimizes for
+                              // cases where auto-eviction is not desired:
+                              // e.g. cache_storage, service worker script cache
   SHADER_CACHE,               // Backing store for the GL shader cache.
   PNACL_CACHE,                // Backing store the PNaCl translation cache
   GENERATED_BYTE_CODE_CACHE,  // Backing store for renderer generated data like
diff --git a/net/cookies/cookie_partition_key.h b/net/cookies/cookie_partition_key.h
index 925aa67c..64f39bbe 100644
--- a/net/cookies/cookie_partition_key.h
+++ b/net/cookies/cookie_partition_key.h
@@ -50,8 +50,11 @@
                           absl::optional<CookiePartitionKey>& out)
       WARN_UNUSED_RESULT;
 
-  static CookiePartitionKey FromURLForTesting(const GURL& url) {
-    return CookiePartitionKey(url);
+  static CookiePartitionKey FromURLForTesting(
+      const GURL& url,
+      const absl::optional<base::UnguessableToken> nonce = absl::nullopt) {
+    return nonce ? CookiePartitionKey(SchemefulSite(url), nonce)
+                 : CookiePartitionKey(url);
   }
 
   // Create a cookie partition key from a request's NetworkIsolationKey.
diff --git a/net/cookies/cookie_partition_key_unittest.cc b/net/cookies/cookie_partition_key_unittest.cc
index 83b6d33..1c7a1831 100644
--- a/net/cookies/cookie_partition_key_unittest.cc
+++ b/net/cookies/cookie_partition_key_unittest.cc
@@ -133,45 +133,44 @@
   }
 }
 
-TEST_P(CookiePartitionKeyTest, FromNetworkIsolationKeyWithNonce) {
-  SchemefulSite top_level_site =
+TEST_P(CookiePartitionKeyTest, FromNetworkIsolationKey_WithNonce) {
+  const SchemefulSite kTopLevelSite =
       SchemefulSite(GURL("https://toplevelsite.com"));
-  base::UnguessableToken nonce = base::UnguessableToken::Create();
+  const base::UnguessableToken kNonce = base::UnguessableToken::Create();
+
   absl::optional<CookiePartitionKey> got =
       CookiePartitionKey::FromNetworkIsolationKey(NetworkIsolationKey(
-          top_level_site, SchemefulSite(GURL("https://cookiesite.com")),
-          &nonce));
+          kTopLevelSite, SchemefulSite(GURL("https://cookiesite.com")),
+          &kNonce));
   bool partitioned_cookies_enabled = PartitionedCookiesEnabled();
   EXPECT_EQ(partitioned_cookies_enabled, got.has_value());
   if (!partitioned_cookies_enabled)
     return;
 
-  EXPECT_TRUE(got.has_value());
   EXPECT_FALSE(got->from_script());
-  EXPECT_TRUE(got->nonce().has_value());
-  EXPECT_EQ(nonce, got->nonce().value());
+  EXPECT_TRUE(got->nonce());
+  EXPECT_EQ(kTopLevelSite, got->site());
+  EXPECT_EQ(kNonce, got->nonce().value());
 }
 
 TEST_P(CookiePartitionKeyTest, FromWire) {
-  auto want = CookiePartitionKey::FromURLForTesting(GURL("https://foo.com"));
-  auto got = CookiePartitionKey::FromWire(want.site(), want.nonce());
-  EXPECT_EQ(want, got);
-  EXPECT_FALSE(got.from_script());
-}
+  struct TestCase {
+    const GURL url;
+    const absl::optional<base::UnguessableToken> nonce;
+  } test_cases[] = {
+      {GURL("https://foo.com"), absl::nullopt},
+      {GURL(), absl::nullopt},
+      {GURL("https://foo.com"),
+       absl::make_optional(base::UnguessableToken::Create())},
+  };
 
-TEST_P(CookiePartitionKeyTest, FromWireWithNonce) {
-  SchemefulSite top_level_site =
-      SchemefulSite(GURL("https://toplevelsite.com"));
-  base::UnguessableToken nonce = base::UnguessableToken::Create();
-  auto want = CookiePartitionKey::FromNetworkIsolationKey(NetworkIsolationKey(
-      top_level_site, SchemefulSite(GURL("https://cookiesite.com")), &nonce));
-  bool partitioned_cookies_enabled = PartitionedCookiesEnabled();
-  EXPECT_EQ(partitioned_cookies_enabled, want.has_value());
-  if (!partitioned_cookies_enabled)
-    return;
-  auto got = CookiePartitionKey::FromWire(want->site(), want->nonce());
-  EXPECT_EQ(want, got);
-  EXPECT_FALSE(got.from_script());
+  for (const auto& test_case : test_cases) {
+    auto want =
+        CookiePartitionKey::FromURLForTesting(test_case.url, test_case.nonce);
+    auto got = CookiePartitionKey::FromWire(want.site(), want.nonce());
+    EXPECT_EQ(want, got);
+    EXPECT_FALSE(got.from_script());
+  }
 }
 
 TEST_P(CookiePartitionKeyTest, FromScript) {
@@ -188,7 +187,7 @@
                                              .IsSerializeable());
 }
 
-TEST_P(CookiePartitionKeyTest, EqualityWithNonce) {
+TEST_P(CookiePartitionKeyTest, Equality_WithNonce) {
   SchemefulSite top_level_site =
       SchemefulSite(GURL("https://toplevelsite.com"));
   SchemefulSite frame_site = SchemefulSite(GURL("https://cookiesite.com"));
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index c3826a27..50f16643 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -1775,7 +1775,6 @@
     { "name": "fewo-thueringer-wald.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "food4health.guide", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "johners.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "kdyby.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "kupschke.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "manicode.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ouvirmusica.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -3628,7 +3627,6 @@
     { "name": "zzsec.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "33-km.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "42ms.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "abeestrada.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "adamradocz.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "aladdin.ie", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "alarmsystemreviews.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -4064,7 +4062,6 @@
     { "name": "poon.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "poon.tech", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pr1sm.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "premierheart.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pressrush.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "proxybay.la", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ptm.ro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -7406,7 +7403,6 @@
     { "name": "planete-cocoon.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "plexusmd.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "politologos.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "polypet.com.sg", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "posylka.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pro-link.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "punknews.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -9207,7 +9203,6 @@
     { "name": "pepperhead.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "perfectseourl.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "performous.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "perspectivum.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pet-nsk.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pewboards.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pfarchimedes-pensioen123.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -9739,7 +9734,6 @@
     { "name": "tsrstore.gq", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tubepro.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "turnik-67.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "turtle.ai", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "turtlementors.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tuxcloud.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "twarog.cc", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -12205,7 +12199,6 @@
     { "name": "goto.world", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "gracethrufaith.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "grademymac.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "grandwailea.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "greenaddress.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "greg.red", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "groenaquasolutions.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -13417,7 +13410,6 @@
     { "name": "alexismeza.com.mx", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "alexismeza.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ameza.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "builditsolutions.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bws16.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "campaign.gov.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "c-webdesign.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -16304,7 +16296,6 @@
     { "name": "alexismeza.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "alexismeza.es", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "biointelligence-explosion.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "ameza.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bluemoonroleplaying.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ameza.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "biopsychiatry.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -16497,7 +16488,6 @@
     { "name": "computerbase.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cookie4.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cognitivecomputingconsortium.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "creepypastas.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "csmainframe.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cryptoshot.pw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "codedump.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -17368,7 +17358,6 @@
     { "name": "moovablestorage.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "musewearflipflops.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "michelledonelan.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "mokadev.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "mhermans.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "mondedie.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "mticareportal.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -17666,7 +17655,6 @@
     { "name": "rca.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "rehabthailand.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "rtejr.ie", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "real-compare.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "rogerriendeau.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "quality1.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "roelof.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -17896,7 +17884,6 @@
     { "name": "teachmeplease.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "teachmeplease.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "strangeplace.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "teacherph.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "teacherph.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "suempresa.cloud", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "sysadminstory.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -18029,7 +18016,6 @@
     { "name": "turkrock.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "topnotepad.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "totalprint.hu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "uefeng.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "touchoflife.in", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "v2bv.win", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "twelverocks.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -18177,7 +18163,6 @@
     { "name": "vrijstaandhuis-in-zuid-holland-kopen.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vuljespaarpot.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "warumsuchen.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "wbvb.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "xbtmusic.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "xtom.email", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "wnmm.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -19165,13 +19150,11 @@
     { "name": "hardyboyplant.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "heckelektro.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "hitterfamily.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "hgbet.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "hitter-lauzon.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "hentaimaster.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "gutuia.blue", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "hmksq.ae", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "handicapindeles.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "hosts.cf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "higilopocht.li", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "hitter.family", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "hotartup.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -19192,7 +19175,6 @@
     { "name": "httpsnow.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "herni-kupony.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "httphacker.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "hgw168.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "helikon.ro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "howtogeek.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "hilinemerchandising.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -19456,7 +19438,6 @@
     { "name": "laserplaza.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "la-retraite-info.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "leerkotte.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "lerlivros.online", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "laboxfaitsoncinema.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "kevinkla.es", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "legioniv.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -20760,7 +20741,6 @@
     { "name": "burcevo.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "buzztelco.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "by77.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "by777.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bypass.kr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cafelandia.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cafeobscura.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -25632,7 +25612,6 @@
     { "name": "cyumus.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dallaslu.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cs2016.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "defender-pro.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dailykos.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dalb.in", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "daw.nz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -26842,7 +26821,6 @@
     { "name": "neostralis.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nella.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nickcraver.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "newaccess.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nicolasiung.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "night2stay.cn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nebulae.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -27122,7 +27100,6 @@
     { "name": "promods.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "privacyscore.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "propepper.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "prodinger.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "proactive.run", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "productpeo.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "qbnt.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -27141,7 +27118,6 @@
     { "name": "quickandroid.tools", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "plushev.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pugilares.com.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "rallycycling.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "provisionaldriving.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "quay.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "psydix.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -27431,7 +27407,6 @@
     { "name": "skatingchina.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "smallshopit.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "smiledirectsales.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "singee.site", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "slip-gaming.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "sma-gift.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "silvergoldbull.co.tz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -27601,7 +27576,6 @@
     { "name": "taartenfeesies.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "suzi3d.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tatiloley.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "tchnics.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "techshift.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "techshift.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "symbiose-bien-etre.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -28390,7 +28364,6 @@
     { "name": "casapalla.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "casamorelli.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ch-laborit.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "chrisbrakebill.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cheeseemergency.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "burlesquemakeup.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ci-fo.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -29061,7 +29034,6 @@
     { "name": "luisyr.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "luginbuehl.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "lommyfleet.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "lonbali.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "liviababynet.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "lohanaflores.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "lojadewhisky.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -29833,7 +29805,6 @@
     { "name": "vadennissanofhiltonheadparts.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "valenciadevops.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "u4mh-dev-portal.azurewebsites.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "uxux.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "viaje-a-china.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "viaggio-in-cina.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "u4mh-dev-accesscontroller.azurewebsites.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -29949,7 +29920,6 @@
     { "name": "x-lan.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "windowwellcovers.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "torontocorporatelimo.services", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "xlfblog.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "xlan.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "xiangblog.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ymtsonline.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -31014,7 +30984,6 @@
     { "name": "vierdaagsehotel.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "viltsu.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "virtusaero.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "vivirenelmundo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "voltimax.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "voxfilmeonline.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "wahidhasan.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -31138,7 +31107,6 @@
     { "name": "ma-eir.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "mail4geek.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "masterhelenaroma.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "matchboxdesigngroup.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "maynardnetworks.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "mongla168.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "mongla88.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -34895,7 +34863,6 @@
     { "name": "concursos.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "consommateuraverti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "convergence.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "coslinker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cotta.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "creativedigital.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "creativesprite.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -36317,7 +36284,6 @@
     { "name": "scp500.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "searchgov.gov.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sebastiaandouma.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "shawnstarrcustomhomes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shieldcomputer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shutter-shower.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "siciliadisinfestazioni.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -36480,7 +36446,6 @@
     { "name": "alljamin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "allpropertyservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "allseasons-cleaning.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "alpinechaletrental.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "altaplana.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "alwaysonssl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "amalficoastchauffeur.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -39725,7 +39690,6 @@
     { "name": "caibi.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "canadian-nurse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "carbontv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "cardexchangesolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "carlobiagi.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "caryefurd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "catalogobiblioteca.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -39757,7 +39721,6 @@
     { "name": "combatircelulitis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "combattrecellulite.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "comodosslstore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "conju.cat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "constares.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "consultingroupitaly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cooljs.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -41300,7 +41263,6 @@
     { "name": "hartzer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hautaka.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "healthplansamerica.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "heka.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "helpscoutdocs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "herkam.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "herrtxbias.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -43244,7 +43206,6 @@
     { "name": "jeda.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jenniferengerwingaantrouwen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jeremypaul.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "jiazhao.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jimbiproducts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jmcataffo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jtl-software.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -44786,7 +44747,6 @@
     { "name": "marianelaisashi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "markdescande.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "marmolrain.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "martin.vet", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "martineweitweg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "masarik.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "maskim.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -44884,7 +44844,6 @@
     { "name": "oiaio.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "okna-tm.kz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "oldtimerreifen-moeller.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "olgui.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "omnilab.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "onemusou.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "onhistory.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -46046,7 +46005,6 @@
     { "name": "diamantovaburza.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dianafaraj.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "digitalhabit.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "digitalhabitat.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dimmersoakpark.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dmx.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dokspot.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -46468,7 +46426,6 @@
     { "name": "cp-st-martin.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "crickey.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "csbgtribalta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "csca.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "csu.st", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ctl.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "customfitbymj.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -47574,7 +47531,6 @@
     { "name": "bignumworks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "billionaire365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "binnenmeer.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "biomasscore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "birthright.website", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bit-service-aalter.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bitbox.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -47600,7 +47556,6 @@
     { "name": "burncorp.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "buycbd.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bztraveler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "bztraveler.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "c0rporation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cabineritten.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "calrotaract.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -47791,7 +47746,6 @@
     { "name": "emvoice.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "emyself.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "emyself.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "encore.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "enjoy-drive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "enpasenerji.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ensembling.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -47993,7 +47947,6 @@
     { "name": "joshruppe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "js93029.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jsdelivr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ju.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "juttaheitland.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jvandenbroeck.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jzcapital.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -48109,8 +48062,6 @@
     { "name": "murray.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "my-best-wishes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "myamihealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "myclasscam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "myclasscam.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "myhome-24.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "myinvite.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mylittlechat.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -48457,7 +48408,6 @@
     { "name": "thomasmerritt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "thoroughbreddiesel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "threit.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ticketmaze.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ticketrunway.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tilta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "timbers.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -48928,7 +48878,6 @@
     { "name": "mundomagicotv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mvisioncorp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mwezi-foundation.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "mwezi.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mygirlfriendshouse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "myweddingreceptionideas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "myxnr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -51190,7 +51139,6 @@
     { "name": "sakura.zone", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sakuracdn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "samanacafe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "samlaw.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "savingsoftheyear.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "schgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "schoeller.click", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -53166,7 +53114,6 @@
     { "name": "techglover.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "technospeakco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "techpilipinas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ted.do", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tenderplan.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "texashomesandland.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "the-big-bang-theory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -54262,7 +54209,6 @@
     { "name": "olsh-hilltown.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "olsonproperties.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "on.tax", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ondrejbudin.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "onkentessegertdij.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "onlinemarketingmuscle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "oposicionesapolicialocal.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -54500,7 +54446,6 @@
     { "name": "se-live.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "seamoo.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "searchfox.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "secretpigeon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "section77.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "securist.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "seedcoworking.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -54719,7 +54664,6 @@
     { "name": "vehicletransportservices.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "venusbymariatash.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "verboom.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "veri2.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "verificaprezzi.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "verkeersschoolrichardschut.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "versalhost.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -55885,7 +55829,6 @@
     { "name": "whollyskincare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "whqqq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wicharypawel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "wick-machinery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wildcatdiesel.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wildercerron.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "woblex.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -56595,7 +56538,6 @@
     { "name": "kennedyinsurancesolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kiarayoga.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kieran.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kii91.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kinecle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kipsu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kirchhoff-getraenke.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -56885,7 +56827,6 @@
     { "name": "piu.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pixshop.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pixulutinho.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "pjp.com.mt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "plantron.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "plastic-id.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "plumbercincoranch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -57145,7 +57086,6 @@
     { "name": "ufo-blogger.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ultramookie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "umzuege-berlin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "unik.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "united-german-commander.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "uoone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "urbangymfirenze.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -57831,7 +57771,6 @@
     { "name": "serverping.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sextfriend.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shapediver.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "shareeri.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sheenveininstitutestl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shopfinale.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "simplegoodhealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -61768,7 +61707,6 @@
     { "name": "myjuvelirika.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mytntware.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mywetpussycams.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "naga.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "naka.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "namalelaki.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "namaperempuan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -62874,7 +62812,6 @@
     { "name": "couponbates.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cpcp380.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cryptizy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "csjministriesfoundation.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "css125.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "curacaodiveguide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cxq77128.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -63068,7 +63005,6 @@
     { "name": "mywiwe.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nb10000.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "neev.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "neo2k.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "newenglandworkinjury.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "next-server.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nicolaottomano.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -63923,7 +63859,6 @@
     { "name": "v5197.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "v9297.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "v9728.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "v9728.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vancoevents.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vanderlest.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vehiclematsuk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -64947,7 +64882,6 @@
     { "name": "6729u.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "6729v.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "6729vv.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "6729vv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "6729w.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "6729w.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "6729ww.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -65486,7 +65420,6 @@
     { "name": "vipf88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vivo.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vtuber.land", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "vv6729.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vv6957.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "w6729.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "w6729.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -65499,7 +65432,6 @@
     { "name": "wikibuy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wowin88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ww6729.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ww6729.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ww6957.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "x6729.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xinbo190.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -67444,7 +67376,6 @@
     { "name": "salesblackbelt.coach", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sam-cousins.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sampleappservice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "sduconnect.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sellmymobile.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sender.services", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "simplycateringequipment.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68784,7 +68715,6 @@
     { "name": "3957f.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "3957g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "396302.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "396305.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "3963aa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "3963bb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "3963ee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -69150,8 +69080,6 @@
     { "name": "azora.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b-honey.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b0308.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "b03aa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "b03cc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b3333.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b36512.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b58365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -69203,14 +69131,11 @@
     { "name": "besttrade.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bestwebcams.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bet062.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "bet064.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bet06vip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "bet074.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bet07vip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bet08vip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bet09vip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bet290.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "bet3639.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bet365bc.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bet365cnq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bet365cnr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -72985,7 +72910,6 @@
     { "name": "ayudapreview.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b9618.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bankheadvegetables.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "bazar-24.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "behemot.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "belroyale.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bestgearlist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -73001,7 +72925,6 @@
     { "name": "brandingcoapps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bride-forever.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "briefkasten-welt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "btcbenthuizen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bugteam.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "burmesecats.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bwin58.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -73827,7 +73750,6 @@
     { "name": "bu-dun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "burmakatze.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "buttonizer.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "bwin18.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cc8822.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "chaturbate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "chcuscojungle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -73991,7 +73913,6 @@
     { "name": "nuva.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nxtgenbroadband.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nylasercenter.com.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "obu4alka.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "oe2018.gov.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "oe2019.gov.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "only.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -74290,7 +74211,6 @@
     { "name": "lonelypawn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "loverngifts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lz898.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "machinerysafety101.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "magicnethosting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "magicvps.md", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "marketing-apps.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -74390,7 +74310,6 @@
     { "name": "softly.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sonderfloral.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "songyang.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "spectrum-markets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "srfloki.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "srkb.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "summusglobal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -74507,7 +74426,6 @@
     { "name": "autorijschoolstorm.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "baneh-academic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "banglarfont.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "bankruptcy.ky", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "basebalance.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bauingenieur24.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "become-lucky.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -75240,7 +75158,6 @@
     { "name": "go.exchange", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "goldenhost.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "goldships.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "grasscity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "gridtennis.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "h-server.myfirewall.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "heightselectrical.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -75487,7 +75404,6 @@
     { "name": "brugerklub.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bryanphilton.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bsstainless.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "callmewhatever.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cameramark.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "canhas.report", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cardozovargas.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -76234,7 +76150,6 @@
     { "name": "v88158.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vivoregularizafacil.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vulpr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w36594.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wakastream.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "watchlol.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wca.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -77152,7 +77067,6 @@
     { "name": "fhyl888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fidoo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fitequilibrio.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "flatfix.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "foreignxchange.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "freddieleeman.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "freevst.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -77944,7 +77858,6 @@
     { "name": "allindiacityguide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "alpha-premium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "altabib.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ambra.net.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "analisi-logica.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "anney-life.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "aponkral.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -78091,7 +78004,6 @@
     { "name": "drpil.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "duelingaces.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "durmatest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "earlyimage.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "earthsolidarity.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "easy-vn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ecobagsmauritius.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -78667,7 +78579,6 @@
     { "name": "droppia.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "drrr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dtivandortbv.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "dwz-solutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "e-businessexpert.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "eastmaintech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "eastping.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -78691,7 +78602,6 @@
     { "name": "expertisematrix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "f1distribution.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fairgaming.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "feuerhaken.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fidias.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "firecareandsecurity.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "firstdorsal.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -82180,7 +82090,6 @@
     { "name": "onebestdeal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "oosm.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "open.film", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "openreel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "p81365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "p82365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "panamarealestatebrokers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -82729,7 +82638,6 @@
     { "name": "nordsec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nordvpn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "notifications.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nou.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "octane.net.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "oeilpouroeilcreations.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "omnibnk.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -82893,7 +82801,6 @@
     { "name": "zeit.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zeit.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zety.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zety.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zjy7722.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zum-ziegenhainer.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "0064427.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -86015,7 +85922,6 @@
     { "name": "custosd.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cutienautica.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cyber.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "cyberlab.team", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cybersecurity.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cyprus-company-for.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "d-vision-create.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -87687,7 +87593,6 @@
     { "name": "primbit.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "prinesec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "procsec.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "prodevops.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "prodottitipicidellatoscana.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "progtime.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pryan.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -89951,7 +89856,6 @@
     { "name": "6yue.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "80078.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "9u.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "accessmania.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "adaio.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "adaio.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "adaio.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -89976,9 +89880,6 @@
     { "name": "beakbirds.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "beleadsteam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "benthanhtourist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "bet391.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "bet392.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "bet397.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "betaoptimize.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "beverleycounselling.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "blackarch.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -90071,8 +89972,6 @@
     { "name": "hallighof.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hannde.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "harvilldesigns.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "healthy1lifestyle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "heaven-boutique.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hebamme-sabine.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hehome.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hemant.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -90715,7 +90614,6 @@
     { "name": "archives.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "arclookup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "arroyoins.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "assured.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "atomictag.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "austinmobilestorage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "australianhimalayanfoundation.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -91213,7 +91111,6 @@
     { "name": "goturkmenistan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "gpselect.com.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "grceurope.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "greavessports.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "greenderma.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "greenearthlawns.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "grenoblepartners.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -91490,7 +91387,6 @@
     { "name": "secs.london", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "selectiveasia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sembrando-amor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "sergeenko.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sherijames.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shoplogcap.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "signature.in.th", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -102164,7 +102060,6 @@
     { "name": "hack.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hackade.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hafer.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "haigekassa.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "happybaby-ec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "happywheels1.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hdmovies.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -102548,7 +102443,6 @@
     { "name": "ahornblatt.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ahu.zone", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "akssma.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "alevel.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "alexanderjshapiro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "allergento.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "allpornvids.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -102818,7 +102712,6 @@
     { "name": "max-cafe.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "maxdargent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mccuskey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "mcmk.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "media-valko.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "meijo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mema.recipes", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -102872,7 +102765,6 @@
     { "name": "perustorelowcost.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "petercawthron.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "phcloud.spdns.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "phxserver.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pichainlabs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "piercingnagykereskedes.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "piercingpiac.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -103209,7 +103101,6 @@
     { "name": "fotohiking.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fotrino.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fowos.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "fr-phonix.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "freddyvasquez.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "free-ppp.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "freelancerim.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -104462,7 +104353,6 @@
     { "name": "nolische.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "novokurovka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nuriaamat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nussschale.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nutrygente.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "o30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "objectifs-fitness.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -107256,7 +107146,6 @@
     { "name": "altinopoliscervejaria.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "alvastonauto.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "americanpop.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "amoraparavoce.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ancroma.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "apartema.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "apartema.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -108200,7 +108089,6 @@
     { "name": "stellar.com.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "stellarlumensnews.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "stockmarkettoday.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "storkfront.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "stormdamages.claims", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "strategicmind.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "stumblefallcrawl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -109944,7 +109832,6 @@
     { "name": "tomikoyco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "toneelverenigingnutengenoegen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "topupandearn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "totnhatvina.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tpnky.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tripguide.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tusupermercado.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -110281,7 +110168,6 @@
     { "name": "medfinancial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "medimush.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "meditation-kompass.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "melbar.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mepc.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "merchantcardadvisors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "merryvic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -110638,7 +110524,6 @@
     { "name": "desergo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "diebasis-partei.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "diemperu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "digital-workshop.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "digitalservices.lk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dimequebuscas.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "doctruyencotich.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -111106,7 +110991,6 @@
     { "name": "courttranscriptontario.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cruceroadicto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "custompac.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "cyhour.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "czeh.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "d-ku.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dailydealika.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -111462,7 +111346,6 @@
     { "name": "askhow.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "aspirestore.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "astrologywizard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "atik.kr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "azmabepors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "azon.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bachlongbeach.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -111912,7 +111795,6 @@
     { "name": "woodward-vets.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wvhin.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xemcanho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xiahdeh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xn--54-6kc3btfht.xn--p1ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xyquadrat.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yduc.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -112408,7 +112290,6 @@
     { "name": "hardinal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hargaindo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "healthequity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "healthykitchen101.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "heartofamum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hellven.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "heraldmakassar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -112799,7 +112680,6 @@
     { "name": "ro89.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "robersonaudio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "roofingpioneers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "rsvpdesign.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rumus.co.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rurup.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sadko-group.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -113626,7 +113506,6 @@
     { "name": "gpl5.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "greycrane.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "gs-pflege.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "gsmnext.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "gsmpreview.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "gyoriedes.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "h2ox.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -113722,7 +113601,6 @@
     { "name": "natextruck.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "newchoicesspb.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nextgen-wealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nextrader.guru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nidosi.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nijimama-life.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nixops.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -113806,7 +113684,6 @@
     { "name": "sdruzeniprovltavu.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "secopsolution.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "seonurse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "seoruse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "serve.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "setmore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "seu-emprego.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -114455,7 +114332,6 @@
     { "name": "desentupimentoportoalegre.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "detoxtorehab.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dev-advancedservicesportal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "developpeur-web.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "digipaste.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "digiriik.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dinevigroup.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -114572,7 +114448,6 @@
     { "name": "lifebun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "liquidplus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "loavies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "localserver.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "loli.edu.kg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "londynelliot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "love4taylor.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -115156,7 +115031,6 @@
     { "name": "tinturanaturale.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tipwho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tlcbynature.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tolmandrywall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tothetopmentoring.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "trarch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "travelbags.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -115592,7 +115466,6 @@
     { "name": "restic.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "richandsteph.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "richandsteph.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ripplemarkeg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rollinspass.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "roostminneapolis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rsc.wiki", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -115720,7 +115593,6 @@
     { "name": "01337.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "0xacab.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "1234.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "129.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "136book.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "14er.games", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "14er.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -117417,7 +117289,6 @@
     { "name": "inwonderofit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ip-addr.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "iqreview.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ironscales.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "isleyfarmsupply.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "israel-escorts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "israelimtovim.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -118342,7 +118213,6 @@
     { "name": "r4g3baby.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "racheltinniswood.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ragrosstudios.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "rakipro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ramen-dealer.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ranikaart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rbzl.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -118482,7 +118352,6 @@
     { "name": "tebuscotrabajo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "techstackjournal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "teddie.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tendergrupp.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tennisapp.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "terra7.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "textecnologia.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -118985,7 +118854,6 @@
     { "name": "getjobtoday.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ghentlichtfestival.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ghwconline.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "giacomorosaldi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "giftex.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "giftnix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "gistportal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -121531,7 +121399,6 @@
     { "name": "geolex.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "georgeclooney.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "geowest.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "geowithmaps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "gesentorno.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "getdishnow.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "getfreeelectricity.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -121785,7 +121652,6 @@
     { "name": "hungryas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hupsa-kindermode.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "huron.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "hutson-foods.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hxr404.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hydrochlorothiazide.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hydrogenplatform.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -124113,7 +123979,6 @@
     { "name": "yukimiu.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zac.cy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zaci.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zack.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zagadki-cosmosa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zakaria.website", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zakazat-dizayn-interyera.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -124454,7 +124319,6 @@
     { "name": "costeltrans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "coun.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "creditandfinancialmanagement.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "crimsoncoward.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "crockettmyers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cruelalice.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cryptic-game.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -124555,9 +124419,6 @@
     { "name": "dulse.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dutchbeautyacademy.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dwp-solutions.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "dwz-solutions.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "dwz-solutions.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "dwz-solutions.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dynalab.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dynamicsdjs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "e-dv.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -128173,7 +128034,6 @@
     { "name": "tawjihi21.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tbcloud.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tcncompany.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tecnyal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tejaswi.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "temporaryair.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "thaitonic.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -129629,7 +129489,6 @@
     { "name": "chriswiggin.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "chriswiggin.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "chromestatus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "chromium.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "chryslerbuilding.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "chunabhatti.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "chunkeat.cyou", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -129951,7 +129810,6 @@
     { "name": "first-legion.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fitandslimmerbody.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fitanu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "fitawakening.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fitodifesa.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "flaeskeklubben.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "flagmanfishing.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -132373,7 +132231,6 @@
     { "name": "hirorock.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "historymuseumsb.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hit-electronics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "hitech-zone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hkskhf.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hoahop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hoikin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -132390,7 +132247,6 @@
     { "name": "housing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "howtomakefriends.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hrmcms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "huabianwa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hupeng.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hwasung.com.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hyra.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -132411,7 +132267,6 @@
     { "name": "incometricks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "indo-wiki.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "indst.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "inetpub.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "informationinhindi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "instantuprise.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "instituto18denoviembre.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -132517,7 +132372,6 @@
     { "name": "letsrave.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lettragetattoo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lidarwindtechnolog.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "lighttp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lilicloth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lioe.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lionsk.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -132788,7 +132642,6 @@
     { "name": "samoylov.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "santiagomartinez.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sarahneumann.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "saturuang.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "savesilvercreek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "scorpia.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "scroll.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -133821,7 +133674,6 @@
     { "name": "lia.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lialeone.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "libbysbooks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "liehuojun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "limestart.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "linamila.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lindner-edv.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -134048,7 +133900,6 @@
     { "name": "shoppingvariety.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shoppingwinner.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shoppingworth.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "shota.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shuhra.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sidneyhaberland.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "simsfinnchiropractic.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -136770,7 +136621,6 @@
     { "name": "flirty.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "flop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fluep.ke", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "football.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "foraz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "forixecommerce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "formation-colmar.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -137865,7 +137715,6 @@
     { "name": "nvestproperties.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nvtz.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "occrp.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ocebot.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "offerte-gas.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "offerte-luce.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "olennolla.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -138111,7 +137960,6 @@
     { "name": "beknoumovies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "belinks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "benefitz.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "berlinerwerke.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "besnard.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bestkbeauty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "besttechnews.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -138650,7 +138498,6 @@
     { "name": "radiobunker.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ragingrune.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rahmans.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "rainbowmode.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rajafashion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ramle.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "raspberryvalley.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -138798,7 +138645,6 @@
     { "name": "theintentionalgolfer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "thelodgeonlakedetroit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "themodel.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "thinkwisesoftware.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tifia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tinyproxy.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tokarconsulting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -139168,7 +139014,6 @@
     { "name": "digitaleducationarea.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dirtypretties.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "discoverchinanow.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "dishcrawl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "diskusi.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "distancelove.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dkweb.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -145149,7 +144994,6 @@
     { "name": "casinocity.web.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "castelsardo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "catbop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "cbncuritiba.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ccgaminggifts.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cdawoerden.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cefolklore.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -145884,7 +145728,6 @@
     { "name": "xixi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xiyu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xn--n8jyc5f.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "yareiy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yaslihastabakici.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yogibear.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "youngsophie.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -148318,7 +148161,6 @@
     { "name": "zprogramming.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ztmovies.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zydecozityradio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "0r3.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "1a-media.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "1dot1dot1dot1.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "3h-co.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -149020,7 +148862,6 @@
     { "name": "zvukipro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "20four7va.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "305westendassistedliving.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "4kitchenknives.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "4pals.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "55jam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "abbystrange.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -149519,7 +149360,6 @@
     { "name": "traveladventure.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "travelersuniverse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "travelways.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "trk1234.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ttbonline.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ttdrive.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "turkology.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -149811,7 +149651,6 @@
     { "name": "drthiagorighetto.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dsgvo-fit.co.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dveretti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "dwgfree.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "easyescortwebsites.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "edinburghopenworkshop.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "egliseclichy92.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -150854,7 +150693,6 @@
     { "name": "webminidisc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "webuyhousesingainesvillefl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wenaiwu.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "wheregoes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wihdaparty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wikitrek.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "win-the-1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -150969,7 +150807,6 @@
     { "name": "bouwbedrijfjstam.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "boxmail.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "brianoost.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "bsigroup.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "buildr.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bundesamtsozialesicherung.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bupa.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -151418,13 +151255,11 @@
     { "name": "tex-izol.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tf2pickup.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tf2pickup.web.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tglbbs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "thebutterflypig.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "thedanielswedding.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "thehijau.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "thelittlecountrykitchen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "thenamingcommission.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "theologique.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "theschoolab.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "theshroomery.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "thestitchynerd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -151471,7 +151306,6 @@
     { "name": "villagiant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vintizen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "violetmc.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "viscura.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vistapoquei.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "voeding-en-fitness.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "voffka.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -152284,7 +152118,6 @@
     { "name": "herne-kupony.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hetcoronalab.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hmailserver.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "hocz.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hondasancarlos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hospiceandcommunitycare.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hospiceoflancaster.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -152319,7 +152152,6 @@
     { "name": "itsrana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ivmstatus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jacketscenter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "jae.su", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jalingo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jamesgarrigan.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jamesgarrigan.nyc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -152457,7 +152289,6 @@
     { "name": "myorder-pg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mysexydate.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mysilkandhoney.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nadilo.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nagelfam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nalle.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "namecoin.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -152465,7 +152296,6 @@
     { "name": "nbapwned.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "networkgazette.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "newdigitalmarketing.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "newman.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "newonlineroad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nicholaslazzerini.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nlcpakistan.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -152926,7 +152756,6 @@
     { "name": "castagnino.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "catandmoonalchemy.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ccaag.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ccamtech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ccsrv.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cedarrockalliance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cellrg.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -155188,7 +155017,6 @@
     { "name": "mysilvershield.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "n3oneglass-uat.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "naacam.org.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nafconnexus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nairus.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "naturamaxx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ne.jo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -156080,6 +155908,613 @@
     { "name": "zaraheating.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zgh.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zstrebarov.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "0.sb", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "123comparer.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "123comparer.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "19216811-sifre.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "301.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "30deagosto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3dblender.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "4blm.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "5amat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "5tart.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "5top.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "99sitedesign.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aartbouman.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abaa.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abashevo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aberson.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abritek.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "acalvio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "acompanhantes.com.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "actionablefuturist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adaptivesound.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adminwp.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aesmoris.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "afripay.africa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aiosetups.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aiqidm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "akaconvention.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "akoben.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alatest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alekos2go.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alluance.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "amal.co.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ambersafety.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "amotarget.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ancade.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "annoyinggui.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "antlerprojects.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "anton-nb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "apbio.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "apis.com.py", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "appingrove.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arbil.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arrestage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arrestageinternational.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "asturk.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "attahiyatstore.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "avinpharma.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "azallon.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "babyfit-organic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "babytandarts.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "baccarat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bank-hub.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bankina.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "banksulselbar.co.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bardtech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "barzus.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "basilicproduction.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "baz.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bazaleev.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bckl.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "beatsaver.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "belgischekeizer.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "berthoudeconomicdevelopment.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "betshow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "beyondgames.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "beyondnodes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "beyondtoshi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "biallywoodtv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bighugbotanicals.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blackspark.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bluessoulfunk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bnrailstories.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "boam.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bofn.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "boostsafety.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "branchrvparktexas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brand-design.studio", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brasdir.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "breachlock.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "breadcat.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brixxonline.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brusnika.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "budidayatani.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "burewalanews.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bwa.wroc.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cacommenceavecmoi.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "caenergyprograms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "callaworker.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "canadapets.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carolinacybercenter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carwashkampen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cbiq.com.iq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cdusapps.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cesac.mil.do", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chamath.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chamath.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chamath.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chamathinfotech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chamudi.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chiara.net.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "childrensdentalranch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chocorp.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chrestos.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chronnick.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chungachyan.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cimat.ma", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "classentials.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cleanforce.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clevelandohioinvesting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clevercoaching.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clicy.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clinicadentalhome.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cloudsecuritycommunity.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubeamizade.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubeamizade.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubegls.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubegls.com.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubetravel.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubetravel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubetravel.com.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubetravel.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubetravel.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubgls.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "colombian.cam", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "comswp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "construccionesyequiposayala.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "contenized.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cors.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coursdejaponais.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "crawler.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "creer-mon-business-plan.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cremalleradenuria.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "crestrockadvisors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "crimeamet.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "csreturn.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cubensi.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cvage.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cyberjake.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cyberknife-sigulda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cyberpanelsetup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cybersec.help", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cyclecoach.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "d1iwhdc6scsqsn.cloudfront.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dabes.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "davelucia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "davidgroup.finance", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "daybreaklearning.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dco.sg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "debesteehbodoos.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dehaancaravans.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "delofderonvolmaaktheid.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "denvertechcenter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "develoself.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "devindavid.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "diesignloods.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "digitalproduct.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "discoverlutruwita.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dixa.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "diyadinnet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dnabler.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "doccafe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "docsunited.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dodiedods.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dogadayiz.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dostkuijper.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dowina.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dreamcatchers-events.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dreamwayled.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "duesendruck.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dymond.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dziseldra.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eagleplanners.agency", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eastmedo.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eckerle-gruppe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eeiletudiant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "egdsk.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "egreensvape.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eheartspecialist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ekspres.az", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elektrilevi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elexon.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elkarizan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elkeniels.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elvorti.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elvorti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "encotentin.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "enefit.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "enefitgreen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "enefitgreen.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "enefitgreen.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "enefitgreen.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "enefitgreen.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "engineertaplin.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "englishcompany-mobile.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "englishcompany.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ensightpharma.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "epasuno.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "erik1erik1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "esadnext.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "esilva.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eurekatech.eti.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eyetelligence.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "facebookenterprise.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "facedeplook.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "farmqa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fenns.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fermateh.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fionafuchs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fitint.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "flexurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "florianysantiago.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fmportal.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fondazionescuolapatrimonio.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "franzoni.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fratellisbt.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fuessenaktuell.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fullerotikfilm.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "futureville.city", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gamescum.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gastronomias.com.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gbcdigitalmarketing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "genclikotobusu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "germanrojas.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gftwy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ghostarrow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gli.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gobeyondtheimpossible.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gorgeconnect.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "grambaba.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "graphicz.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "growfedbiz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "haber.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "habtum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hajajaam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hak.edu.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "halgap.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "handsonscience.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hdfilmtime.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hdfreeizle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hdfreex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hdmixfilim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hdsinemax.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hdxxxpics.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hexavalent.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hiddenharbormarina.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hirelisting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hiringopps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hlnet.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hoast.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "homeer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "honeywellbuildings.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hotfulltv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hotmovix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "houdah.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hpk.edu.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hrprofessionals.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hyperdsg.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "idream-solutions.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ijubt.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iksankomputer.web.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "imakeyougreatagain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "imarketing.courses", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "imlhx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "income-earnings.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inferiousbypasser.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "info4camper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inkpay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "interdez.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ioanavisan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iqos-partner.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "isabelvalfer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "isifarshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "island.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jaanikese.edu.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jameshawk.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "javiergddw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jgregory.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jixing.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "johndonmoyer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jurgenfranse.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "justlovecoffeefranchise.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k7cl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kaffeetechnik-goetz.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kagamimods.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kardla.edu.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kashmirtreks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kd23.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "keigakusha.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "keritial.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kewbee.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "khonggin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kienhuon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kino-dom.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kirsehir.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kluberphoto.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kneblesauto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "knownfaqs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kordamentha.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kristinagatto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kudoway.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lachivaloca.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lacteosandinos.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ladyboss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lakecountyohiocondos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "laqira.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "latelatetoyshow.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lauren.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "leadonvale-stemcell.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "learso.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lecannabis.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "leefbaarkrimpen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "legitedelaguiole.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lenta.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lepuyenvelay-tourisme.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lesbicas.com.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "liivimeretuulepark.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "limitlex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lindeal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "liveworkplaycleveland.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "loading.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lonestarpediatricdental.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lovebooks.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lovell.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "loyaltech.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "luizluz.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lumizor.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lytkins.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "m-a-s.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mahtabichat.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mahtra.edu.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "makemoneymojo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mansoorkhan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maroochydorecentre.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maroochydorecitycenter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maroochydorecitycenter.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "matc.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "matteosaturn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mbombela.gov.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mclear.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mcycbd.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mdaesthetique.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "meetyou.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "melusine.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mesas-auxiliares.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mesbonnesrecettes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "meshdigital.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "miedepain.asso.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "minpolit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mirprav.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mitratani.my.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mitrausahatani.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mixizle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mixmovi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "miyajima-ken.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mnsvu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moba-automation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moba-automation.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mobile-industrial-robots.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mobiledatabank.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moneyfuxx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "morghochak.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "motorhome.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "msquared.id.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mtnc.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "munduberriak.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "muzetxe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mybuddytheplumberparkcity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myjobsex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mysmart.team", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myvagnews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nanax.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nanoavionics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "naprawa-bazy-danych.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "necronomusick.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "netbasequid.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nickfreeman.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nickpavel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nilnasc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "niltran.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nordhealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "notebin.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "notionbackups.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nutriflex.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nvtpower.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "obyna3.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "odzyskiwanie-danych-z-dysku.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "offgrid.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ohmycar.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oktrik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "omerdemirel.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "omniflora.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "one2team.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "onefestivalplaza.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ontariodogs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "orlandopooltech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "owncloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pakforces.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "paradisu.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "parperfeito.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pccds-ln.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pcegy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "peliculasclasicas.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pengewangan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pequenaitalia.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "perfekt-style.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "petersonelectricllc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "petruv-grunt.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pfsx.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pgwellnesscoach.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "phantomlighting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "philipzhan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "phobos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pietraglobal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pinarecordsmusic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pinoyreal.team", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pitrick.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "postacarreta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pousadamaremata.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "powerhourllc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "productupdates.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "profarea.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "promethiumex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "protonorbit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "psezalla.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "qgushi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "qpai.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "quantiphi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "quicko.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "quicktricks.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "radiomix.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rahenytennis.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "raidkeeper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rapid20.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rdforum.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "realestateresource.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rebus.support", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "recehandollar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "regent.pp.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "remkond.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "remontkompyutera.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rentptr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rescuemybusiness.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "respawn-group.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rfodistribution.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rightship.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rioloagolf.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rnmkrs.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rocket.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "romanovka.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rosenberggard.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rotasgastronomicas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rotasgastronomicas.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ruffkatt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rutas-turisticas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rxcom.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "s3w.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sachsenflug.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "safagiza.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "safesmartvent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "saladin.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sale-sokuho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "salesforcecass.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sanduskyohioliving.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "savinglivesatbirth.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sbtv.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sby-tampere.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "schuhfits.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sebastianelectric.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "semalt.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "seoefectivo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "seoeye.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "service-soft.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sethgrayson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sharepointcass.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shipeurousa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shitfest.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shkolamishlenia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shopelvorti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shorted.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shortedone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sie.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "simabonnement.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "site-master.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sitramos.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sky-motion.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "skypce.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "soax.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "speciosapro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "spiceislandhome.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "starinsights.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "starprime.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stockmaquinas.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stonegray.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "strullmeier.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "strypsteen.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "studenfy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "studyhacker.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stunningwroclaw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "suff.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "superfilmgeldi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "superfullhdfilmizle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "superpowerexperts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "surmoms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "swingers.com.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "syncmedia.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "talichi.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "taxjusticeafrica.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "techmatters.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "technicalhub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "techvision.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tek-el.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "telemitra.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "telugupublications.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "test-coz.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "testnet-faucet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tgrade.finance", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thebuffalospotfranchise.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theconsultant.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thefoodieblogger.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thephmp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thestopoff.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thinksmartersolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thomasgriffin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "threatint.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "threesixteen.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "timeking.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "timetreeapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tin-check.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "toby3d.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "totalmerchandise.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tourisme-castillonpujols.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tourisme-fronsadais.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "toyotaconnected.co.th", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "toyshowappeal.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "travelclube.com.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trial-144510.url.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tribesofneurot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trikeweb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tsvit.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tule.studio", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tulpawiki.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tumed-ks.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "turadio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "turismozumagperu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tuvanmat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tworzeniesklepu.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ubersmith.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "udrivingschool.com.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "unausa.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "unison-d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "upfreshfranchise.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "urgencesolidarite.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "urlauthority.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "urvastekool.edu.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "usmantrader.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "utwf.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uulu.edu.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uzcard.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "valdor2.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vcross.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "verificationlink.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vianetplc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vicsancab.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vinepower.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vinocapka.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vinogradgid.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vipmercedes.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vmett.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "voice-pic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "voxel.cat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vreklame.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vyyer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "w33b.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "waligorska.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "warpjump.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "watisleukemie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webkato.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "weitzel-it.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "weitzel-it.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "westappin.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wheelchair-mobility-scooter-rental-london.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wildanfauzy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "withpersona.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "woodysinstalaciones.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "workindia.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wp-op.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wwwbox.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "x0rg.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xaviermalisse.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbookcn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbookcn.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xemod.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "y99.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yanagibashi.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yapmaz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yaravidasana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yedm.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yesichat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yoitsu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yuvaskillfoundation.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zalaetavoleibol.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zeilinstructeurs.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zeitzuleben.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zocoxx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zvrottal.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zwemschooldezwaantjes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zywave.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     // END OF 1-YEAR BULK HSTS ENTRIES
 
     // Only eTLD+1 domains can be submitted automatically to hstspreload.org,
@@ -157597,6 +158032,99 @@
     { "name": "willcounty911.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
     { "name": "wincoil.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
     { "name": "winnebagocountywi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "abbevillecountysc.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "akiakira-nsn.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "ardmoreok.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "bayvotesfl.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "bloomingtonil.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "bondcountyil.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "butlercountyne.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "ccb.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "centrecountyvotes.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "champaigncountyil.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "chatsworthil.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "chenangocountyny.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "chocolay.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "cityofmte.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "cityofroncevertewv.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "colquittga.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "commercega.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "copyrightclaimsboard.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "cua911.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "dadecityfl.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "darlingtonwi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "domainops.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "duxbury-ma.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "elizabethcitync.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "elkmontal.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "floridaethics.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "fortdeposital.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "foxpointwi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "gcwcid1tx.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "halseyor.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "hardenburghny.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "hastingsne.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "hewlettbayparkny.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "hobokenpdnj.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "iowadol.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "jacksoncountywi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "jacksontwpclermontoh.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "jamaicabeachtx.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "ksdot.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "lakelafayettemo.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "latahcountyid.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "lcfwasa.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "leyeslaboralesdecolorado.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "lyndhurstohio.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "madcosao.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "mcdowellcountywv.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "meccrcog-oh.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "monmouthcountynj.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "montgomerynj.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "morgancountymo.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "mtdnrc.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "nancecountyne.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "ncswboard.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "omro-wi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "oswegoil.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "pahrumpnv.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "peoriacounty.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "peoriaelections.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "polkcountywi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "prairievilletwp-mi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "redwillowcountyne.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "rochesterwi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "rockislandcountyil.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "salinecountyne.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "santacruzca.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "sheridancountyks.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "slopecountynd.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "stmaryscountymd.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "thprd.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "titusvillepapd.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "townofadamswi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "townofcranmoor.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "townofeaugallewi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "townofgermantownwi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "townofhollandwi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "townoflebanonwi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "townofmiltonwi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "townofnorwichny.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "townofrichmondwi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "townofwescott-wi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "villageofcazenoviany.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "villageofclaytonmi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "villageoffremontwi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "voteosceola.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "votesantarosa.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "washingtoncountyid.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "washingtoncountyne.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "washingtoncountysheriffne.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "waterfordvt.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "wgfl.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "willardwi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "winterset.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "wwtg.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
     // END OF ETLD-OWNER REQUESTED ENTRIES
 
     // To avoid trailing comma changes from showing up in diffs, we place a
diff --git a/net/url_request/redirect_info.cc b/net/url_request/redirect_info.cc
index ccaff4e..940027e5 100644
--- a/net/url_request/redirect_info.cc
+++ b/net/url_request/redirect_info.cc
@@ -138,8 +138,7 @@
     GURL::Replacements replacements;
     // Reference the |ref| directly out of the original URL to avoid a
     // malloc.
-    replacements.SetRef(original_url.spec().data(),
-                        original_url.parsed_for_possibly_invalid_spec().ref);
+    replacements.SetRefStr(original_url.ref_piece());
     redirect_info.new_url = new_location.ReplaceComponents(replacements);
   } else {
     redirect_info.new_url = new_location;
diff --git a/remoting/host/installer/linux/BUILD.gn b/remoting/host/installer/linux/BUILD.gn
index 60829f4..5c5144d 100644
--- a/remoting/host/installer/linux/BUILD.gn
+++ b/remoting/host/installer/linux/BUILD.gn
@@ -77,6 +77,7 @@
     "//remoting/host/linux:remoting_user_session",
     "//remoting/host/linux:url_forwarder_desktop_entry",
     "//remoting/host/remote_open_url",
+    "//remoting/host/webauthn:remote_webauthn",
     "//remoting/resources",
     "//third_party/icu:icudata",
   ]
diff --git a/remoting/host/installer/linux/Makefile b/remoting/host/installer/linux/Makefile
index 55993212..d079a9b 100644
--- a/remoting/host/installer/linux/Makefile
+++ b/remoting/host/installer/linux/Makefile
@@ -30,6 +30,8 @@
 REMOTE_ASSISTANCE_DEBUGFILE = $(REMOTE_ASSISTANCE_PROGNAME).debug
 REMOTE_OPEN_URL_PROGNAME = $(BUILD_DIR)/remote_open_url
 REMOTE_OPEN_URL_DEBUGFILE = $(REMOTE_OPEN_URL_PROGNAME).debug
+REMOTE_WEBAUTHN_PROGNAME = $(BUILD_DIR)/remote_webauthn
+REMOTE_WEBAUTHN_DEBUGFILE = $(REMOTE_WEBAUTHN_PROGNAME).debug
 
 all:
 
@@ -92,6 +94,9 @@
 	eu-strip -f "$(REMOTE_OPEN_URL_DEBUGFILE)" \
 	  "$(INSTALL_DIR)/remote-open-url"
 
+	install "$(REMOTE_WEBAUTHN_PROGNAME)" "$(INSTALL_DIR)/remote-webauthn"
+	eu-strip -f "$(REMOTE_WEBAUTHN_DEBUGFILE)" "$(INSTALL_DIR)/remote-webauthn"
+
 	install -m 0644 \
 	  "$(BUILD_DIR)/remoting/crd-url-forwarder.desktop" \
 	  "$(SYSTEM_WIDE_DESKTOP_ENTRIES_DIR)/crd-url-forwarder.desktop"
diff --git a/remoting/host/linux/BUILD.gn b/remoting/host/linux/BUILD.gn
index 4045a0a..589caff 100644
--- a/remoting/host/linux/BUILD.gn
+++ b/remoting/host/linux/BUILD.gn
@@ -74,6 +74,7 @@
       ":url_forwarder_desktop_entry",
       "//remoting/host:remoting_me2me_host",
       "//remoting/host/remote_open_url",
+      "//remoting/host/webauthn:remote_webauthn",
     ]
   }
 }
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index 9fc3452..6535a463 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -1668,9 +1668,11 @@
   // The feature is enabled for all Googlers using a supported platform.
   desktop_environment_options_.set_enable_remote_open_url(is_googler_);
 
-#if !defined(NDEBUG)
-  // Experimental feature.
-  desktop_environment_options_.set_enable_remote_webauthn(true);
+#if defined(OS_LINUX) || !defined(NDEBUG)
+  // Experimental feature. Enabled on Linux for easier testing.
+  if (is_googler_) {
+    desktop_environment_options_.set_enable_remote_webauthn(true);
+  }
 #endif
 
   if (max_clipboard_size_.has_value()) {
diff --git a/sandbox/policy/fuchsia/sandbox_policy_fuchsia.cc b/sandbox/policy/fuchsia/sandbox_policy_fuchsia.cc
index afc289c..b511e3cd 100644
--- a/sandbox/policy/fuchsia/sandbox_policy_fuchsia.cc
+++ b/sandbox/policy/fuchsia/sandbox_policy_fuchsia.cc
@@ -263,8 +263,8 @@
   ZX_CHECK(status == ZX_OK, status) << "zx_job_create";
   options->job_handle = job_.get();
 
-  // Only allow ambient VMO mark-as-executable capability to be granted
-  // to processes that which need to JIT (i.e. do not run V8/WASM).
+  // Only allow the ambient VMO mark-as-executable capability to be granted
+  // to processes that need to JIT (i.e. run V8/WASM).
   zx_policy_basic_v2_t ambient_mark_vmo_exec{
       ZX_POL_AMBIENT_MARK_VMO_EXEC,
 
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn
index f92707c..e69d74c4 100644
--- a/sandbox/win/BUILD.gn
+++ b/sandbox/win/BUILD.gn
@@ -125,12 +125,6 @@
     "src/socket_dispatcher.h",
     "src/startup_information_helper.cc",
     "src/startup_information_helper.h",
-    "src/sync_dispatcher.cc",
-    "src/sync_dispatcher.h",
-    "src/sync_interception.cc",
-    "src/sync_interception.h",
-    "src/sync_policy.cc",
-    "src/sync_policy.h",
     "src/target_interceptions.cc",
     "src/target_interceptions.h",
     "src/target_process.cc",
@@ -211,8 +205,6 @@
     "src/process_policy_test.cc",
     "src/registry_policy_test.cc",
     "src/restricted_token_test.cc",
-    "src/sync_policy_test.cc",
-    "src/sync_policy_test.h",
     "src/unload_dll_test.cc",
     "tests/common/controller.cc",
     "tests/common/test_utils.cc",
diff --git a/sandbox/win/src/app_container_base.cc b/sandbox/win/src/app_container_base.cc
index 8f81044f..f20947b 100644
--- a/sandbox/win/src/app_container_base.cc
+++ b/sandbox/win/src/app_container_base.cc
@@ -15,6 +15,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/win/scoped_co_mem.h"
 #include "base/win/scoped_handle.h"
+#include "base/win/scoped_localalloc.h"
 #include "sandbox/win/src/acl.h"
 #include "sandbox/win/src/app_container_base.h"
 #include "sandbox/win/src/restricted_token_utils.h"
@@ -232,17 +233,17 @@
 
   GENERIC_MAPPING generic_mapping = GetGenericMappingForType(object_type);
   ::MapGenericMask(&desired_access, &generic_mapping);
-  PSECURITY_DESCRIPTOR sd = nullptr;
+  PSECURITY_DESCRIPTOR sd_ptr = nullptr;
   PACL dacl = nullptr;
   if (::GetNamedSecurityInfo(
           object_name, native_object_type,
           OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
               DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
-          nullptr, nullptr, &dacl, nullptr, &sd) != ERROR_SUCCESS) {
+          nullptr, nullptr, &dacl, nullptr, &sd_ptr) != ERROR_SUCCESS) {
     return false;
   }
 
-  std::unique_ptr<void, LocalFreeDeleter> sd_ptr(sd);
+  base::win::ScopedLocalAlloc sd = base::win::TakeLocalAlloc(sd_ptr);
 
   if (enable_low_privilege_app_container_) {
     base::win::Sid any_package_sid = *base::win::Sid::FromKnownSid(
@@ -276,9 +277,9 @@
   if (BuildLowBoxToken(&token) != SBOX_ALL_OK)
     return false;
 
-  return !!::AccessCheck(sd, token.Get(), desired_access, &generic_mapping,
-                         &priv_set, &priv_set_length, granted_access,
-                         access_status);
+  return !!::AccessCheck(sd.get(), token.Get(), desired_access,
+                         &generic_mapping, &priv_set, &priv_set_length,
+                         granted_access, access_status);
 }
 
 bool AppContainerBase::AddCapability(const wchar_t* capability_name) {
@@ -356,8 +357,8 @@
     base::win::ScopedHandle* lockdown) {
   if (type_ == AppContainerType::kLowbox) {
     if (!lowbox_directory_.IsValid()) {
-      DWORD result = CreateLowBoxObjectDirectory(package_sid_.GetPSID(), true,
-                                                 &lowbox_directory_);
+      DWORD result =
+          CreateLowBoxObjectDirectory(package_sid_, true, &lowbox_directory_);
       DCHECK(result == ERROR_SUCCESS);
     }
 
diff --git a/sandbox/win/src/app_container_test.cc b/sandbox/win/src/app_container_test.cc
index 6eef634..cff8269b 100644
--- a/sandbox/win/src/app_container_test.cc
+++ b/sandbox/win/src/app_container_test.cc
@@ -28,12 +28,12 @@
 #include "base/test/task_environment.h"
 #include "base/test/test_timeouts.h"
 #include "base/win/scoped_handle.h"
+#include "base/win/scoped_localalloc.h"
 #include "base/win/scoped_process_information.h"
 #include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #include "sandbox/win/src/app_container_base.h"
 #include "sandbox/win/src/sandbox_factory.h"
-#include "sandbox/win/src/sync_policy_test.h"
 #include "sandbox/win/src/win_utils.h"
 #include "sandbox/win/tests/common/controller.h"
 #include "sandbox/win/tests/common/test_utils.h"
@@ -156,13 +156,14 @@
   ASSERT_TRUE(::ConvertStringSecurityDescriptorToSecurityDescriptor(
       L"O:SYG:SYD:(A;;0x3;;;WD)(A;;0x1;;;AC)(A;;0x2;;;S-1-15-2-2)",
       SDDL_REVISION_1, &security_desc_ptr, nullptr));
-  std::unique_ptr<void, LocalFreeDeleter> security_desc(security_desc_ptr);
+  base::win::ScopedLocalAlloc security_desc =
+      base::win::TakeLocalAlloc(security_desc_ptr);
   GENERIC_MAPPING generic_mapping = {};
   PRIVILEGE_SET priv_set = {};
   DWORD priv_set_length = sizeof(PRIVILEGE_SET);
   DWORD granted_access;
   BOOL access_status;
-  ASSERT_TRUE(::AccessCheck(security_desc_ptr, token.Get(), MAXIMUM_ALLOWED,
+  ASSERT_TRUE(::AccessCheck(security_desc.get(), token.Get(), MAXIMUM_ALLOWED,
                             &generic_mapping, &priv_set, &priv_set_length,
                             &granted_access, &access_status));
   ASSERT_TRUE(access_status);
@@ -475,6 +476,25 @@
 
 }  // namespace
 
+SBOX_TESTS_COMMAND int AppContainerEvent_Open(int argc, wchar_t** argv) {
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  base::win::ScopedHandle event_open(
+      ::OpenEvent(EVENT_ALL_ACCESS, false, argv[0]));
+  DWORD error_open = ::GetLastError();
+
+  if (event_open.IsValid())
+    return SBOX_TEST_SUCCEEDED;
+
+  if (ERROR_ACCESS_DENIED == error_open || ERROR_BAD_PATHNAME == error_open ||
+      ERROR_FILE_NOT_FOUND == error_open) {
+    return SBOX_TEST_DENIED;
+  }
+
+  return SBOX_TEST_FAILED;
+}
+
 TEST_F(AppContainerTest, DenyOpenEventForLowBox) {
   if (base::win::GetVersion() < base::win::Version::WIN8)
     return;
@@ -484,7 +504,7 @@
   EXPECT_EQ(SBOX_ALL_OK, runner.GetPolicy()->SetLowBox(kAppContainerSid));
   // Run test once, this ensures the app container directory exists, we
   // ignore the result.
-  runner.RunTest(L"Event_Open f test");
+  runner.RunTest(L"AppContainerEvent_Open test");
   std::wstring event_name = L"AppContainerNamedObjects\\";
   event_name += kAppContainerSid;
   event_name += L"\\test";
@@ -493,7 +513,7 @@
       ::CreateEvent(nullptr, false, false, event_name.c_str()));
   ASSERT_TRUE(event.IsValid());
 
-  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open f test"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"AppContainerEvent_Open test"));
 }
 
 TEST_F(AppContainerTest, CheckIncompatibleOptions) {
@@ -678,7 +698,7 @@
 // correctly.
 SBOX_TESTS_COMMAND int Socket_CreateTCP(int argc, wchar_t** argv) {
   int init_status = InitWinsock();
-  if (init_status != STATUS_SUCCESS)
+  if (init_status != ERROR_SUCCESS)
     return init_status;
   SOCKET socket_handle = INVALID_SOCKET;
 
@@ -773,7 +793,7 @@
 // correctly.
 SBOX_TESTS_COMMAND int Socket_CreateUDP(int argc, wchar_t** argv) {
   int init_status = InitWinsock();
-  if (init_status != STATUS_SUCCESS)
+  if (init_status != ERROR_SUCCESS)
     return init_status;
   SOCKET socket_handle = INVALID_SOCKET;
 
@@ -897,7 +917,7 @@
                            /* add brokering rule */ bool>> {
  public:
   void SetUp() override {
-    ASSERT_EQ(STATUS_SUCCESS, InitWinsock());
+    ASSERT_EQ(ERROR_SUCCESS, InitWinsock());
     SetUpSandboxPolicy();
   }
 
diff --git a/sandbox/win/src/heap_helper.h b/sandbox/win/src/heap_helper.h
index 302a3c4..1aa440b 100644
--- a/sandbox/win/src/heap_helper.h
+++ b/sandbox/win/src/heap_helper.h
@@ -5,9 +5,7 @@
 #ifndef SANDBOX_WIN_SRC_HEAP_HELPER_H_
 #define SANDBOX_WIN_SRC_HEAP_HELPER_H_
 
-#include <windows.h>
-
-#include "base/win/windows_version.h"
+#include "base/win/windows_types.h"
 
 namespace sandbox {
 // These helper functions are not expected to be used generally, but are exposed
diff --git a/sandbox/win/src/interception.cc b/sandbox/win/src/interception.cc
index a7914a4..4a21fd0 100644
--- a/sandbox/win/src/interception.cc
+++ b/sandbox/win/src/interception.cc
@@ -21,6 +21,7 @@
 #include "base/win/windows_version.h"
 #include "sandbox/win/src/interception_internal.h"
 #include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/internal_types.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/sandbox_rand.h"
 #include "sandbox/win/src/service_resolver.h"
diff --git a/sandbox/win/src/interceptors_64.cc b/sandbox/win/src/interceptors_64.cc
index 0081bb3b..950cb2e1 100644
--- a/sandbox/win/src/interceptors_64.cc
+++ b/sandbox/win/src/interceptors_64.cc
@@ -14,7 +14,6 @@
 #include "sandbox/win/src/sandbox_nt_types.h"
 #include "sandbox/win/src/sandbox_types.h"
 #include "sandbox/win/src/signed_interception.h"
-#include "sandbox/win/src/sync_interception.h"
 #include "sandbox/win/src/target_interceptions.h"
 
 namespace sandbox {
@@ -309,30 +308,6 @@
 
 // -----------------------------------------------------------------------
 
-SANDBOX_INTERCEPT NTSTATUS WINAPI
-TargetNtCreateEvent64(PHANDLE event_handle,
-                      ACCESS_MASK desired_access,
-                      POBJECT_ATTRIBUTES object_attributes,
-                      EVENT_TYPE event_type,
-                      BOOLEAN initial_state) {
-  NtCreateEventFunction orig_fn =
-      reinterpret_cast<NtCreateEventFunction>(g_originals[CREATE_EVENT_ID]);
-  return TargetNtCreateEvent(orig_fn, event_handle, desired_access,
-                             object_attributes, event_type, initial_state);
-}
-
-SANDBOX_INTERCEPT NTSTATUS WINAPI
-TargetNtOpenEvent64(PHANDLE event_handle,
-                    ACCESS_MASK desired_access,
-                    POBJECT_ATTRIBUTES object_attributes) {
-  NtOpenEventFunction orig_fn =
-      reinterpret_cast<NtOpenEventFunction>(g_originals[OPEN_EVENT_ID]);
-  return TargetNtOpenEvent(orig_fn, event_handle, desired_access,
-                           object_attributes);
-}
-
-// -----------------------------------------------------------------------
-
 SANDBOX_INTERCEPT BOOL WINAPI TargetGdiDllInitialize64(HANDLE dll,
                                                        DWORD reason) {
   GdiDllInitializeFunction orig_fn =
diff --git a/sandbox/win/src/interceptors_64.h b/sandbox/win/src/interceptors_64.h
index 0b5c6f8..bcfdf8a 100644
--- a/sandbox/win/src/interceptors_64.h
+++ b/sandbox/win/src/interceptors_64.h
@@ -208,22 +208,6 @@
                     ULONG open_options);
 
 // -----------------------------------------------------------------------
-// Interceptors handled by the sync dispatcher.
-
-// Interception of NtCreateEvent/NtOpenEvent on the child process.
-SANDBOX_INTERCEPT NTSTATUS WINAPI
-TargetNtCreateEvent64(PHANDLE event_handle,
-                      ACCESS_MASK desired_access,
-                      POBJECT_ATTRIBUTES object_attributes,
-                      EVENT_TYPE event_type,
-                      BOOLEAN initial_state);
-
-SANDBOX_INTERCEPT NTSTATUS WINAPI
-TargetNtOpenEvent64(PHANDLE event_handle,
-                    ACCESS_MASK desired_access,
-                    POBJECT_ATTRIBUTES object_attributes);
-
-// -----------------------------------------------------------------------
 // Interceptors handled by the process mitigations win32k lockdown code.
 
 // Interceptor for the GdiDllInitialize function.
diff --git a/sandbox/win/src/ipc_tags.h b/sandbox/win/src/ipc_tags.h
index 8603a24..e9ae5a94 100644
--- a/sandbox/win/src/ipc_tags.h
+++ b/sandbox/win/src/ipc_tags.h
@@ -24,8 +24,6 @@
   NTOPENPROCESSTOKEN,
   NTOPENPROCESSTOKENEX,
   CREATEPROCESSW,
-  CREATEEVENT,
-  OPENEVENT,
   NTCREATEKEY,
   NTOPENKEY,
   GDI_GDIDLLINITIALIZE,
diff --git a/sandbox/win/src/job.cc b/sandbox/win/src/job.cc
index 02c5107..7ef429d8 100644
--- a/sandbox/win/src/job.cc
+++ b/sandbox/win/src/job.cc
@@ -4,6 +4,8 @@
 
 #include "sandbox/win/src/job.h"
 
+#include <windows.h>
+
 #include <stddef.h>
 #include <utility>
 
diff --git a/sandbox/win/src/nt_internals.h b/sandbox/win/src/nt_internals.h
index 1bde6a5..46d489f 100644
--- a/sandbox/win/src/nt_internals.h
+++ b/sandbox/win/src/nt_internals.h
@@ -761,12 +761,6 @@
 
 typedef ULONG(WINAPI* RtlNtStatusToDosErrorFunction)(NTSTATUS status);
 
-typedef enum _EVENT_TYPE {
-  NotificationEvent,
-  SynchronizationEvent
-} EVENT_TYPE,
-    *PEVENT_TYPE;
-
 typedef NTSTATUS(WINAPI* NtCreateDirectoryObjectFunction)(
     PHANDLE DirectoryHandle,
     ACCESS_MASK DesiredAccess,
diff --git a/sandbox/win/src/policy_broker.cc b/sandbox/win/src/policy_broker.cc
index 6d02711..1f9fa6b 100644
--- a/sandbox/win/src/policy_broker.cc
+++ b/sandbox/win/src/policy_broker.cc
@@ -13,6 +13,7 @@
 #include "base/win/windows_version.h"
 #include "sandbox/win/src/interception.h"
 #include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/internal_types.h"
 #include "sandbox/win/src/policy_target.h"
 #include "sandbox/win/src/process_thread_interception.h"
 #include "sandbox/win/src/sandbox.h"
diff --git a/sandbox/win/src/registry_dispatcher.cc b/sandbox/win/src/registry_dispatcher.cc
index 26d2bb3..45dd6c4f 100644
--- a/sandbox/win/src/registry_dispatcher.cc
+++ b/sandbox/win/src/registry_dispatcher.cc
@@ -18,6 +18,7 @@
 #include "sandbox/win/src/registry_policy.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/win_utils.h"
 
 namespace {
 
diff --git a/sandbox/win/src/restricted_token.cc b/sandbox/win/src/restricted_token.cc
index 4397fdb5..16c96d41 100644
--- a/sandbox/win/src/restricted_token.cc
+++ b/sandbox/win/src/restricted_token.cc
@@ -4,6 +4,8 @@
 
 #include "sandbox/win/src/restricted_token.h"
 
+#include <windows.h>
+
 #include <stddef.h>
 
 #include <memory>
@@ -26,6 +28,29 @@
   return buffer;
 }
 
+LUID ConvertToLuid(const CHROME_LUID& luid) {
+  LUID ret;
+  memcpy(&ret, &luid, sizeof(luid));
+  return ret;
+}
+
+CHROME_LUID ConvertToChromeLuid(const LUID& luid) {
+  CHROME_LUID ret;
+  memcpy(&ret, &luid, sizeof(luid));
+  return ret;
+}
+
+std::vector<SID_AND_ATTRIBUTES> ConvertToAttributes(
+    const std::vector<base::win::Sid>& sids,
+    DWORD attributes) {
+  std::vector<SID_AND_ATTRIBUTES> ret(sids.size());
+  for (size_t i = 0; i < sids.size(); ++i) {
+    ret[i].Attributes = attributes;
+    ret[i].Sid = sids[i].GetPSID();
+  }
+  return ret;
+}
+
 }  // namespace
 
 namespace sandbox {
@@ -68,48 +93,24 @@
   if (!init_)
     return ERROR_NO_TOKEN;
 
-  size_t deny_size = sids_for_deny_only_.size();
-  size_t restrict_size = sids_to_restrict_.size();
-  size_t privileges_size = privileges_to_disable_.size();
-
-  SID_AND_ATTRIBUTES* deny_only_array = nullptr;
-  if (deny_size) {
-    deny_only_array = new SID_AND_ATTRIBUTES[deny_size];
-
-    for (unsigned int i = 0; i < sids_for_deny_only_.size(); ++i) {
-      deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY;
-      deny_only_array[i].Sid = sids_for_deny_only_[i].GetPSID();
-    }
-  }
-
-  SID_AND_ATTRIBUTES* sids_to_restrict_array = nullptr;
-  if (restrict_size) {
-    sids_to_restrict_array = new SID_AND_ATTRIBUTES[restrict_size];
-
-    for (unsigned int i = 0; i < restrict_size; ++i) {
-      sids_to_restrict_array[i].Attributes = 0;
-      sids_to_restrict_array[i].Sid = sids_to_restrict_[i].GetPSID();
-    }
-  }
-
-  LUID_AND_ATTRIBUTES* privileges_to_disable_array = nullptr;
-  if (privileges_size) {
-    privileges_to_disable_array = new LUID_AND_ATTRIBUTES[privileges_size];
-
-    for (unsigned int i = 0; i < privileges_size; ++i) {
-      privileges_to_disable_array[i].Attributes = 0;
-      privileges_to_disable_array[i].Luid = privileges_to_disable_[i];
-    }
+  std::vector<SID_AND_ATTRIBUTES> deny_sids =
+      ConvertToAttributes(sids_for_deny_only_, SE_GROUP_USE_FOR_DENY_ONLY);
+  std::vector<SID_AND_ATTRIBUTES> restrict_sids =
+      ConvertToAttributes(sids_to_restrict_, 0);
+  std::vector<LUID_AND_ATTRIBUTES> disable_privs(privileges_to_disable_.size());
+  for (size_t i = 0; i < privileges_to_disable_.size(); ++i) {
+    disable_privs[i].Attributes = 0;
+    disable_privs[i].Luid = ConvertToLuid(privileges_to_disable_[i]);
   }
 
   bool result = true;
   HANDLE new_token_handle = nullptr;
-  if (deny_size || restrict_size || privileges_size) {
+  if (!deny_sids.empty() || !restrict_sids.empty() || !disable_privs.empty()) {
     result = ::CreateRestrictedToken(
-        effective_token_.Get(), 0, static_cast<DWORD>(deny_size),
-        deny_only_array, static_cast<DWORD>(privileges_size),
-        privileges_to_disable_array, static_cast<DWORD>(restrict_size),
-        sids_to_restrict_array, &new_token_handle);
+        effective_token_.Get(), 0, static_cast<DWORD>(deny_sids.size()),
+        deny_sids.data(), static_cast<DWORD>(disable_privs.size()),
+        disable_privs.data(), static_cast<DWORD>(restrict_sids.size()),
+        restrict_sids.data(), &new_token_handle);
   } else {
     // Duplicate the token even if it's not modified at this point
     // because any subsequent changes to this token would also affect the
@@ -118,19 +119,9 @@
                                 nullptr, SecurityIdentification, TokenPrimary,
                                 &new_token_handle);
   }
-  auto last_error = ::GetLastError();
-
-  if (deny_only_array)
-    delete[] deny_only_array;
-
-  if (sids_to_restrict_array)
-    delete[] sids_to_restrict_array;
-
-  if (privileges_to_disable_array)
-    delete[] privileges_to_disable_array;
 
   if (!result)
-    return last_error;
+    return ::GetLastError();
 
   base::win::ScopedHandle new_token(new_token_handle);
 
@@ -206,7 +197,7 @@
 }
 
 DWORD RestrictedToken::AddAllSidsForDenyOnly(
-    std::vector<base::win::Sid>* exceptions) {
+    const std::vector<base::win::Sid>& exceptions) {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
@@ -225,12 +216,10 @@
     if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
         (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) {
       bool should_ignore = false;
-      if (exceptions) {
-        for (unsigned int j = 0; j < exceptions->size(); ++j) {
-          if ((*exceptions)[j].Equal(token_groups->Groups[i].Sid)) {
-            should_ignore = true;
-            break;
-          }
+      for (const base::win::Sid& sid : exceptions) {
+        if (sid.Equal(token_groups->Groups[i].Sid)) {
+          should_ignore = true;
+          break;
         }
       }
       if (!should_ignore) {
@@ -274,7 +263,7 @@
 }
 
 DWORD RestrictedToken::DeleteAllPrivileges(
-    const std::vector<std::wstring>* exceptions) {
+    const std::vector<std::wstring>& exceptions) {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
@@ -292,19 +281,18 @@
   // Build the list of privileges to disable
   for (unsigned int i = 0; i < token_privileges->PrivilegeCount; ++i) {
     bool should_ignore = false;
-    if (exceptions) {
-      for (unsigned int j = 0; j < exceptions->size(); ++j) {
-        LUID luid = {0};
-        ::LookupPrivilegeValue(nullptr, (*exceptions)[j].c_str(), &luid);
-        if (token_privileges->Privileges[i].Luid.HighPart == luid.HighPart &&
-            token_privileges->Privileges[i].Luid.LowPart == luid.LowPart) {
-          should_ignore = true;
-          break;
-        }
+    for (const std::wstring& name : exceptions) {
+      LUID luid = {};
+      ::LookupPrivilegeValue(nullptr, name.c_str(), &luid);
+      if (token_privileges->Privileges[i].Luid.HighPart == luid.HighPart &&
+          token_privileges->Privileges[i].Luid.LowPart == luid.LowPart) {
+        should_ignore = true;
+        break;
       }
     }
     if (!should_ignore) {
-      privileges_to_disable_.push_back(token_privileges->Privileges[i].Luid);
+      privileges_to_disable_.push_back(
+          ConvertToChromeLuid(token_privileges->Privileges[i].Luid));
     }
   }
 
@@ -317,8 +305,8 @@
     return ERROR_NO_TOKEN;
 
   LUID luid = {0};
-  if (LookupPrivilegeValue(nullptr, privilege, &luid))
-    privileges_to_disable_.push_back(luid);
+  if (::LookupPrivilegeValue(nullptr, privilege, &luid))
+    privileges_to_disable_.push_back(ConvertToChromeLuid(luid));
   else
     return ::GetLastError();
 
diff --git a/sandbox/win/src/restricted_token.h b/sandbox/win/src/restricted_token.h
index 8b813af..5345161 100644
--- a/sandbox/win/src/restricted_token.h
+++ b/sandbox/win/src/restricted_token.h
@@ -5,8 +5,6 @@
 #ifndef SANDBOX_WIN_SRC_RESTRICTED_TOKEN_H_
 #define SANDBOX_WIN_SRC_RESTRICTED_TOKEN_H_
 
-#include <windows.h>
-
 #include <vector>
 
 #include <string>
@@ -19,14 +17,6 @@
 #include "sandbox/win/src/restricted_token_utils.h"
 #include "sandbox/win/src/security_level.h"
 
-// Flags present in the Group SID list. These 2 flags are new in Windows Vista
-#ifndef SE_GROUP_INTEGRITY
-#define SE_GROUP_INTEGRITY (0x00000020L)
-#endif
-#ifndef SE_GROUP_INTEGRITY_ENABLED
-#define SE_GROUP_INTEGRITY_ENABLED (0x00000040L)
-#endif
-
 namespace sandbox {
 
 // Handles the creation of a restricted token using the effective token or
@@ -89,12 +79,11 @@
   //
   // Sample usage:
   //    std::vector<base::win::Sid> sid_exceptions;
-  //    sid_exceptions.push_back(ATL::Sids::Users().GetPSID());
-  //    sid_exceptions.push_back(ATL::Sids::World().GetPSID());
-  //    restricted_token.AddAllSidsForDenyOnly(&sid_exceptions);
+  //    sid_exceptions.push_back(*base::win::Sid::FromPSID(psid));
+  //    restricted_token.AddAllSidsForDenyOnly(sid_exceptions);
   // Note: A Sid marked for Deny Only in a token cannot be used to grant
   // access to any resource. It can only be used to deny access.
-  DWORD AddAllSidsForDenyOnly(std::vector<base::win::Sid>* exceptions);
+  DWORD AddAllSidsForDenyOnly(const std::vector<base::win::Sid>& exceptions);
 
   // Adds a user or group SID for Deny Only in the restricted token.
   // Parameter: sid is the SID to add in the Deny Only list.
@@ -130,8 +119,8 @@
   // Sample usage:
   //    std::vector<std::wstring> privilege_exceptions;
   //    privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
-  //    restricted_token.DeleteAllPrivileges(&privilege_exceptions);
-  DWORD DeleteAllPrivileges(const std::vector<std::wstring>* exceptions);
+  //    restricted_token.DeleteAllPrivileges(privilege_exceptions);
+  DWORD DeleteAllPrivileges(const std::vector<std::wstring>& exceptions);
 
   // Adds a privilege to the list of privileges to remove in the restricted
   // token.
@@ -216,7 +205,7 @@
   // The list of restricting sids in the restricted token.
   std::vector<base::win::Sid> sids_to_restrict_;
   // The list of privileges to remove in the restricted token.
-  std::vector<LUID> privileges_to_disable_;
+  std::vector<CHROME_LUID> privileges_to_disable_;
   // The list of sids to mark as Deny Only in the restricted token.
   std::vector<base::win::Sid> sids_for_deny_only_;
   // The list of sids to add to the default DACL of the restricted token.
diff --git a/sandbox/win/src/restricted_token_unittest.cc b/sandbox/win/src/restricted_token_unittest.cc
index 5621819..534d5e02 100644
--- a/sandbox/win/src/restricted_token_unittest.cc
+++ b/sandbox/win/src/restricted_token_unittest.cc
@@ -402,8 +402,7 @@
   base::win::ScopedHandle token_handle;
 
   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
-  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
-            token.AddAllSidsForDenyOnly(nullptr));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.AddAllSidsForDenyOnly({}));
   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
             token.GetRestrictedToken(&token_handle));
 
@@ -438,7 +437,7 @@
 
   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
-            token.AddAllSidsForDenyOnly(&sids_exception));
+            token.AddAllSidsForDenyOnly(sids_exception));
   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
             token.GetRestrictedToken(&token_handle));
 
@@ -544,8 +543,7 @@
   base::win::ScopedHandle token_handle;
 
   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
-  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
-            token.DeleteAllPrivileges(nullptr));
+  ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.DeleteAllPrivileges({}));
   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
             token.GetRestrictedToken(&token_handle));
 
@@ -568,7 +566,7 @@
 
   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
-            token.DeleteAllPrivileges(&exceptions));
+            token.DeleteAllPrivileges(exceptions));
   ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
             token.GetRestrictedToken(&token_handle));
 
@@ -842,12 +840,14 @@
   CheckLowBoxToken(token, ::TokenPrimary, &caps_with_capabilities);
   CheckRestrictingSid(token.Get(), ATL::Sids::World(), 1);
 
-  SecurityCapabilities caps_for_handles(
-      *base::win::Sid::FromSddlString(L"S-1-15-2-1-2-3-4-5-6-8"));
+  auto caps_for_handles_sid =
+      base::win::Sid::FromSddlString(L"S-1-15-2-1-2-3-4-5-6-8");
+  ASSERT_TRUE(caps_for_handles_sid);
+  SecurityCapabilities caps_for_handles(*caps_for_handles_sid);
   base::win::ScopedHandle object_handle;
-  ASSERT_EQ(DWORD{ERROR_SUCCESS},
-            CreateLowBoxObjectDirectory(caps_for_handles.AppContainerSid, true,
-                                        &object_handle));
+  ASSERT_EQ(
+      DWORD{ERROR_SUCCESS},
+      CreateLowBoxObjectDirectory(*caps_for_handles_sid, true, &object_handle));
   HANDLE saved_handles[] = {object_handle.Get()};
 
   ASSERT_EQ(DWORD{ERROR_SUCCESS},
@@ -857,7 +857,7 @@
   object_handle.Close();
   ASSERT_FALSE(object_handle.IsValid());
   ASSERT_EQ(DWORD{ERROR_ALREADY_EXISTS},
-            CreateLowBoxObjectDirectory(caps_for_handles.AppContainerSid, false,
+            CreateLowBoxObjectDirectory(*caps_for_handles_sid, false,
                                         &object_handle));
 }
 
diff --git a/sandbox/win/src/restricted_token_utils.cc b/sandbox/win/src/restricted_token_utils.cc
index 60aff09..f68fe1d 100644
--- a/sandbox/win/src/restricted_token_utils.cc
+++ b/sandbox/win/src/restricted_token_utils.cc
@@ -185,13 +185,13 @@
 
   DWORD err_code = ERROR_SUCCESS;
   if (deny_sids) {
-    err_code = restricted_token.AddAllSidsForDenyOnly(&sid_exceptions);
+    err_code = restricted_token.AddAllSidsForDenyOnly(sid_exceptions);
     if (ERROR_SUCCESS != err_code)
       return err_code;
   }
 
   if (remove_privileges) {
-    err_code = restricted_token.DeleteAllPrivileges(&privilege_exceptions);
+    err_code = restricted_token.DeleteAllPrivileges(privilege_exceptions);
     if (ERROR_SUCCESS != err_code)
       return err_code;
   }
@@ -299,8 +299,8 @@
 
 DWORD CreateLowBoxToken(HANDLE base_token,
                         TokenType token_type,
-                        PSECURITY_CAPABILITIES security_capabilities,
-                        PHANDLE saved_handles,
+                        SECURITY_CAPABILITIES* security_capabilities,
+                        HANDLE* saved_handles,
                         DWORD saved_handles_count,
                         base::win::ScopedHandle* token) {
   NtCreateLowBoxToken CreateLowBoxToken = nullptr;
@@ -375,20 +375,20 @@
   return ERROR_SUCCESS;
 }
 
-DWORD CreateLowBoxObjectDirectory(PSID lowbox_sid,
+DWORD CreateLowBoxObjectDirectory(const base::win::Sid& lowbox_sid,
                                   bool open_directory,
                                   base::win::ScopedHandle* directory) {
   DWORD session_id = 0;
   if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &session_id))
     return ::GetLastError();
 
-  LPWSTR sid_string = nullptr;
-  if (!::ConvertSidToStringSid(lowbox_sid, &sid_string))
-    return ::GetLastError();
+  absl::optional<std::wstring> sid_string = lowbox_sid.ToSddlString();
+  if (!sid_string)
+    return ERROR_INVALID_SID;
 
-  std::unique_ptr<wchar_t, LocalFreeDeleter> sid_string_ptr(sid_string);
-  std::wstring directory_path = base::StringPrintf(
-      L"\\Sessions\\%d\\AppContainerNamedObjects\\%ls", session_id, sid_string);
+  std::wstring directory_path =
+      base::StringPrintf(L"\\Sessions\\%d\\AppContainerNamedObjects\\%ls",
+                         session_id, sid_string->c_str());
 
   NtCreateDirectoryObjectFunction CreateObjectDirectory = nullptr;
   ResolveNTFunctionPtr("NtCreateDirectoryObject", &CreateObjectDirectory);
diff --git a/sandbox/win/src/restricted_token_utils.h b/sandbox/win/src/restricted_token_utils.h
index 37bc2ec1..87d2270 100644
--- a/sandbox/win/src/restricted_token_utils.h
+++ b/sandbox/win/src/restricted_token_utils.h
@@ -5,10 +5,9 @@
 #ifndef SANDBOX_WIN_SRC_RESTRICTED_TOKEN_UTILS_H_
 #define SANDBOX_WIN_SRC_RESTRICTED_TOKEN_UTILS_H_
 
-#include <windows.h>
-
 #include "base/win/scoped_handle.h"
 #include "base/win/sid.h"
+#include "base/win/windows_types.h"
 #include "sandbox/win/src/restricted_token.h"
 #include "sandbox/win/src/security_level.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -18,7 +17,8 @@
 
 namespace sandbox {
 
-// The type of the token returned by the CreateNakedToken.
+// The type of the token returned by the CreateRestrictedToken and
+// CreateLowBoxToken APIs.
 enum TokenType { IMPERSONATION = 0, PRIMARY };
 
 // Creates a restricted token from effective token. If it's nullptr then
@@ -99,8 +99,8 @@
 // the error.
 DWORD CreateLowBoxToken(HANDLE base_token,
                         TokenType token_type,
-                        PSECURITY_CAPABILITIES security_capabilities,
-                        PHANDLE saved_handles,
+                        SECURITY_CAPABILITIES* security_capabilities,
+                        HANDLE* saved_handles,
                         DWORD saved_handles_count,
                         base::win::ScopedHandle* token);
 
@@ -112,7 +112,7 @@
 // If the function succeeds, the return value is ERROR_SUCCESS. If the
 // function fails, the return value is the win32 error code corresponding to
 // the error.
-DWORD CreateLowBoxObjectDirectory(PSID lowbox_sid,
+DWORD CreateLowBoxObjectDirectory(const base::win::Sid& lowbox_sid,
                                   bool open_directory,
                                   base::win::ScopedHandle* directory);
 
diff --git a/sandbox/win/src/sandbox.h b/sandbox/win/src/sandbox.h
index 3e280ad3..3fe939b8 100644
--- a/sandbox/win/src/sandbox.h
+++ b/sandbox/win/src/sandbox.h
@@ -19,18 +19,16 @@
 #ifndef SANDBOX_WIN_SRC_SANDBOX_H_
 #define SANDBOX_WIN_SRC_SANDBOX_H_
 
-#if !defined(SANDBOX_FUZZ_TARGET)
-#include <windows.h>
-#include <winsock2.h>
-#else
-#include "sandbox/win/fuzzer/fuzzer_types.h"
-#endif
-
 #include <stddef.h>
 #include <memory>
 #include <vector>
 
 #include "base/memory/ref_counted.h"
+#if !defined(SANDBOX_FUZZ_TARGET)
+#include "base/win/windows_types.h"
+#else
+#include "sandbox/win/fuzzer/fuzzer_types.h"
+#endif
 #include "sandbox/win/src/sandbox_policy.h"
 #include "sandbox/win/src/sandbox_types.h"
 
diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h
index df8491f..7ef1c8b6 100644
--- a/sandbox/win/src/sandbox_policy.h
+++ b/sandbox/win/src/sandbox_policy.h
@@ -30,7 +30,6 @@
     SUBSYS_NAMED_PIPES,      // Creation of named pipes.
     SUBSYS_PROCESS,          // Creation of child processes.
     SUBSYS_REGISTRY,         // Creation and opening of registry keys.
-    SUBSYS_SYNC,             // Creation of named sync objects.
     SUBSYS_WIN32K_LOCKDOWN,  // Win32K Lockdown related policy.
     SUBSYS_SIGNED_BINARY,    // Signed binary policy.
     SUBSYS_SOCKET            // Socket brokering policy.
@@ -53,15 +52,13 @@
                            // access on the returned handles.
                            // This flag can be used only when the main token of
                            // the sandboxed application is at least INTERACTIVE.
-    EVENTS_ALLOW_ANY,      // Allows the creation of an event with full access.
-    EVENTS_ALLOW_READONLY,  // Allows opening an even with synchronize access.
-    REG_ALLOW_READONLY,     // Allows readonly access to a registry key.
-    REG_ALLOW_ANY,          // Allows read and write access to a registry key.
-    FAKE_USER_GDI_INIT,     // Fakes user32 and gdi32 initialization. This can
-                            // be used to allow the DLLs to load and initialize
-                            // even if the process cannot access that subsystem.
-    SIGNED_ALLOW_LOAD,      // Allows loading the module when CIG is enabled.
-    SOCKET_ALLOW_BROKER     // Allows brokering of sockets.
+    REG_ALLOW_READONLY,    // Allows readonly access to a registry key.
+    REG_ALLOW_ANY,         // Allows read and write access to a registry key.
+    FAKE_USER_GDI_INIT,    // Fakes user32 and gdi32 initialization. This can
+                           // be used to allow the DLLs to load and initialize
+                           // even if the process cannot access that subsystem.
+    SIGNED_ALLOW_LOAD,     // Allows loading the module when CIG is enabled.
+    SOCKET_ALLOW_BROKER    // Allows brokering of sockets.
   };
 
   // Increments the reference count of this object. The reference count must
diff --git a/sandbox/win/src/sandbox_policy_base.cc b/sandbox/win/src/sandbox_policy_base.cc
index ad8562cc..e310759 100644
--- a/sandbox/win/src/sandbox_policy_base.cc
+++ b/sandbox/win/src/sandbox_policy_base.cc
@@ -16,6 +16,7 @@
 #include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #include "sandbox/win/src/acl.h"
+#include "sandbox/win/src/crosscall_server.h"
 #include "sandbox/win/src/filesystem_policy.h"
 #include "sandbox/win/src/interception.h"
 #include "sandbox/win/src/job.h"
@@ -33,7 +34,6 @@
 #include "sandbox/win/src/sandbox_utils.h"
 #include "sandbox/win/src/security_capabilities.h"
 #include "sandbox/win/src/signed_policy.h"
-#include "sandbox/win/src/sync_policy.h"
 #include "sandbox/win/src/target_process.h"
 #include "sandbox/win/src/top_level_dispatcher.h"
 #include "sandbox/win/src/window.h"
@@ -112,15 +112,12 @@
       add_restricting_random_sid_(false),
       effective_token_(nullptr),
       allow_no_sandbox_job_(false) {
-  ::InitializeCriticalSection(&lock_);
   dispatcher_ = std::make_unique<TopLevelDispatcher>(this);
 }
 
 PolicyBase::~PolicyBase() {
   delete policy_maker_;
   delete policy_;
-
-  ::DeleteCriticalSection(&lock_);
 }
 
 void PolicyBase::AddRef() {
@@ -541,13 +538,13 @@
   if (SBOX_ALL_OK != ret)
     return ret;
 
-  AutoLock lock(&lock_);
+  base::AutoLock lock(lock_);
   targets_.push_back(std::move(target));
   return SBOX_ALL_OK;
 }
 
 bool PolicyBase::OnJobEmpty(HANDLE job) {
-  AutoLock lock(&lock_);
+  base::AutoLock lock(lock_);
   targets_.erase(
       std::remove_if(targets_.begin(), targets_.end(),
                      [&](auto&& p) -> bool { return p->Job() == job; }),
@@ -556,7 +553,7 @@
 }
 
 bool PolicyBase::OnProcessFinished(DWORD process_id) {
-  AutoLock lock(&lock_);
+  base::AutoLock lock(lock_);
   targets_.erase(std::remove_if(targets_.begin(), targets_.end(),
                                 [&](auto&& p) -> bool {
                                   return p->ProcessId() == process_id;
@@ -715,13 +712,6 @@
       }
       break;
     }
-    case SUBSYS_SYNC: {
-      if (!SyncPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
-        NOTREACHED();
-        return SBOX_ERROR_BAD_PARAMS;
-      }
-      break;
-    }
     case SUBSYS_PROCESS: {
       if (lockdown_level_ < USER_INTERACTIVE &&
           TargetPolicy::PROCESS_ALL_EXEC == semantics) {
diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h
index 6c48afb..373fde41 100644
--- a/sandbox/win/src/sandbox_policy_base.h
+++ b/sandbox/win/src/sandbox_policy_base.h
@@ -5,8 +5,6 @@
 #ifndef SANDBOX_WIN_SRC_SANDBOX_POLICY_BASE_H_
 #define SANDBOX_WIN_SRC_SANDBOX_POLICY_BASE_H_
 
-#include <windows.h>
-
 #include <stddef.h>
 #include <stdint.h>
 
@@ -18,18 +16,19 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/process/launch.h"
+#include "base/synchronization/lock.h"
 #include "base/win/scoped_handle.h"
+#include "base/win/windows_types.h"
 #include "sandbox/win/src/app_container_base.h"
-#include "sandbox/win/src/crosscall_server.h"
 #include "sandbox/win/src/handle_closer.h"
 #include "sandbox/win/src/ipc_tags.h"
 #include "sandbox/win/src/policy_engine_opcodes.h"
 #include "sandbox/win/src/policy_engine_params.h"
 #include "sandbox/win/src/sandbox_policy.h"
-#include "sandbox/win/src/win_utils.h"
 
 namespace sandbox {
 
+class Dispatcher;
 class LowLevelPolicy;
 class PolicyDiagnostic;
 class PolicyInfo;
@@ -103,8 +102,6 @@
                         base::win::ScopedHandle* lockdown,
                         base::win::ScopedHandle* lowbox);
 
-  PSID GetLowBoxSid() const;
-
   // Adds a target process to the internal list of targets. Internally a
   // call to TargetProcess::Init() is issued.
   ResultCode AddTarget(std::unique_ptr<TargetProcess> target);
@@ -142,7 +139,7 @@
                              const wchar_t* pattern);
 
   // This lock synchronizes operations on the targets_ collection.
-  CRITICAL_SECTION lock_;
+  base::Lock lock_;
   // Maintains the list of target process associated with this policy.
   // The policy takes ownership of them.
   typedef std::list<std::unique_ptr<TargetProcess>> TargetSet;
diff --git a/sandbox/win/src/sandbox_policy_diagnostic.cc b/sandbox/win/src/sandbox_policy_diagnostic.cc
index a4bdf8c7..0760571 100644
--- a/sandbox/win/src/sandbox_policy_diagnostic.cc
+++ b/sandbox/win/src/sandbox_policy_diagnostic.cc
@@ -177,10 +177,6 @@
       return "NtOpenProcessTokenEx";
     case IpcTag::CREATEPROCESSW:
       return "CreateProcessW";
-    case IpcTag::CREATEEVENT:
-      return "CreateEvent";
-    case IpcTag::OPENEVENT:
-      return "OpenEvent";
     case IpcTag::NTCREATEKEY:
       return "NtCreateKey";
     case IpcTag::NTOPENKEY:
@@ -384,7 +380,7 @@
   DCHECK(policy);
   // TODO(crbug/997273) Add more fields once webui plumbing is complete.
   {
-    AutoLock lock(&policy->lock_);
+    base::AutoLock lock(policy->lock_);
     for (auto&& target_process : policy->targets_) {
       process_ids_.push_back(
           base::strict_cast<uint32_t>(target_process->ProcessId()));
diff --git a/sandbox/win/src/signed_dispatcher.cc b/sandbox/win/src/signed_dispatcher.cc
index 49e7cbe..b2ef054e 100644
--- a/sandbox/win/src/signed_dispatcher.cc
+++ b/sandbox/win/src/signed_dispatcher.cc
@@ -18,6 +18,7 @@
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/signed_interception.h"
 #include "sandbox/win/src/signed_policy.h"
+#include "sandbox/win/src/win_utils.h"
 
 namespace sandbox {
 
diff --git a/sandbox/win/src/sync_dispatcher.cc b/sandbox/win/src/sync_dispatcher.cc
deleted file mode 100644
index d728e1d..0000000
--- a/sandbox/win/src/sync_dispatcher.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "sandbox/win/src/sync_dispatcher.h"
-
-#include <stdint.h>
-
-#include "base/win/windows_version.h"
-#include "sandbox/win/src/crosscall_client.h"
-#include "sandbox/win/src/interception.h"
-#include "sandbox/win/src/interceptors.h"
-#include "sandbox/win/src/ipc_tags.h"
-#include "sandbox/win/src/policy_broker.h"
-#include "sandbox/win/src/policy_params.h"
-#include "sandbox/win/src/sandbox.h"
-#include "sandbox/win/src/sync_interception.h"
-#include "sandbox/win/src/sync_policy.h"
-
-namespace sandbox {
-
-SyncDispatcher::SyncDispatcher(PolicyBase* policy_base)
-    : policy_base_(policy_base) {
-  static const IPCCall create_params = {
-      {IpcTag::CREATEEVENT, {WCHAR_TYPE, UINT32_TYPE, UINT32_TYPE}},
-      reinterpret_cast<CallbackGeneric>(&SyncDispatcher::CreateEvent)};
-
-  static const IPCCall open_params = {
-      {IpcTag::OPENEVENT, {WCHAR_TYPE, UINT32_TYPE}},
-      reinterpret_cast<CallbackGeneric>(&SyncDispatcher::OpenEvent)};
-
-  ipc_calls_.push_back(create_params);
-  ipc_calls_.push_back(open_params);
-}
-
-bool SyncDispatcher::SetupService(InterceptionManager* manager,
-                                  IpcTag service) {
-  if (service == IpcTag::CREATEEVENT) {
-    return INTERCEPT_NT(manager, NtCreateEvent, CREATE_EVENT_ID, 24);
-  }
-  return (service == IpcTag::OPENEVENT) &&
-         INTERCEPT_NT(manager, NtOpenEvent, OPEN_EVENT_ID, 16);
-}
-
-bool SyncDispatcher::CreateEvent(IPCInfo* ipc,
-                                 std::wstring* name,
-                                 uint32_t event_type,
-                                 uint32_t initial_state) {
-  const wchar_t* event_name = name->c_str();
-  CountedParameterSet<NameBased> params;
-  params[NameBased::NAME] = ParamPickerMake(event_name);
-
-  EvalResult result =
-      policy_base_->EvalPolicy(IpcTag::CREATEEVENT, params.GetBase());
-  HANDLE handle = nullptr;
-  // Return operation status on the IPC.
-  ipc->return_info.nt_status = SyncPolicy::CreateEventAction(
-      result, *ipc->client_info, *name, event_type, initial_state, &handle);
-  ipc->return_info.handle = handle;
-  return true;
-}
-
-bool SyncDispatcher::OpenEvent(IPCInfo* ipc,
-                               std::wstring* name,
-                               uint32_t desired_access) {
-  const wchar_t* event_name = name->c_str();
-
-  CountedParameterSet<OpenEventParams> params;
-  params[OpenEventParams::NAME] = ParamPickerMake(event_name);
-  params[OpenEventParams::ACCESS] = ParamPickerMake(desired_access);
-
-  EvalResult result =
-      policy_base_->EvalPolicy(IpcTag::OPENEVENT, params.GetBase());
-  HANDLE handle = nullptr;
-  // Return operation status on the IPC.
-  ipc->return_info.nt_status = SyncPolicy::OpenEventAction(
-      result, *ipc->client_info, *name, desired_access, &handle);
-  ipc->return_info.handle = handle;
-  return true;
-}
-
-}  // namespace sandbox
diff --git a/sandbox/win/src/sync_dispatcher.h b/sandbox/win/src/sync_dispatcher.h
deleted file mode 100644
index bae1bd3..0000000
--- a/sandbox/win/src/sync_dispatcher.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2010 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 SANDBOX_WIN_SRC_SYNC_DISPATCHER_H_
-#define SANDBOX_WIN_SRC_SYNC_DISPATCHER_H_
-
-#include <stdint.h>
-
-#include <string>
-
-#include "sandbox/win/src/crosscall_server.h"
-#include "sandbox/win/src/ipc_tags.h"
-#include "sandbox/win/src/sandbox_policy_base.h"
-
-namespace sandbox {
-
-// This class handles sync-related IPC calls.
-class SyncDispatcher : public Dispatcher {
- public:
-  explicit SyncDispatcher(PolicyBase* policy_base);
-
-  SyncDispatcher(const SyncDispatcher&) = delete;
-  SyncDispatcher& operator=(const SyncDispatcher&) = delete;
-
-  ~SyncDispatcher() override {}
-
-  // Dispatcher interface.
-  bool SetupService(InterceptionManager* manager, IpcTag service) override;
-
- private:
-  // Processes IPC requests coming from calls to CreateEvent in the target.
-  bool CreateEvent(IPCInfo* ipc,
-                   std::wstring* name,
-                   uint32_t event_type,
-                   uint32_t initial_state);
-
-  // Processes IPC requests coming from calls to OpenEvent in the target.
-  bool OpenEvent(IPCInfo* ipc, std::wstring* name, uint32_t desired_access);
-
-  PolicyBase* policy_base_;
-};
-
-}  // namespace sandbox
-
-#endif  // SANDBOX_WIN_SRC_SYNC_DISPATCHER_H_
diff --git a/sandbox/win/src/sync_interception.cc b/sandbox/win/src/sync_interception.cc
deleted file mode 100644
index d062ecb..0000000
--- a/sandbox/win/src/sync_interception.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright (c) 2006-2008 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 "sandbox/win/src/sync_interception.h"
-
-#include <stdint.h>
-
-#include "sandbox/win/src/crosscall_client.h"
-#include "sandbox/win/src/ipc_tags.h"
-#include "sandbox/win/src/policy_params.h"
-#include "sandbox/win/src/policy_target.h"
-#include "sandbox/win/src/sandbox_factory.h"
-#include "sandbox/win/src/sandbox_nt_util.h"
-#include "sandbox/win/src/sharedmem_ipc_client.h"
-#include "sandbox/win/src/target_services.h"
-
-namespace sandbox {
-
-ResultCode ProxyCreateEvent(LPCWSTR name,
-                            uint32_t initial_state,
-                            EVENT_TYPE event_type,
-                            void* ipc_memory,
-                            CrossCallReturn* answer) {
-  CountedParameterSet<NameBased> params;
-  params[NameBased::NAME] = ParamPickerMake(name);
-
-  if (!QueryBroker(IpcTag::CREATEEVENT, params.GetBase()))
-    return SBOX_ERROR_GENERIC;
-
-  SharedMemIPCClient ipc(ipc_memory);
-  ResultCode code = CrossCall(ipc, IpcTag::CREATEEVENT, name, event_type,
-                              initial_state, answer);
-  return code;
-}
-
-ResultCode ProxyOpenEvent(LPCWSTR name,
-                          uint32_t desired_access,
-                          void* ipc_memory,
-                          CrossCallReturn* answer) {
-  CountedParameterSet<OpenEventParams> params;
-  params[OpenEventParams::NAME] = ParamPickerMake(name);
-  params[OpenEventParams::ACCESS] = ParamPickerMake(desired_access);
-
-  if (!QueryBroker(IpcTag::OPENEVENT, params.GetBase()))
-    return SBOX_ERROR_GENERIC;
-
-  SharedMemIPCClient ipc(ipc_memory);
-  ResultCode code =
-      CrossCall(ipc, IpcTag::OPENEVENT, name, desired_access, answer);
-
-  return code;
-}
-
-NTSTATUS WINAPI TargetNtCreateEvent(NtCreateEventFunction orig_CreateEvent,
-                                    PHANDLE event_handle,
-                                    ACCESS_MASK desired_access,
-                                    POBJECT_ATTRIBUTES object_attributes,
-                                    EVENT_TYPE event_type,
-                                    BOOLEAN initial_state) {
-  NTSTATUS status =
-      orig_CreateEvent(event_handle, desired_access, object_attributes,
-                       event_type, initial_state);
-  if (status != STATUS_ACCESS_DENIED || !object_attributes)
-    return status;
-
-  // We don't trust that the IPC can work this early.
-  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
-    return status;
-
-  do {
-    if (!ValidParameter(event_handle, sizeof(HANDLE), WRITE))
-      break;
-
-    void* memory = GetGlobalIPCMemory();
-    if (!memory)
-      break;
-
-    OBJECT_ATTRIBUTES object_attribs_copy = *object_attributes;
-    // The RootDirectory points to BaseNamedObjects. We can ignore it.
-    object_attribs_copy.RootDirectory = nullptr;
-
-    std::unique_ptr<wchar_t, NtAllocDeleter> name;
-    uint32_t attributes = 0;
-    NTSTATUS ret =
-        AllocAndCopyName(&object_attribs_copy, &name, &attributes, nullptr);
-    if (!NT_SUCCESS(ret) || !name)
-      break;
-
-    CrossCallReturn answer = {0};
-    answer.nt_status = status;
-    ResultCode code = ProxyCreateEvent(name.get(), initial_state, event_type,
-                                       memory, &answer);
-
-    if (code != SBOX_ALL_OK) {
-      status = answer.nt_status;
-      break;
-    }
-    __try {
-      *event_handle = answer.handle;
-      status = STATUS_SUCCESS;
-    } __except (EXCEPTION_EXECUTE_HANDLER) {
-      break;
-    }
-  } while (false);
-
-  return status;
-}
-
-NTSTATUS WINAPI TargetNtOpenEvent(NtOpenEventFunction orig_OpenEvent,
-                                  PHANDLE event_handle,
-                                  ACCESS_MASK desired_access,
-                                  POBJECT_ATTRIBUTES object_attributes) {
-  NTSTATUS status =
-      orig_OpenEvent(event_handle, desired_access, object_attributes);
-  if (status != STATUS_ACCESS_DENIED || !object_attributes)
-    return status;
-
-  // We don't trust that the IPC can work this early.
-  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
-    return status;
-
-  do {
-    if (!ValidParameter(event_handle, sizeof(HANDLE), WRITE))
-      break;
-
-    void* memory = GetGlobalIPCMemory();
-    if (!memory)
-      break;
-
-    OBJECT_ATTRIBUTES object_attribs_copy = *object_attributes;
-    // The RootDirectory points to BaseNamedObjects. We can ignore it.
-    object_attribs_copy.RootDirectory = nullptr;
-
-    std::unique_ptr<wchar_t, NtAllocDeleter> name;
-    uint32_t attributes = 0;
-    NTSTATUS ret =
-        AllocAndCopyName(&object_attribs_copy, &name, &attributes, nullptr);
-    if (!NT_SUCCESS(ret) || !name)
-      break;
-
-    CrossCallReturn answer = {0};
-    answer.nt_status = status;
-    ResultCode code =
-        ProxyOpenEvent(name.get(), desired_access, memory, &answer);
-
-    if (code != SBOX_ALL_OK) {
-      status = answer.nt_status;
-      break;
-    }
-    __try {
-      *event_handle = answer.handle;
-      status = STATUS_SUCCESS;
-    } __except (EXCEPTION_EXECUTE_HANDLER) {
-      break;
-    }
-  } while (false);
-
-  return status;
-}
-
-}  // namespace sandbox
diff --git a/sandbox/win/src/sync_interception.h b/sandbox/win/src/sync_interception.h
deleted file mode 100644
index c21e7ee..0000000
--- a/sandbox/win/src/sync_interception.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2006-2008 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 SANDBOX_WIN_SRC_SYNC_INTERCEPTION_H_
-#define SANDBOX_WIN_SRC_SYNC_INTERCEPTION_H_
-
-#include "sandbox/win/src/nt_internals.h"
-#include "sandbox/win/src/sandbox_types.h"
-
-namespace sandbox {
-
-extern "C" {
-
-typedef NTSTATUS(WINAPI* NtCreateEventFunction)(
-    PHANDLE EventHandle,
-    ACCESS_MASK DesiredAccess,
-    POBJECT_ATTRIBUTES ObjectAttributes,
-    EVENT_TYPE EventType,
-    BOOLEAN InitialState);
-
-typedef NTSTATUS(WINAPI* NtOpenEventFunction)(
-    PHANDLE EventHandle,
-    ACCESS_MASK DesiredAccess,
-    POBJECT_ATTRIBUTES ObjectAttributes);
-
-// Interceptors for NtCreateEvent/NtOpenEvent
-SANDBOX_INTERCEPT NTSTATUS WINAPI
-TargetNtCreateEvent(NtCreateEventFunction orig_CreateEvent,
-                    PHANDLE event_handle,
-                    ACCESS_MASK desired_access,
-                    POBJECT_ATTRIBUTES object_attributes,
-                    EVENT_TYPE event_type,
-                    BOOLEAN initial_state);
-
-SANDBOX_INTERCEPT NTSTATUS WINAPI
-TargetNtOpenEvent(NtOpenEventFunction orig_OpenEvent,
-                  PHANDLE event_handle,
-                  ACCESS_MASK desired_access,
-                  POBJECT_ATTRIBUTES object_attributes);
-
-}  // extern "C"
-
-}  // namespace sandbox
-
-#endif  // SANDBOX_WIN_SRC_SYNC_INTERCEPTION_H_
diff --git a/sandbox/win/src/sync_policy.cc b/sandbox/win/src/sync_policy.cc
deleted file mode 100644
index fb1777cc..0000000
--- a/sandbox/win/src/sync_policy.cc
+++ /dev/null
@@ -1,248 +0,0 @@
-// Copyright (c) 2006-2008 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 "sandbox/win/src/sync_policy.h"
-
-#include <stdint.h>
-
-#include <string>
-
-#include "base/logging.h"
-#include "base/strings/stringprintf.h"
-#include "sandbox/win/src/ipc_tags.h"
-#include "sandbox/win/src/nt_internals.h"
-#include "sandbox/win/src/policy_engine_opcodes.h"
-#include "sandbox/win/src/policy_params.h"
-#include "sandbox/win/src/sandbox_types.h"
-#include "sandbox/win/src/sandbox_utils.h"
-#include "sandbox/win/src/sync_interception.h"
-#include "sandbox/win/src/win_utils.h"
-
-namespace sandbox {
-
-// Provides functionality to resolve a symbolic link within the object
-// directory passed in.
-NTSTATUS ResolveSymbolicLink(const std::wstring& directory_name,
-                             const std::wstring& name,
-                             std::wstring* target) {
-  NtOpenDirectoryObjectFunction NtOpenDirectoryObject = nullptr;
-  ResolveNTFunctionPtr("NtOpenDirectoryObject", &NtOpenDirectoryObject);
-
-  NtQuerySymbolicLinkObjectFunction NtQuerySymbolicLinkObject = nullptr;
-  ResolveNTFunctionPtr("NtQuerySymbolicLinkObject", &NtQuerySymbolicLinkObject);
-
-  NtOpenSymbolicLinkObjectFunction NtOpenSymbolicLinkObject = nullptr;
-  ResolveNTFunctionPtr("NtOpenSymbolicLinkObject", &NtOpenSymbolicLinkObject);
-
-  NtCloseFunction NtClose = nullptr;
-  ResolveNTFunctionPtr("NtClose", &NtClose);
-
-  OBJECT_ATTRIBUTES symbolic_link_directory_attributes = {};
-  UNICODE_STRING symbolic_link_directory_string = {};
-  InitObjectAttribs(directory_name, OBJ_CASE_INSENSITIVE, nullptr,
-                    &symbolic_link_directory_attributes,
-                    &symbolic_link_directory_string, nullptr);
-
-  HANDLE symbolic_link_directory = nullptr;
-  NTSTATUS status =
-      NtOpenDirectoryObject(&symbolic_link_directory, DIRECTORY_QUERY,
-                            &symbolic_link_directory_attributes);
-  if (!NT_SUCCESS(status))
-    return status;
-
-  OBJECT_ATTRIBUTES symbolic_link_attributes = {};
-  UNICODE_STRING name_string = {};
-  InitObjectAttribs(name, OBJ_CASE_INSENSITIVE, symbolic_link_directory,
-                    &symbolic_link_attributes, &name_string, nullptr);
-
-  HANDLE symbolic_link = nullptr;
-  status = NtOpenSymbolicLinkObject(&symbolic_link, GENERIC_READ,
-                                    &symbolic_link_attributes);
-  CHECK(NT_SUCCESS(NtClose(symbolic_link_directory)));
-  if (!NT_SUCCESS(status))
-    return status;
-
-  UNICODE_STRING target_path = {};
-  unsigned long target_bytes = 0;
-  status =
-      NtQuerySymbolicLinkObject(symbolic_link, &target_path, &target_bytes);
-  if (status != STATUS_BUFFER_TOO_SMALL) {
-    CHECK(NT_SUCCESS(NtClose(symbolic_link)));
-    return status;
-  }
-
-  // NtQuerySymbolicLinkObject length and UNICODE_STRING lengths are bytes
-  // not characters.
-  size_t target_wchars = target_bytes / sizeof(wchar_t);
-  target_path.Length = 0;
-  target_path.MaximumLength = static_cast<USHORT>(target_bytes);
-  target_path.Buffer = new wchar_t[target_wchars + 1];
-  status =
-      NtQuerySymbolicLinkObject(symbolic_link, &target_path, &target_bytes);
-  if (NT_SUCCESS(status)) {
-    DCHECK_EQ(target_bytes, sizeof(wchar_t) * target_wchars);
-    target->assign(target_path.Buffer, target_wchars);
-  }
-
-  CHECK(NT_SUCCESS(NtClose(symbolic_link)));
-  delete[] target_path.Buffer;
-  return status;
-}
-
-NTSTATUS GetBaseNamedObjectsDirectory(HANDLE* directory) {
-  static HANDLE base_named_objects_handle = nullptr;
-  if (base_named_objects_handle) {
-    *directory = base_named_objects_handle;
-    return STATUS_SUCCESS;
-  }
-
-  NtOpenDirectoryObjectFunction NtOpenDirectoryObject = nullptr;
-  ResolveNTFunctionPtr("NtOpenDirectoryObject", &NtOpenDirectoryObject);
-
-  DWORD session_id = 0;
-  ProcessIdToSessionId(::GetCurrentProcessId(), &session_id);
-
-  std::wstring base_named_objects_path;
-
-  NTSTATUS status = ResolveSymbolicLink(L"\\Sessions\\BNOLINKS",
-                                        base::StringPrintf(L"%d", session_id),
-                                        &base_named_objects_path);
-  if (!NT_SUCCESS(status)) {
-    DLOG(ERROR) << "Failed to resolve BaseNamedObjects path. Error: " << status;
-    return status;
-  }
-
-  UNICODE_STRING directory_name = {};
-  OBJECT_ATTRIBUTES object_attributes = {};
-  InitObjectAttribs(base_named_objects_path, OBJ_CASE_INSENSITIVE, nullptr,
-                    &object_attributes, &directory_name, nullptr);
-  status = NtOpenDirectoryObject(&base_named_objects_handle,
-                                 DIRECTORY_ALL_ACCESS, &object_attributes);
-  if (NT_SUCCESS(status))
-    *directory = base_named_objects_handle;
-  return status;
-}
-
-bool SyncPolicy::GenerateRules(const wchar_t* name,
-                               TargetPolicy::Semantics semantics,
-                               LowLevelPolicy* policy) {
-  std::wstring mod_name(name);
-  if (mod_name.empty()) {
-    return false;
-  }
-
-  if (TargetPolicy::EVENTS_ALLOW_ANY != semantics &&
-      TargetPolicy::EVENTS_ALLOW_READONLY != semantics) {
-    // Other flags are not valid for sync policy yet.
-    NOTREACHED();
-    return false;
-  }
-
-  // Add the open rule.
-  EvalResult result = ASK_BROKER;
-  PolicyRule open(result);
-
-  if (!open.AddStringMatch(IF, OpenEventParams::NAME, name, CASE_INSENSITIVE))
-    return false;
-
-  if (TargetPolicy::EVENTS_ALLOW_READONLY == semantics) {
-    // We consider all flags that are not known to be readonly as potentially
-    // used for write.
-    uint32_t allowed_flags = SYNCHRONIZE | GENERIC_READ | READ_CONTROL;
-    uint32_t restricted_flags = ~allowed_flags;
-    open.AddNumberMatch(IF_NOT, OpenEventParams::ACCESS, restricted_flags, AND);
-  }
-
-  if (!policy->AddRule(IpcTag::OPENEVENT, &open))
-    return false;
-
-  // If it's not a read only, add the create rule.
-  if (TargetPolicy::EVENTS_ALLOW_READONLY != semantics) {
-    PolicyRule create(result);
-    if (!create.AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE))
-      return false;
-
-    if (!policy->AddRule(IpcTag::CREATEEVENT, &create))
-      return false;
-  }
-
-  return true;
-}
-
-NTSTATUS SyncPolicy::CreateEventAction(EvalResult eval_result,
-                                       const ClientInfo& client_info,
-                                       const std::wstring& event_name,
-                                       uint32_t event_type,
-                                       uint32_t initial_state,
-                                       HANDLE* handle) {
-  NtCreateEventFunction NtCreateEvent = nullptr;
-  ResolveNTFunctionPtr("NtCreateEvent", &NtCreateEvent);
-
-  // The only action supported is ASK_BROKER which means create the requested
-  // file as specified.
-  if (ASK_BROKER != eval_result)
-    return false;
-
-  HANDLE object_directory = nullptr;
-  NTSTATUS status = GetBaseNamedObjectsDirectory(&object_directory);
-  if (status != STATUS_SUCCESS)
-    return status;
-
-  UNICODE_STRING unicode_event_name = {};
-  OBJECT_ATTRIBUTES object_attributes = {};
-  InitObjectAttribs(event_name, OBJ_CASE_INSENSITIVE, object_directory,
-                    &object_attributes, &unicode_event_name, nullptr);
-
-  HANDLE local_handle = nullptr;
-  status = NtCreateEvent(&local_handle, EVENT_ALL_ACCESS, &object_attributes,
-                         static_cast<EVENT_TYPE>(event_type),
-                         static_cast<BOOLEAN>(initial_state != 0));
-  if (!local_handle)
-    return status;
-
-  if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
-                         client_info.process, handle, 0, false,
-                         DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
-    return STATUS_ACCESS_DENIED;
-  }
-  return status;
-}
-
-NTSTATUS SyncPolicy::OpenEventAction(EvalResult eval_result,
-                                     const ClientInfo& client_info,
-                                     const std::wstring& event_name,
-                                     uint32_t desired_access,
-                                     HANDLE* handle) {
-  NtOpenEventFunction NtOpenEvent = nullptr;
-  ResolveNTFunctionPtr("NtOpenEvent", &NtOpenEvent);
-
-  // The only action supported is ASK_BROKER which means create the requested
-  // event as specified.
-  if (ASK_BROKER != eval_result)
-    return false;
-
-  HANDLE object_directory = nullptr;
-  NTSTATUS status = GetBaseNamedObjectsDirectory(&object_directory);
-  if (status != STATUS_SUCCESS)
-    return status;
-
-  UNICODE_STRING unicode_event_name = {};
-  OBJECT_ATTRIBUTES object_attributes = {};
-  InitObjectAttribs(event_name, OBJ_CASE_INSENSITIVE, object_directory,
-                    &object_attributes, &unicode_event_name, nullptr);
-
-  HANDLE local_handle = nullptr;
-  status = NtOpenEvent(&local_handle, desired_access, &object_attributes);
-  if (!local_handle)
-    return status;
-
-  if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
-                         client_info.process, handle, 0, false,
-                         DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
-    return STATUS_ACCESS_DENIED;
-  }
-  return status;
-}
-
-}  // namespace sandbox
diff --git a/sandbox/win/src/sync_policy.h b/sandbox/win/src/sync_policy.h
deleted file mode 100644
index 375b462c..0000000
--- a/sandbox/win/src/sync_policy.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2006-2008 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 SANDBOX_WIN_SRC_SYNC_POLICY_H_
-#define SANDBOX_WIN_SRC_SYNC_POLICY_H_
-
-#include <stdint.h>
-
-#include <string>
-
-#include "sandbox/win/src/crosscall_server.h"
-#include "sandbox/win/src/nt_internals.h"
-#include "sandbox/win/src/policy_low_level.h"
-#include "sandbox/win/src/sandbox_policy.h"
-
-namespace sandbox {
-
-// This class centralizes most of the knowledge related to sync policy
-class SyncPolicy {
- public:
-  // Creates the required low-level policy rules to evaluate a high-level
-  // policy rule for sync calls, in particular open or create actions.
-  // name is the sync object name, semantics is the desired semantics for the
-  // open or create and policy is the policy generator to which the rules are
-  // going to be added.
-  static bool GenerateRules(const wchar_t* name,
-                            TargetPolicy::Semantics semantics,
-                            LowLevelPolicy* policy);
-
-  // Performs the desired policy action on a request.
-  // client_info is the target process that is making the request and
-  // eval_result is the desired policy action to accomplish.
-  static NTSTATUS CreateEventAction(EvalResult eval_result,
-                                    const ClientInfo& client_info,
-                                    const std::wstring& event_name,
-                                    uint32_t event_type,
-                                    uint32_t initial_state,
-                                    HANDLE* handle);
-  static NTSTATUS OpenEventAction(EvalResult eval_result,
-                                  const ClientInfo& client_info,
-                                  const std::wstring& event_name,
-                                  uint32_t desired_access,
-                                  HANDLE* handle);
-};
-
-}  // namespace sandbox
-
-#endif  // SANDBOX_WIN_SRC_SYNC_POLICY_H_
diff --git a/sandbox/win/src/sync_policy_test.cc b/sandbox/win/src/sync_policy_test.cc
deleted file mode 100644
index 97f60d35..0000000
--- a/sandbox/win/src/sync_policy_test.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright (c) 2011 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 "sandbox/win/src/sync_policy_test.h"
-
-#include "base/win/scoped_handle.h"
-#include "sandbox/win/src/nt_internals.h"
-#include "sandbox/win/src/sandbox.h"
-#include "sandbox/win/src/sandbox_factory.h"
-#include "sandbox/win/src/sandbox_policy.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace sandbox {
-
-SBOX_TESTS_COMMAND int Event_Open(int argc, wchar_t** argv) {
-  if (argc != 2)
-    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
-
-  DWORD desired_access = SYNCHRONIZE;
-  if (L'f' == argv[0][0])
-    desired_access = EVENT_ALL_ACCESS;
-
-  base::win::ScopedHandle event_open(
-      ::OpenEvent(desired_access, false, argv[1]));
-  DWORD error_open = ::GetLastError();
-
-  if (event_open.IsValid())
-    return SBOX_TEST_SUCCEEDED;
-
-  if (ERROR_ACCESS_DENIED == error_open || ERROR_BAD_PATHNAME == error_open ||
-      ERROR_FILE_NOT_FOUND == error_open)
-    return SBOX_TEST_DENIED;
-
-  return SBOX_TEST_FAILED;
-}
-
-SBOX_TESTS_COMMAND int Event_CreateOpen(int argc, wchar_t** argv) {
-  if (argc < 2 || argc > 3)
-    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
-
-  wchar_t* event_name = nullptr;
-  if (3 == argc)
-    event_name = argv[2];
-
-  bool manual_reset = false;
-  bool initial_state = false;
-  if (L't' == argv[0][0])
-    manual_reset = true;
-  if (L't' == argv[1][0])
-    initial_state = true;
-
-  base::win::ScopedHandle event_create(
-      ::CreateEvent(nullptr, manual_reset, initial_state, event_name));
-  DWORD error_create = ::GetLastError();
-  base::win::ScopedHandle event_open;
-  if (event_name)
-    event_open.Set(::OpenEvent(EVENT_ALL_ACCESS, false, event_name));
-
-  if (event_create.IsValid()) {
-    DWORD wait = ::WaitForSingleObject(event_create.Get(), 0);
-    if (initial_state && WAIT_OBJECT_0 != wait)
-      return SBOX_TEST_FAILED;
-
-    if (!initial_state && WAIT_TIMEOUT != wait)
-      return SBOX_TEST_FAILED;
-  }
-
-  if (event_name) {
-    // Both event_open and event_create have to be valid.
-    if (event_open.IsValid() && event_create.IsValid())
-      return SBOX_TEST_SUCCEEDED;
-
-    if ((event_open.IsValid() && !event_create.IsValid()) ||
-        (!event_open.IsValid() && event_create.IsValid())) {
-      return SBOX_TEST_FAILED;
-    }
-  } else {
-    // Only event_create has to be valid.
-    if (event_create.Get())
-      return SBOX_TEST_SUCCEEDED;
-  }
-
-  if (ERROR_ACCESS_DENIED == error_create || ERROR_BAD_PATHNAME == error_create)
-    return SBOX_TEST_DENIED;
-
-  return SBOX_TEST_FAILED;
-}
-
-// Tests the creation of events using all the possible combinations.
-TEST(SyncPolicyTest, TestEvent) {
-  TestRunner runner;
-  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
-                             TargetPolicy::EVENTS_ALLOW_ANY, L"test1"));
-  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
-                             TargetPolicy::EVENTS_ALLOW_ANY, L"test2"));
-
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f f"));
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t f"));
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f t"));
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t t"));
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f f test1"));
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t f test2"));
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f t test1"));
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t t test2"));
-  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen f f test3"));
-  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen t f test4"));
-  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen f t test3"));
-  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen t t test4"));
-}
-
-// Tests opening events with read only access.
-TEST(SyncPolicyTest, TestEventReadOnly) {
-  TestRunner runner;
-  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
-                             TargetPolicy::EVENTS_ALLOW_READONLY, L"test1"));
-  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
-                             TargetPolicy::EVENTS_ALLOW_READONLY, L"test2"));
-  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
-                             TargetPolicy::EVENTS_ALLOW_READONLY, L"test5"));
-  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
-                             TargetPolicy::EVENTS_ALLOW_READONLY, L"test6"));
-
-  base::win::ScopedHandle handle1(
-      ::CreateEvent(nullptr, false, false, L"test1"));
-  base::win::ScopedHandle handle2(
-      ::CreateEvent(nullptr, false, false, L"test2"));
-  base::win::ScopedHandle handle3(
-      ::CreateEvent(nullptr, false, false, L"test3"));
-  base::win::ScopedHandle handle4(
-      ::CreateEvent(nullptr, false, false, L"test4"));
-
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f f"));
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t f"));
-  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open f test1"));
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_Open s test2"));
-  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open f test3"));
-  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open s test4"));
-  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen f f test5"));
-  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen t f test6"));
-  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen f t test5"));
-  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen t t test6"));
-}
-
-}  // namespace sandbox
diff --git a/sandbox/win/src/sync_policy_test.h b/sandbox/win/src/sync_policy_test.h
deleted file mode 100644
index 4f354b3..0000000
--- a/sandbox/win/src/sync_policy_test.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SANDBOX_WIN_SRC_SYNC_POLICY_TEST_H_
-#define SANDBOX_WIN_SRC_SYNC_POLICY_TEST_H_
-
-#include "sandbox/win/tests/common/controller.h"
-
-namespace sandbox {
-
-// Opens the named event received on argv[1]. The requested access is
-// EVENT_ALL_ACCESS if argv[0] starts with 'f', or SYNCHRONIZE otherwise.
-SBOX_TESTS_COMMAND int Event_Open(int argc, wchar_t **argv);
-
-}  // namespace sandbox
-
-#endif  // SANDBOX_WIN_SRC_SYNC_POLICY_TEST_H_
diff --git a/sandbox/win/src/target_process.cc b/sandbox/win/src/target_process.cc
index 5288359fc..5490cfbd 100644
--- a/sandbox/win/src/target_process.cc
+++ b/sandbox/win/src/target_process.cc
@@ -4,6 +4,8 @@
 
 #include "sandbox/win/src/target_process.h"
 
+#include <windows.h>
+
 #include <stddef.h>
 #include <stdint.h>
 
diff --git a/sandbox/win/src/target_process.h b/sandbox/win/src/target_process.h
index bc7a6b6..dbc529c0 100644
--- a/sandbox/win/src/target_process.h
+++ b/sandbox/win/src/target_process.h
@@ -5,8 +5,6 @@
 #ifndef SANDBOX_WIN_SRC_TARGET_PROCESS_H_
 #define SANDBOX_WIN_SRC_TARGET_PROCESS_H_
 
-#include <windows.h>
-
 #include <stddef.h>
 #include <stdint.h>
 
@@ -17,11 +15,12 @@
 #include "base/win/scoped_handle.h"
 #include "base/win/scoped_process_information.h"
 #include "base/win/sid.h"
-#include "sandbox/win/src/crosscall_server.h"
+#include "base/win/windows_types.h"
 #include "sandbox/win/src/sandbox_types.h"
 
 namespace sandbox {
 
+class Dispatcher;
 class SharedMemIPCServer;
 class Sid;
 class ThreadPool;
diff --git a/sandbox/win/src/target_services.cc b/sandbox/win/src/target_services.cc
index 23a29b6..0fdd54a 100644
--- a/sandbox/win/src/target_services.cc
+++ b/sandbox/win/src/target_services.cc
@@ -4,6 +4,9 @@
 
 #include "sandbox/win/src/target_services.h"
 
+#include <windows.h>
+#include <winsock2.h>
+
 #include <new>
 
 #include <process.h>
diff --git a/sandbox/win/src/threadpool.cc b/sandbox/win/src/threadpool.cc
index d4f9a554..ca5c653b 100644
--- a/sandbox/win/src/threadpool.cc
+++ b/sandbox/win/src/threadpool.cc
@@ -4,15 +4,16 @@
 
 #include "sandbox/win/src/threadpool.h"
 
+#include <windows.h>
+
 #include <stddef.h>
 
-#include "sandbox/win/src/win_utils.h"
+#include <vector>
 
 namespace sandbox {
 
-ThreadPool::ThreadPool() {
-  ::InitializeCriticalSection(&lock_);
-}
+ThreadPool::ThreadPool() = default;
+ThreadPool::~ThreadPool() = default;
 
 bool ThreadPool::RegisterWait(const void* cookie,
                               HANDLE waitable_object,
@@ -28,7 +29,7 @@
     return false;
   }
   PoolObject pool_obj = {cookie, pool_object};
-  AutoLock lock(&lock_);
+  base::AutoLock lock(lock_);
   pool_objects_.push_back(pool_obj);
   return true;
 }
@@ -39,7 +40,7 @@
   }
   std::vector<HANDLE> finished_waits;
   {
-    AutoLock lock(&lock_);
+    base::AutoLock lock(lock_);
     PoolObjects::iterator it = pool_objects_.begin();
     while (it != pool_objects_.end()) {
       if (it->cookie == cookie) {
@@ -59,15 +60,8 @@
 }
 
 size_t ThreadPool::OutstandingWaits() {
-  AutoLock lock(&lock_);
+  base::AutoLock lock(lock_);
   return pool_objects_.size();
 }
 
-ThreadPool::~ThreadPool() {
-  // Here we used to unregister all the pool wait handles. Now, following the
-  // rest of the code we avoid lengthy or blocking calls given that the process
-  // is being torn down.
-  ::DeleteCriticalSection(&lock_);
-}
-
 }  // namespace sandbox
diff --git a/sandbox/win/src/threadpool.h b/sandbox/win/src/threadpool.h
index 096eee17..47c9392 100644
--- a/sandbox/win/src/threadpool.h
+++ b/sandbox/win/src/threadpool.h
@@ -5,11 +5,9 @@
 #ifndef SANDBOX_WIN_SRC_THREADPOOL_H_
 #define SANDBOX_WIN_SRC_THREADPOOL_H_
 
-#include <stddef.h>
-
-#include <algorithm>
 #include <list>
-#include "sandbox/win/src/crosscall_server.h"
+#include "base/synchronization/lock.h"
+#include "base/win/windows_types.h"
 
 namespace sandbox {
 // This function signature is required as the callback when an IPC call fires.
@@ -80,7 +78,7 @@
   typedef std::list<PoolObject> PoolObjects;
   PoolObjects pool_objects_;
   // This lock protects the list of pool wait objects.
-  CRITICAL_SECTION lock_;
+  base::Lock lock_;
 };
 
 }  // namespace sandbox
diff --git a/sandbox/win/src/threadpool_unittest.cc b/sandbox/win/src/threadpool_unittest.cc
index 15cc3863..01086159 100644
--- a/sandbox/win/src/threadpool_unittest.cc
+++ b/sandbox/win/src/threadpool_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "sandbox/win/src/threadpool.h"
 
+#include <windows.h>
+
 #include <stdint.h>
 
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/sandbox/win/src/top_level_dispatcher.cc b/sandbox/win/src/top_level_dispatcher.cc
index 522f2f6..a751cbdf 100644
--- a/sandbox/win/src/top_level_dispatcher.cc
+++ b/sandbox/win/src/top_level_dispatcher.cc
@@ -21,7 +21,6 @@
 #include "sandbox/win/src/sandbox_policy_base.h"
 #include "sandbox/win/src/signed_dispatcher.h"
 #include "sandbox/win/src/socket_dispatcher.h"
-#include "sandbox/win/src/sync_dispatcher.h"
 
 namespace sandbox {
 
@@ -52,11 +51,6 @@
   ipc_targets_[static_cast<size_t>(IpcTag::CREATETHREAD)] = dispatcher;
   thread_process_dispatcher_.reset(dispatcher);
 
-  dispatcher = new SyncDispatcher(policy_);
-  ipc_targets_[static_cast<size_t>(IpcTag::CREATEEVENT)] = dispatcher;
-  ipc_targets_[static_cast<size_t>(IpcTag::OPENEVENT)] = dispatcher;
-  sync_dispatcher_.reset(dispatcher);
-
   dispatcher = new RegistryDispatcher(policy_);
   ipc_targets_[static_cast<size_t>(IpcTag::NTCREATEKEY)] = dispatcher;
   ipc_targets_[static_cast<size_t>(IpcTag::NTOPENKEY)] = dispatcher;
diff --git a/sandbox/win/src/top_level_dispatcher.h b/sandbox/win/src/top_level_dispatcher.h
index 5fbae1b4..988dc1c 100644
--- a/sandbox/win/src/top_level_dispatcher.h
+++ b/sandbox/win/src/top_level_dispatcher.h
@@ -41,7 +41,6 @@
   std::unique_ptr<Dispatcher> filesystem_dispatcher_;
   std::unique_ptr<Dispatcher> named_pipe_dispatcher_;
   std::unique_ptr<Dispatcher> thread_process_dispatcher_;
-  std::unique_ptr<Dispatcher> sync_dispatcher_;
   std::unique_ptr<Dispatcher> registry_dispatcher_;
   std::unique_ptr<Dispatcher> handle_dispatcher_;
   std::unique_ptr<Dispatcher> process_mitigations_win32k_dispatcher_;
diff --git a/sandbox/win/src/unload_dll_test.cc b/sandbox/win/src/unload_dll_test.cc
index 0acb178..c983243 100644
--- a/sandbox/win/src/unload_dll_test.cc
+++ b/sandbox/win/src/unload_dll_test.cc
@@ -32,13 +32,17 @@
   return rv;
 }
 
-// Opens an event passed as the first parameter of argv.
-SBOX_TESTS_COMMAND int SimpleOpenEvent(int argc, wchar_t** argv) {
+// Opens an HKLM registry key passed as the first parameter of argv.
+SBOX_TESTS_COMMAND int SimpleOpenKey(int argc, wchar_t** argv) {
   if (argc != 1)
     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
-
-  base::win::ScopedHandle event_open(::OpenEvent(SYNCHRONIZE, false, argv[0]));
-  return event_open.Get() ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED;
+  HKEY handle;
+  if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, argv[0], 0, KEY_ENUMERATE_SUB_KEYS,
+                     &handle)) {
+    return SBOX_TEST_FAILED;
+  }
+  ::CloseHandle(handle);
+  return SBOX_TEST_SUCCEEDED;
 }
 
 // Fails on Windows ARM64: https://crbug.com/905526
@@ -51,10 +55,11 @@
   TestRunner runner;
   runner.SetTestState(BEFORE_REVERT);
   runner.SetTimeout(2000);
-  // Add a sync rule, because that ensures that the interception agent has
+  // Add a registry rule, because that ensures that the interception agent has
   // more than one item in its internal table.
-  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
-                             TargetPolicy::EVENTS_ALLOW_ANY, L"t0001"));
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_ANY,
+                             L"HKEY_LOCAL_MACHINE\\Software\\Microsoft"));
 
   // Note for the puzzled: avicap32.dll is a 64-bit dll in 64-bit versions of
   // windows so this test and the others just work.
@@ -79,22 +84,21 @@
   sandbox::TargetPolicy* policy = runner.GetPolicy();
   policy->AddDllToUnload(L"avicap32.dll");
 
-  base::win::ScopedHandle handle1(
-      ::CreateEvent(nullptr, false, false, L"tst0001"));
-
   // Add a couple of rules that ensures that the interception agent add EAT
   // patching on the client which makes sure that the unload dll record does
   // not interact badly with them.
   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_READONLY,
+                             L"HKEY_LOCAL_MACHINE"));
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
                              TargetPolicy::REG_ALLOW_ANY,
                              L"HKEY_LOCAL_MACHINE\\Software\\Microsoft"));
-  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
-                             TargetPolicy::EVENTS_ALLOW_ANY, L"tst0001"));
 
   EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"UseOneDLL L avicap32.dll"));
 
   runner.SetTestState(AFTER_REVERT);
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"SimpleOpenEvent tst0001"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"SimpleOpenKey software\\microsoft"));
 }
 
 }  // namespace sandbox
diff --git a/sandbox/win/src/win_utils.h b/sandbox/win/src/win_utils.h
index e427a3b..8998853 100644
--- a/sandbox/win/src/win_utils.h
+++ b/sandbox/win/src/win_utils.h
@@ -5,13 +5,15 @@
 #ifndef SANDBOX_WIN_SRC_WIN_UTILS_H_
 #define SANDBOX_WIN_SRC_WIN_UTILS_H_
 
-#include <stddef.h>
 #include <windows.h>
+
+#include <stdlib.h>
+
 #include <memory>
 #include <string>
 
 #include "base/cxx17_backports.h"
-#include "sandbox/win/src/nt_internals.h"
+#include "base/win/windows_types.h"
 
 namespace sandbox {
 
@@ -22,27 +24,6 @@
 const wchar_t kNTDevicePrefix[] = L"\\Device\\";
 const size_t kNTDevicePrefixLen = base::size(kNTDevicePrefix) - 1;
 
-// Automatically acquires and releases a lock when the object is
-// is destroyed.
-class AutoLock {
- public:
-  AutoLock() = delete;
-
-  // Acquires the lock.
-  explicit AutoLock(CRITICAL_SECTION* lock) : lock_(lock) {
-    ::EnterCriticalSection(lock);
-  }
-
-  AutoLock(const AutoLock&) = delete;
-  AutoLock& operator=(const AutoLock&) = delete;
-
-  // Releases the lock;
-  ~AutoLock() { ::LeaveCriticalSection(lock_); }
-
- private:
-  CRITICAL_SECTION* lock_;
-};
-
 // Basic implementation of a singleton which calls the destructor
 // when the exe is shutting down or the DLL is being unloaded.
 template <typename Derived>
@@ -68,15 +49,6 @@
   }
 };
 
-// Function object which invokes LocalFree on its parameter, which must be
-// a pointer. Can be used to store LocalAlloc pointers in std::unique_ptr:
-//
-// std::unique_ptr<int, sandbox::LocalFreeDeleter> foo_ptr(
-//     static_cast<int*>(LocalAlloc(LMEM_FIXED, sizeof(int))));
-struct LocalFreeDeleter {
-  inline void operator()(void* ptr) const { ::LocalFree(ptr); }
-};
-
 // Convert a short path (C:\path~1 or \\??\\c:\path~1) to the long version of
 // the path. If the path is not a valid filesystem path, the function returns
 // false and argument is not modified.
diff --git a/sandbox/win/tests/integration_tests/integration_tests_test.cc b/sandbox/win/tests/integration_tests/integration_tests_test.cc
index 69933e11..7edb78b4 100644
--- a/sandbox/win/tests/integration_tests/integration_tests_test.cc
+++ b/sandbox/win/tests/integration_tests/integration_tests_test.cc
@@ -5,12 +5,14 @@
 // Some tests for the framework itself.
 
 #include <stddef.h>
+#include <stdlib.h>
 
 #include <windows.h>
 
 // Must be after windows.h.
 #include <versionhelpers.h>
 
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_timeouts.h"
 #include "base/unguessable_token.h"
@@ -25,11 +27,6 @@
 namespace sandbox {
 
 namespace {
-std::wstring NonCollidingName() {
-  auto token = base::UnguessableToken::Create();
-  return base::UTF8ToWide(token.ToString().c_str());
-}
-
 struct PolicyDiagnosticsWaiter {
  public:
   PolicyDiagnosticsWaiter() {
@@ -117,22 +114,21 @@
   return argc;
 }
 
-// Sets the first named event, then waits on the second. This ensures
+// Sets the first inherited event, then waits on the second. This ensures
 // this process is alive and remains alive while its parent tests diagnostics.
 SBOX_TESTS_COMMAND int IntegrationTestsTest_event(int argc, wchar_t** argv) {
   if (argc < 2)
     return SBOX_TEST_INVALID_PARAMETER;
 
-  HANDLE hEventA =
-      ::OpenEventW(SYNCHRONIZE | EVENT_MODIFY_STATE, false, argv[0]);
-  if (!hEventA)
+  base::win::ScopedHandle handle_started(
+      reinterpret_cast<HANDLE>(wcstoul(argv[0], nullptr, 16)));
+  if (!handle_started.IsValid())
     return SBOX_TEST_NOT_FOUND;
-  base::win::ScopedHandle handle_started(hEventA);
 
-  HANDLE hEventB = ::OpenEventW(SYNCHRONIZE, false, argv[1]);
-  if (!hEventB)
+  base::win::ScopedHandle handle_done(
+      reinterpret_cast<HANDLE>(wcstoul(argv[1], nullptr, 16)));
+  if (!handle_done.IsValid())
     return SBOX_TEST_NOT_FOUND;
-  base::win::ScopedHandle handle_done(hEventB);
 
   if (!::SetEvent(handle_started.Get()))
     return SBOX_TEST_FIRST_ERROR;
@@ -381,15 +377,8 @@
 // GetPolicyInfo validation
 TEST(IntegrationTestsTest, GetPolicyDiagnosticsReflectsActiveChildren) {
   TestRunner runner;
-  // Unique event names so tests can run in parallel.
-  auto name_a = NonCollidingName();
-  auto name_done = NonCollidingName();
 
   runner.SetAsynchronous(true);
-  runner.AddRule(TargetPolicy::SUBSYS_SYNC, TargetPolicy::EVENTS_ALLOW_ANY,
-                 name_a.c_str());
-  runner.AddRule(TargetPolicy::SUBSYS_SYNC, TargetPolicy::EVENTS_ALLOW_ANY,
-                 name_done.c_str());
 
   // This helper can be reused if it has finished waiting.
   auto waiter = std::make_unique<PolicyDiagnosticsWaiter>();
@@ -404,15 +393,15 @@
     ASSERT_EQ(policies->size(), 0U);
   }
 
-  HANDLE event_a = CreateEventW(nullptr, true, false, name_a.c_str());
-  base::win::ScopedHandle handle_started(event_a);
-  HANDLE event_done = CreateEventW(nullptr, true, false, name_done.c_str());
-  base::win::ScopedHandle handle_done(event_done);
+  base::win::ScopedHandle handle_started(
+      CreateEventW(nullptr, true, false, nullptr));
+  base::win::ScopedHandle handle_done(
+      CreateEventW(nullptr, true, false, nullptr));
 
-  auto cmd_line = std::wstring(L"IntegrationTestsTest_event ");
-  cmd_line += name_a;
-  cmd_line += L" ";
-  cmd_line += name_done;
+  runner.GetPolicy()->AddHandleToShare(handle_started.Get());
+  runner.GetPolicy()->AddHandleToShare(handle_done.Get());
+  auto cmd_line = base::StringPrintf(L"IntegrationTestsTest_event %p %p",
+                                     handle_started.Get(), handle_done.Get());
 
   ASSERT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd_line.c_str()));
   ASSERT_EQ(WAIT_OBJECT_0,
diff --git a/services/audio/stream_factory.cc b/services/audio/stream_factory.cc
index 9c10ab0..e9a50978 100644
--- a/services/audio/stream_factory.cc
+++ b/services/audio/stream_factory.cc
@@ -23,12 +23,23 @@
 
 const base::Feature kMixingForChromeWideAec{"MixingForChromeWideAec",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
+namespace {
+
+std::unique_ptr<OutputDeviceMixerManager> MaybeCreateOutputDeviceMixerManager(
+    media::AudioManager* audio_manager) {
+  if (!base::FeatureList::IsEnabled(kMixingForChromeWideAec))
+    return nullptr;
+
+  return std::make_unique<OutputDeviceMixerManager>(
+      audio_manager, base::BindRepeating(&OutputDeviceMixer::Create));
+}
+
+}  // namespace
 
 StreamFactory::StreamFactory(media::AudioManager* audio_manager)
     : audio_manager_(audio_manager),
       output_device_mixer_manager_(
-          audio_manager,
-          base::BindRepeating(&OutputDeviceMixer::Create)),
+          MaybeCreateOutputDeviceMixerManager(audio_manager)),
       loopback_worker_thread_("Loopback Worker") {}
 
 StreamFactory::~StreamFactory() {
@@ -118,10 +129,10 @@
   OutputStream::ManagedDeviceOutputStreamCreateCallback
       managed_device_output_stream_create_callback;
 
-  if (base::FeatureList::IsEnabled(kMixingForChromeWideAec)) {
-    managed_device_output_stream_create_callback =
-        base::BindRepeating(&OutputDeviceMixerManager::MakeOutputStream,
-                            base::Unretained(&output_device_mixer_manager_));
+  if (output_device_mixer_manager_) {
+    managed_device_output_stream_create_callback = base::BindRepeating(
+        &OutputDeviceMixerManager::MakeOutputStream,
+        base::Unretained(output_device_mixer_manager_.get()));
   }
 
   output_streams_.insert(std::make_unique<OutputStream>(
diff --git a/services/audio/stream_factory.h b/services/audio/stream_factory.h
index b0a4fdb..f871131 100644
--- a/services/audio/stream_factory.h
+++ b/services/audio/stream_factory.h
@@ -112,7 +112,7 @@
   ConcurrentStreamMetricReporter stream_count_metric_reporter_;
 
   // Order of the following members is important for a clean shutdown.
-  OutputDeviceMixerManager output_device_mixer_manager_;
+  const std::unique_ptr<OutputDeviceMixerManager> output_device_mixer_manager_;
   LoopbackCoordinator coordinator_;
   std::vector<std::unique_ptr<LocalMuter>> muters_;
   base::Thread loopback_worker_thread_;
diff --git a/services/device/device_service.cc b/services/device/device_service.cc
index b9ae467..68e0347 100644
--- a/services/device/device_service.cc
+++ b/services/device/device_service.cc
@@ -153,8 +153,16 @@
 #endif
 #if ((defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(USE_UDEV)) || \
     defined(OS_WIN) || defined(OS_MAC)
-  serial_port_manager_task_runner_->DeleteSoon(FROM_HERE,
-                                               std::move(serial_port_manager_));
+  auto* serial_port_manager = serial_port_manager_.release();
+  if (!serial_port_manager_task_runner_->DeleteSoon(FROM_HERE,
+                                                    serial_port_manager)) {
+    // The ThreadPool can be shutdown by the time ~DeviceService is triggered.
+    // Synchronously delete |serial_port_manager| in that event (which is
+    // naturally sequenced after the last task on
+    // |serial_port_manager_task_runner_| per ThreadPool shutdown semantics).
+    // See crbug.com/1263149#c20 for details.
+    delete serial_port_manager;
+  }
 #endif
 }
 
diff --git a/services/device/serial/bluetooth_serial_device_enumerator.cc b/services/device/serial/bluetooth_serial_device_enumerator.cc
index 3c534b7..792fc3cb 100644
--- a/services/device/serial/bluetooth_serial_device_enumerator.cc
+++ b/services/device/serial/bluetooth_serial_device_enumerator.cc
@@ -14,22 +14,47 @@
 
 namespace device {
 
-BluetoothSerialDeviceEnumerator::BluetoothSerialDeviceEnumerator() {
-  DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kEnableBluetoothSerialPortProfileInSerialApi));
-  device::BluetoothAdapterFactory::Get()->GetClassicAdapter(
-      base::BindOnce(&BluetoothSerialDeviceEnumerator::OnGotClassicAdapter,
-                     weak_ptr_factory_.GetWeakPtr()));
+// Helper class to interact with the BluetoothAdapter which must be accessed
+// on a specific sequence.
+class BluetoothSerialDeviceEnumerator::AdapterHelper
+    : public BluetoothAdapter::Observer {
+ public:
+  AdapterHelper(base::WeakPtr<BluetoothSerialDeviceEnumerator> enumerator,
+                scoped_refptr<base::SequencedTaskRunner> enumerator_runner);
+
+  void OnGotClassicAdapter(scoped_refptr<device::BluetoothAdapter> adapter);
+
+  // BluetoothAdapter::Observer methods:
+  void DeviceAdded(BluetoothAdapter* adapter, BluetoothDevice* device) override;
+  void DeviceRemoved(BluetoothAdapter* adapter,
+                     BluetoothDevice* device) override;
+
+ private:
+  // The enumerator that owns this instance.
+  base::WeakPtr<BluetoothSerialDeviceEnumerator> enumerator_;
+  scoped_refptr<base::SequencedTaskRunner> enumerator_runner_;
+  SEQUENCE_CHECKER(sequence_checker_);
+  base::WeakPtrFactory<AdapterHelper> weak_ptr_factory_{this};
+};
+
+BluetoothSerialDeviceEnumerator::AdapterHelper::AdapterHelper(
+    base::WeakPtr<BluetoothSerialDeviceEnumerator> enumerator,
+    scoped_refptr<base::SequencedTaskRunner> enumerator_runner)
+    : enumerator_(std::move(enumerator)),
+      enumerator_runner_(std::move(enumerator_runner)) {
+  device::BluetoothAdapterFactory::Get()->GetClassicAdapter(base::BindOnce(
+      &BluetoothSerialDeviceEnumerator::AdapterHelper::OnGotClassicAdapter,
+      weak_ptr_factory_.GetWeakPtr()));
 }
 
-BluetoothSerialDeviceEnumerator::~BluetoothSerialDeviceEnumerator() = default;
-
-void BluetoothSerialDeviceEnumerator::OnGotClassicAdapter(
+void BluetoothSerialDeviceEnumerator::AdapterHelper::OnGotClassicAdapter(
     scoped_refptr<device::BluetoothAdapter> adapter) {
+  SEQUENCE_CHECKER(sequence_checker_);
   DCHECK(adapter);
-  adapter_ = adapter;
-  adapter_->AddObserver(this);
-  BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
+  adapter->AddObserver(this);
+  std::unordered_map<std::string, base::UnguessableToken> device_ports;
+  BluetoothAdapter::DeviceList devices = adapter->GetDevices();
+  std::vector<mojom::SerialPortInfoPtr> ports;
   for (auto* device : devices) {
     BluetoothDevice::UUIDSet device_uuids = device->GetUUIDs();
     if (base::Contains(device_uuids, GetSerialPortProfileUUID())) {
@@ -37,32 +62,90 @@
       port->token = base::UnguessableToken::Create();
       port->path = base::FilePath::FromUTF8Unsafe(device->GetAddress());
       port->type = mojom::DeviceType::SPP_DEVICE;
-      bluetooth_ports_.insert(
-          std::make_pair(device->GetAddress(), port->token));
-      AddPort(std::move(port));
+      device_ports.insert(std::make_pair(device->GetAddress(), port->token));
+      ports.push_back(std::move(port));
     }
   }
+
+  enumerator_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&BluetoothSerialDeviceEnumerator::SetClassicAdapter,
+                     enumerator_, std::move(adapter), std::move(device_ports),
+                     std::move(ports)));
 }
 
-void BluetoothSerialDeviceEnumerator::DeviceAdded(BluetoothAdapter* adapter,
-                                                  BluetoothDevice* device) {
+void BluetoothSerialDeviceEnumerator::AdapterHelper::DeviceAdded(
+    BluetoothAdapter* adapter,
+    BluetoothDevice* device) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   BluetoothDevice::UUIDSet device_uuids = device->GetUUIDs();
-  if (base::Contains(device_uuids, GetSerialPortProfileUUID())) {
-    auto port = mojom::SerialPortInfo::New();
-    port->token = base::UnguessableToken::Create();
-    port->path = base::FilePath::FromUTF8Unsafe(device->GetAddress());
-    port->type = mojom::DeviceType::SPP_DEVICE;
-    bluetooth_ports_.insert(std::make_pair(device->GetAddress(), port->token));
+  if (!base::Contains(device_uuids, GetSerialPortProfileUUID()))
+    return;
+
+  auto port = mojom::SerialPortInfo::New();
+  port->token = base::UnguessableToken::Create();
+  port->path = base::FilePath::FromUTF8Unsafe(device->GetAddress());
+  port->type = mojom::DeviceType::SPP_DEVICE;
+  enumerator_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&BluetoothSerialDeviceEnumerator::PortAdded, enumerator_,
+                     device->GetAddress(), std::move(port)));
+}
+
+void BluetoothSerialDeviceEnumerator::AdapterHelper::DeviceRemoved(
+    BluetoothAdapter* adapter,
+    BluetoothDevice* device) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  enumerator_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&BluetoothSerialDeviceEnumerator::PortRemoved,
+                                enumerator_, device->GetAddress()));
+}
+
+BluetoothSerialDeviceEnumerator::BluetoothSerialDeviceEnumerator(
+    scoped_refptr<base::SingleThreadTaskRunner> adapter_runner) {
+  DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableBluetoothSerialPortProfileInSerialApi));
+
+  helper_ = base::SequenceBound<AdapterHelper>(
+      std::move(adapter_runner), weak_ptr_factory_.GetWeakPtr(),
+      base::SequencedTaskRunnerHandle::Get());
+}
+
+BluetoothSerialDeviceEnumerator::~BluetoothSerialDeviceEnumerator() = default;
+
+void BluetoothSerialDeviceEnumerator::SetClassicAdapter(
+    scoped_refptr<device::BluetoothAdapter> adapter,
+    std::unordered_map<std::string, base::UnguessableToken> device_ports,
+    std::vector<mojom::SerialPortInfoPtr> ports) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(adapter);
+  DCHECK(device_ports_.empty());
+  adapter_ = std::move(adapter);
+  device_ports_ = std::move(device_ports);
+  for (auto& port : ports) {
     AddPort(std::move(port));
   }
+  if (got_adapter_callback_) {
+    std::move(got_adapter_callback_).Run();
+  }
 }
 
-void BluetoothSerialDeviceEnumerator::DeviceRemoved(BluetoothAdapter* adapter,
-                                                    BluetoothDevice* device) {
-  auto it = bluetooth_ports_.find(device->GetAddress());
-  DCHECK(it != bluetooth_ports_.end());
+void BluetoothSerialDeviceEnumerator::PortAdded(
+    const std::string& device_address,
+    mojom::SerialPortInfoPtr port) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!base::Contains(device_ports_, device_address));
+  device_ports_.insert(std::make_pair(device_address, port->token));
+  AddPort(std::move(port));
+}
+
+void BluetoothSerialDeviceEnumerator::PortRemoved(
+    const std::string& device_address) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  auto it = device_ports_.find(device_address);
+  DCHECK(it != device_ports_.end());
   base::UnguessableToken token = it->second;
-  bluetooth_ports_.erase(it);
+  device_ports_.erase(it);
   RemovePort(token);
 }
 
@@ -73,11 +156,35 @@
 absl::optional<std::string>
 BluetoothSerialDeviceEnumerator::GetAddressFromToken(
     const base::UnguessableToken& token) {
-  for (const auto& entry : bluetooth_ports_) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  for (const auto& entry : device_ports_) {
     if (entry.second == token)
       return entry.first;
   }
   return absl::nullopt;
 }
 
+void BluetoothSerialDeviceEnumerator::OnGotAdapterForTesting(
+    base::OnceClosure closure) {
+  if (adapter_) {
+    std::move(closure).Run();
+    return;
+  }
+
+  DCHECK(!got_adapter_callback_);
+  got_adapter_callback_ = std::move(closure);
+}
+
+void BluetoothSerialDeviceEnumerator::DeviceAddedForTesting(
+    BluetoothAdapter* adapter,
+    BluetoothDevice* device) {
+  // Pass the device to our helper, which will in turn pass it back to me.
+  helper_.AsyncCall(&AdapterHelper::DeviceAdded)
+      .WithArgs(base::Unretained(adapter), device);
+}
+
+void BluetoothSerialDeviceEnumerator::SynchronouslyResetHelperForTesting() {
+  helper_.SynchronouslyResetForTest();  // IN-TEST
+}
+
 }  // namespace device
diff --git a/services/device/serial/bluetooth_serial_device_enumerator.h b/services/device/serial/bluetooth_serial_device_enumerator.h
index 5a7b63f..c3650d6 100644
--- a/services/device/serial/bluetooth_serial_device_enumerator.h
+++ b/services/device/serial/bluetooth_serial_device_enumerator.h
@@ -6,29 +6,34 @@
 #define SERVICES_DEVICE_SERIAL_BLUETOOTH_SERIAL_DEVICE_ENUMERATOR_H_
 
 #include <map>
+#include <unordered_map>
+#include <vector>
 
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/threading/sequence_bound.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "services/device/public/mojom/serial.mojom-forward.h"
 #include "services/device/serial/serial_device_enumerator.h"
 
 namespace device {
 
-class BluetoothSerialDeviceEnumerator : public BluetoothAdapter::Observer,
-                                        public SerialDeviceEnumerator {
+class BluetoothSerialDeviceEnumerator : public SerialDeviceEnumerator {
  public:
-  BluetoothSerialDeviceEnumerator();
+  // `adapter_runner` is the task runner with which to access the Bluetooth
+  // adapter.
+  explicit BluetoothSerialDeviceEnumerator(
+      scoped_refptr<base::SingleThreadTaskRunner> adapter_runner);
   BluetoothSerialDeviceEnumerator(const BluetoothSerialDeviceEnumerator&) =
       delete;
   BluetoothSerialDeviceEnumerator& operator=(
       const BluetoothSerialDeviceEnumerator&) = delete;
   ~BluetoothSerialDeviceEnumerator() override;
 
-  // BluetoothAdapter::Observer methods:
-  void DeviceAdded(BluetoothAdapter* adapter, BluetoothDevice* device) override;
-  void DeviceRemoved(BluetoothAdapter* adapter,
-                     BluetoothDevice* device) override;
+  void PortAdded(const std::string& device_address,
+                 mojom::SerialPortInfoPtr port);
+  void PortRemoved(const std::string& device_address);
 
   scoped_refptr<BluetoothAdapter> GetAdapter();
 
@@ -37,14 +42,28 @@
   absl::optional<std::string> GetAddressFromToken(
       const base::UnguessableToken& token);
 
- protected:
-  scoped_refptr<BluetoothAdapter> adapter_;
+  void OnGotAdapterForTesting(base::OnceClosure closure);
+  void DeviceAddedForTesting(BluetoothAdapter* adapter,
+                             BluetoothDevice* device);
+  void SynchronouslyResetHelperForTesting();
 
  private:
-  void OnGotClassicAdapter(scoped_refptr<device::BluetoothAdapter> adapter);
+  class AdapterHelper;
 
-  std::unordered_map<std::string, base::UnguessableToken> bluetooth_ports_;
+  // Map BluetoothDevice address to Port token.
+  using DevicePortsMap =
+      std::unordered_map<std::string, base::UnguessableToken>;
 
+  void SetClassicAdapter(
+      scoped_refptr<device::BluetoothAdapter> adapter,
+      std::unordered_map<std::string, base::UnguessableToken> device_ports,
+      std::vector<mojom::SerialPortInfoPtr> ports);
+
+  base::OnceClosure got_adapter_callback_;
+  scoped_refptr<BluetoothAdapter> adapter_;
+  DevicePortsMap device_ports_;
+  base::SequenceBound<AdapterHelper> helper_;
+  SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<BluetoothSerialDeviceEnumerator> weak_ptr_factory_{this};
 };
 
diff --git a/services/device/serial/serial_port_manager_impl.cc b/services/device/serial/serial_port_manager_impl.cc
index 43118cfe..5a14054 100644
--- a/services/device/serial/serial_port_manager_impl.cc
+++ b/services/device/serial/serial_port_manager_impl.cc
@@ -74,7 +74,7 @@
           switches::kEnableBluetoothSerialPortProfileInSerialApi)) {
     if (!bluetooth_enumerator_) {
       bluetooth_enumerator_ =
-          std::make_unique<BluetoothSerialDeviceEnumerator>();
+          std::make_unique<BluetoothSerialDeviceEnumerator>(ui_task_runner_);
       observed_enumerator_.AddObservation(bluetooth_enumerator_.get());
     }
     auto bluetooth_devices = bluetooth_enumerator_->GetDevices();
@@ -113,7 +113,7 @@
           switches::kEnableBluetoothSerialPortProfileInSerialApi)) {
     if (!bluetooth_enumerator_) {
       bluetooth_enumerator_ =
-          std::make_unique<BluetoothSerialDeviceEnumerator>();
+          std::make_unique<BluetoothSerialDeviceEnumerator>(ui_task_runner_);
       observed_enumerator_.AddObservation(bluetooth_enumerator_.get());
     }
     absl::optional<std::string> address =
diff --git a/services/device/serial/serial_port_manager_impl_unittest.cc b/services/device/serial/serial_port_manager_impl_unittest.cc
index 42145027..1059540 100644
--- a/services/device/serial/serial_port_manager_impl_unittest.cc
+++ b/services/device/serial/serial_port_manager_impl_unittest.cc
@@ -98,6 +98,17 @@
 
   ~SerialPortManagerImplTest() override = default;
 
+  void TearDown() override {
+    // Resetting `manager_` will delete the BluetoothSerialDeviceEnumerator
+    // which will enqueue the deletion of a `SequenceBound` helper.
+    manager_.reset();
+    // Wait for any `SequenceBound` objects have been destroyed
+    // to avoid tripping leak detection.
+    base::RunLoop run_loop;
+    adapter_task_runner()->PostTask(FROM_HERE, run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
   // Since not all functions need to use a MockBluetoothAdapter, this function
   // is called at the beginning of test cases that do require a
   // MockBluetoothAdapter.
@@ -116,11 +127,16 @@
     adapter_->AddMockDevice(std::move(mock_device));
 
     auto bluetooth_enumerator =
-        std::make_unique<BluetoothSerialDeviceEnumerator>();
+        std::make_unique<BluetoothSerialDeviceEnumerator>(
+            adapter_task_runner());
     bluetooth_enumerator_ = bluetooth_enumerator.get();
 
     manager_->SetBluetoothSerialEnumeratorForTesting(
         std::move(bluetooth_enumerator));
+
+    base::RunLoop run_loop;
+    bluetooth_enumerator_->OnGotAdapterForTesting(run_loop.QuitClosure());
+    run_loop.Run();
   }
 
   void SetupBluetoothEnumeratorWithExpectations() {
@@ -145,14 +161,23 @@
         .WillOnce(RunOnceCallback<1>(mock_socket_));
 
     auto bluetooth_enumerator =
-        std::make_unique<BluetoothSerialDeviceEnumerator>();
+        std::make_unique<BluetoothSerialDeviceEnumerator>(
+            adapter_task_runner());
     bluetooth_enumerator_ = bluetooth_enumerator.get();
 
     manager_->SetBluetoothSerialEnumeratorForTesting(
         std::move(bluetooth_enumerator));
+
+    base::RunLoop run_loop;
+    bluetooth_enumerator_->OnGotAdapterForTesting(run_loop.QuitClosure());
+    run_loop.Run();
   }
 
  protected:
+  scoped_refptr<base::SingleThreadTaskRunner> adapter_task_runner() {
+    return base::ThreadTaskRunnerHandle::Get();
+  }
+
   FakeSerialEnumerator* enumerator_;
   BluetoothSerialDeviceEnumerator* bluetooth_enumerator_;
   scoped_refptr<MockBluetoothAdapter> adapter_ =
@@ -346,8 +371,7 @@
   }
   ASSERT_FALSE(port1_token.is_empty());
 
-  bluetooth_enumerator_->DeviceRemoved(
-      adapter_.get(), adapter_->RemoveMockDevice(kDeviceAddress).get());
+  bluetooth_enumerator_->PortRemoved(kDeviceAddress);
   {
     base::RunLoop run_loop;
     EXPECT_CALL(client, OnPortRemoved(_))
@@ -367,7 +391,7 @@
   MockBluetoothDevice* mock_device_ptr = mock_device.get();
   adapter_->AddMockDevice(std::move(mock_device));
 
-  bluetooth_enumerator_->DeviceAdded(adapter_.get(), mock_device_ptr);
+  bluetooth_enumerator_->DeviceAddedForTesting(adapter_.get(), mock_device_ptr);
   {
     base::RunLoop run_loop;
     EXPECT_CALL(client, OnPortAdded(_))
@@ -396,9 +420,14 @@
 
   // Create the enumerator, which calls GetAdapter(), which is blocked waiting
   // on adapter initialization.
-  auto enumerator = std::make_unique<BluetoothSerialDeviceEnumerator>();
+  auto enumerator =
+      std::make_unique<BluetoothSerialDeviceEnumerator>(adapter_task_runner());
 
   // Delete the enumerator before adapter initialization completes.
+  // Explicitly delete its helper. This workaround is needed because this test
+  // does not mock out the BluetoothAdapterFactory singleton, which (on Linux)
+  // calls bluez::BluezDBusManager::Get() - failing a CHECK.
+  enumerator->SynchronouslyResetHelperForTesting();
   enumerator.reset();
 
   // Directly call the adapter initialization callback, which calls any saved
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index 9be97b7..480af24 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -224,6 +224,29 @@
   return absl::nullopt;
 }
 
+// Computes the policy to use, given the factory and request-specific policies.
+absl::optional<mojom::PrivateNetworkRequestPolicy>
+CombinePrivateNetworkRequestPolicies(
+    absl::optional<mojom::PrivateNetworkRequestPolicy> factory_policy,
+    const ResourceRequest& request) {
+  if (factory_policy.has_value()) {
+    return factory_policy;
+  }
+
+  if (request.trusted_params && request.trusted_params->client_security_state) {
+    return request.trusted_params->client_security_state
+        ->private_network_request_policy;
+  }
+
+  return absl::nullopt;
+}
+
+bool ShouldIgnorePrivateNetworkAccessErrors(
+    absl::optional<mojom::PrivateNetworkRequestPolicy> policy) {
+  return policy &&
+         *policy == mojom::PrivateNetworkRequestPolicy::kPreflightWarn;
+}
+
 constexpr const char kTimingAllowOrigin[] = "Timing-Allow-Origin";
 }  // namespace
 
@@ -246,7 +269,9 @@
     bool allow_any_cors_exempt_header,
     NonWildcardRequestHeadersSupport non_wildcard_request_headers_support,
     const net::IsolationInfo& isolation_info,
-    mojo::PendingRemote<mojom::DevToolsObserver> devtools_observer)
+    mojo::PendingRemote<mojom::DevToolsObserver> devtools_observer,
+    absl::optional<mojom::PrivateNetworkRequestPolicy>
+        factory_private_network_request_policy)
     : receiver_(this, std::move(loader_receiver)),
       process_id_(process_id),
       request_id_(request_id),
@@ -265,6 +290,11 @@
       non_wildcard_request_headers_support_(
           non_wildcard_request_headers_support),
       isolation_info_(isolation_info),
+      should_ignore_private_network_access_errors_(
+          ShouldIgnorePrivateNetworkAccessErrors(
+              CombinePrivateNetworkRequestPolicies(
+                  factory_private_network_request_policy,
+                  request_))),
       devtools_observer_(std::move(devtools_observer)),
       // CORS preflight related events are logged in a series of URL_REQUEST
       // logs.
@@ -718,8 +748,10 @@
       request_,
       PreflightController::WithTrustedHeaderClient(
           options_ & mojom::kURLLoadOptionUseHeaderClient),
-      non_wildcard_request_headers_support_, tainted_,
-      net::NetworkTrafficAnnotationTag(traffic_annotation_),
+      non_wildcard_request_headers_support_,
+      PreflightController::EnforcePrivateNetworkAccessHeader(
+          !should_ignore_private_network_access_errors_),
+      tainted_, net::NetworkTrafficAnnotationTag(traffic_annotation_),
       network_loader_factory_, isolation_info_, std::move(devtools_observer),
       net_log_);
 }
@@ -731,12 +763,13 @@
   has_authorization_covered_by_wildcard_ =
       has_authorization_covered_by_wildcard;
 
-  if (net_error != net::OK) {
+  if (net_error == net::OK) {
+    DCHECK(!status) << *status;
+  } else if (!should_ignore_preflight_errors_) {
     HandleComplete(status.has_value() ? URLLoaderCompletionStatus(*status)
                                       : URLLoaderCompletionStatus(net_error));
     return;
   }
-  DCHECK(!status) << *status;
 
   StartNetworkRequest();
 }
@@ -797,6 +830,17 @@
           mojom::CorsError::kUnexpectedPrivateNetworkAccess) {
     DCHECK(status.cors_error_status->resource_address_space !=
            mojom::IPAddressSpace::kUnknown);
+
+    // If we only send a preflight because of Private Network Access, and we are
+    // configured to ignore errors caused by Private Network Access, then we
+    // should ignore any preflight error, as if we had never sent the preflight.
+    // Otherwise, if we had sent a preflight before we noticed the private
+    // network access, then we rely on `PreflightController` to ignore
+    // PNA-specific preflight errors during this second preflight request.
+    should_ignore_preflight_errors_ =
+        should_ignore_private_network_access_errors_ &&
+        !NeedsPreflight(request_).has_value();
+
     network_client_receiver_.reset();
     request_.target_ip_address_space =
         status.cors_error_status->resource_address_space;
diff --git a/services/network/cors/cors_url_loader.h b/services/network/cors/cors_url_loader.h
index 769cce1..2df5c91 100644
--- a/services/network/cors/cors_url_loader.h
+++ b/services/network/cors/cors_url_loader.h
@@ -14,6 +14,7 @@
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/cors/preflight_controller.h"
 #include "services/network/public/cpp/cors/cors_error_status.h"
+#include "services/network/public/mojom/client_security_state.mojom.h"
 #include "services/network/public/mojom/devtools_observer.mojom.h"
 #include "services/network/public/mojom/fetch_api.mojom.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
@@ -60,7 +61,9 @@
       bool allow_any_cors_exempt_header,
       NonWildcardRequestHeadersSupport non_wildcard_request_headers_support,
       const net::IsolationInfo& isolation_info,
-      mojo::PendingRemote<mojom::DevToolsObserver> devtools_observer);
+      mojo::PendingRemote<mojom::DevToolsObserver> devtools_observer,
+      absl::optional<mojom::PrivateNetworkRequestPolicy>
+          factory_private_network_request_policy);
 
   CorsURLLoader(const CorsURLLoader&) = delete;
   CorsURLLoader& operator=(const CorsURLLoader&) = delete;
@@ -213,8 +216,34 @@
 
   net::IsolationInfo isolation_info_;
 
+  // If set to true, then preflight errors due exclusively to Private Network
+  // Access checks are ignored. This is used to soft-launch Private Betwork
+  // Access preflights: we send preflights but do not require them to succeed.
+  //
+  // NOTE: A default value is set here in order to avoid any risk of undefined
+  // behavior, but it should never be used since the constructor always
+  // initializes this member explicitly.
+  //
+  // TODO(https://crbug.com/1268378): Remove this once it is never set to true.
+  const bool should_ignore_private_network_access_errors_ = false;
+
   bool has_authorization_covered_by_wildcard_ = false;
 
+  // If set to true, then any and all errors raised by subsequent preflight
+  // requests are ignored.
+  //
+  // This is used to soft-launch Private Network Access preflights. In some
+  // cases, the only reason we send a preflight is because of Private Network
+  // Access. Errors that arise then would never have been noticed if we had not
+  // sent the preflight, so we ignore them all.
+  //
+  // INVARIANT: if this is true, then
+  // `should_ignore_private_network_access_errors_` is also true.
+  //
+  // TODO(https://crbug.com/1268378): Remove this along with
+  // `should_ignore_private_network_access_errors_`.
+  bool should_ignore_preflight_errors_ = false;
+
   mojo::Remote<mojom::DevToolsObserver> devtools_observer_;
 
   net::NetLogWithSource net_log_;
diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc
index 7d49614..e7d8db0c 100644
--- a/services/network/cors/cors_url_loader_factory.cc
+++ b/services/network/cors/cors_url_loader_factory.cc
@@ -82,6 +82,16 @@
   return true;
 }
 
+// Glorified ternary operator, only defined to appease the compiler.
+absl::optional<mojom::PrivateNetworkRequestPolicy>
+GetPrivateNetworkRequestPolicy(const mojom::URLLoaderFactoryParams& params) {
+  if (!params.client_security_state) {
+    return absl::nullopt;
+  }
+
+  return params.client_security_state->private_network_request_policy;
+}
+
 }  // namespace
 
 class CorsURLLoaderFactory::FactoryOverride final {
@@ -178,6 +188,7 @@
               ? params->client_security_state->cross_origin_embedder_policy
               : CrossOriginEmbedderPolicy()),
       coep_reporter_(std::move(params->coep_reporter)),
+      private_network_request_policy_(GetPrivateNetworkRequestPolicy(*params)),
       origin_access_list_(origin_access_list) {
   DCHECK(context_);
   DCHECK(origin_access_list_);
@@ -294,7 +305,7 @@
         context_->cors_exempt_header_list(),
         GetAllowAnyCorsExemptHeaderForBrowser(),
         context_->cors_non_wildcard_request_headers_support(), isolation_info_,
-        std::move(devtools_observer));
+        std::move(devtools_observer), private_network_request_policy_);
     auto* raw_loader = loader.get();
     OnLoaderCreated(std::move(loader));
     raw_loader->Start();
diff --git a/services/network/cors/cors_url_loader_factory.h b/services/network/cors/cors_url_loader_factory.h
index 096415a0..cc015d9 100644
--- a/services/network/cors/cors_url_loader_factory.h
+++ b/services/network/cors/cors_url_loader_factory.h
@@ -17,8 +17,10 @@
 #include "services/network/public/cpp/cors/origin_access_list.h"
 #include "services/network/public/cpp/cross_origin_embedder_policy.h"
 #include "services/network/public/cpp/initiator_lock_compatibility.h"
+#include "services/network/public/mojom/client_security_state.mojom.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace network {
 
@@ -121,6 +123,8 @@
   const std::string debug_tag_;
   const CrossOriginEmbedderPolicy cross_origin_embedder_policy_;
   mojo::Remote<mojom::CrossOriginEmbedderPolicyReporter> coep_reporter_;
+  const absl::optional<mojom::PrivateNetworkRequestPolicy>
+      private_network_request_policy_;
 
   // Relative order of |network_loader_factory_| and |loaders_| matters -
   // URLLoaderFactory needs to live longer than URLLoaders created using the
diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc
index bccda3b..9d750cc 100644
--- a/services/network/cors/cors_url_loader_unittest.cc
+++ b/services/network/cors/cors_url_loader_unittest.cc
@@ -174,6 +174,31 @@
   base::WeakPtrFactory<TestURLLoaderFactory> weak_factory_{this};
 };
 
+// Optional parameters for ResetFactory().
+struct ResetFactoryParams {
+  // Sets each member to the default value of the corresponding mojom member.
+  ResetFactoryParams();
+
+  // Members of `mojom::URLLoaderFactoryParams`.
+  bool is_trusted;
+  bool ignore_isolated_world_origin;
+  mojom::ClientSecurityStatePtr client_security_state;
+
+  // Member of `mojom::URLLoaderFactoryOverride`.
+  bool skip_cors_enabled_scheme_check;
+};
+
+ResetFactoryParams::ResetFactoryParams() {
+  mojom::URLLoaderFactoryParams params;
+  is_trusted = params.is_trusted;
+  ignore_isolated_world_origin = params.ignore_isolated_world_origin;
+  client_security_state = std::move(params.client_security_state);
+
+  mojom::URLLoaderFactoryOverride factory_override;
+  skip_cors_enabled_scheme_check =
+      factory_override.skip_cors_enabled_scheme_check;
+}
+
 class CorsURLLoaderTest : public testing::Test {
  public:
   using ReferrerPolicy = net::ReferrerPolicy;
@@ -389,9 +414,7 @@
 
   void ResetFactory(absl::optional<url::Origin> initiator,
                     uint32_t process_id,
-                    bool is_trusted,
-                    bool ignore_isolated_world_origin,
-                    bool skip_cors_enabled_scheme_check) {
+                    const ResetFactoryParams& params = ResetFactoryParams()) {
     if (process_id != mojom::kBrowserProcessId)
       DCHECK(initiator.has_value());
 
@@ -404,15 +427,18 @@
     if (initiator) {
       factory_params->request_initiator_origin_lock = *initiator;
     }
-    factory_params->is_trusted = is_trusted;
+    factory_params->is_trusted = params.is_trusted;
     factory_params->process_id = process_id;
     factory_params->is_corb_enabled = (process_id != mojom::kBrowserProcessId);
-    factory_params->ignore_isolated_world_origin = ignore_isolated_world_origin;
+    factory_params->ignore_isolated_world_origin =
+        params.ignore_isolated_world_origin;
     factory_params->factory_override = mojom::URLLoaderFactoryOverride::New();
     factory_params->factory_override->overriding_factory =
         test_url_loader_factory_receiver_->BindNewPipeAndPassRemote();
     factory_params->factory_override->skip_cors_enabled_scheme_check =
-        skip_cors_enabled_scheme_check;
+        params.skip_cors_enabled_scheme_check;
+    factory_params->client_security_state =
+        params.client_security_state.Clone();
     auto resource_scheduler_client =
         base::MakeRefCounted<ResourceSchedulerClient>(
             process_id, ++last_issued_route_id, &resource_scheduler_,
@@ -425,14 +451,6 @@
         &origin_access_list_);
   }
 
-  void ResetFactory(absl::optional<url::Origin> initiator,
-                    uint32_t process_id) {
-    auto params = network::mojom::URLLoaderFactoryParams::New();
-    ResetFactory(initiator, process_id, params->is_trusted,
-                 params->ignore_isolated_world_origin,
-                 false /* skip_cors_enabled_scheme_check */);
-  }
-
   NetworkContext* network_context() { return network_context_.get(); }
 
   void set_devtools_observer_for_next_request(MockDevToolsObserver* observer) {
@@ -931,10 +949,10 @@
             client().completion_status().cors_error_status->cors_error);
 
   // Scheme check can be skipped via the factory params.
-  auto params = network::mojom::URLLoaderFactoryParams::New();
+  ResetFactoryParams factory_params;
+  factory_params.skip_cors_enabled_scheme_check = true;
   ResetFactory(url::Origin::Create(origin), mojom::kBrowserProcessId,
-               params->is_trusted, params->ignore_isolated_world_origin,
-               true /* skip_cors_enabled_scheme_check */);
+               factory_params);
 
   // "Access-Control-Allow-Origin: *" accepts the custom scheme.
   CreateLoaderAndStart(origin, url, mojom::RequestMode::kCors);
@@ -1414,10 +1432,9 @@
   const net::SiteForCookies new_url_site_for_cookies =
       net::SiteForCookies::FromOrigin(new_url_origin);
 
-  auto params = network::mojom::URLLoaderFactoryParams::New();
-  ResetFactory(url_origin, kRendererProcessId, true /* is_trusted */,
-               params->ignore_isolated_world_origin,
-               false /* skip_cors_enabled_scheme_check */);
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(url_origin, kRendererProcessId, factory_params);
 
   ResourceRequest request;
   request.mode = mojom::RequestMode::kCors;
@@ -1637,9 +1654,9 @@
       url::Origin::Create(GURL("http://isolated-world.example.com"));
   const GURL url("http://other.example.com/foo.png");
 
-  ResetFactory(main_world_origin, kRendererProcessId, false /* trusted */,
-               false /* ignore_isolated_world_origin */,
-               false /* skip_cors_enabled_scheme_check */);
+  ResetFactoryParams factory_params;
+  factory_params.ignore_isolated_world_origin = false;
+  ResetFactory(main_world_origin, kRendererProcessId, factory_params);
 
   AddAllowListEntryForOrigin(isolated_world_origin, url.scheme(), url.host(),
                              mojom::CorsDomainMatchMode::kDisallowSubdomains);
@@ -1681,9 +1698,9 @@
   // in CorsURLLoader::OnReceiveRedirect.
   const GURL new_url("http://other.example.com/bar.png");
 
-  ResetFactory(main_world_origin, kRendererProcessId, false /* trusted */,
-               false /* ignore_isolated_world_origin */,
-               false /* skip_cors_enabled_scheme_check */);
+  ResetFactoryParams factory_params;
+  factory_params.ignore_isolated_world_origin = false;
+  ResetFactory(main_world_origin, kRendererProcessId, factory_params);
 
   AddAllowListEntryForOrigin(isolated_world_origin, url.scheme(), url.host(),
                              mojom::CorsDomainMatchMode::kDisallowSubdomains);
@@ -1735,9 +1752,7 @@
       url::Origin::Create(GURL("http://isolated-world.example.com"));
   const GURL url("http://other.example.com/foo.png");
 
-  ResetFactory(main_world_origin, kRendererProcessId, false /* trusted */,
-               true /* ignore_isolated_world_origin */,
-               false /* skip_cors_enabled_scheme_check */);
+  ResetFactory(main_world_origin, kRendererProcessId);
 
   AddAllowListEntryForOrigin(isolated_world_origin, url.scheme(), url.host(),
                              mojom::CorsDomainMatchMode::kDisallowSubdomains);
@@ -2330,10 +2345,9 @@
   // Run the test with a trusted URLLoaderFactory as well, to make sure a CORS
   // request is in fact made when using a trusted factory.
   for (bool is_trusted : {false, true}) {
-    bool ignore_isolated_world_origin = true;  // This is the default.
-    ResetFactory(initiator, kRendererProcessId, is_trusted,
-                 ignore_isolated_world_origin,
-                 false /* skip_cors_enabled_scheme_check */);
+    ResetFactoryParams factory_params;
+    factory_params.is_trusted = is_trusted;
+    ResetFactory(initiator, kRendererProcessId, factory_params);
 
     BadMessageTestHelper bad_message_helper;
 
@@ -2381,9 +2395,9 @@
 TEST_F(CorsURLLoaderTest, RestrictedPrefetchSucceedsWithNIK) {
   url::Origin initiator = url::Origin::Create(GURL("https://example.com"));
 
-  ResetFactory(initiator, kRendererProcessId, true /* is_trusted */,
-               true /* ignore_isolated_world_origin */,
-               false /* skip_cors_enabled_scheme_check */);
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator, kRendererProcessId, factory_params);
 
   BadMessageTestHelper bad_message_helper;
 
@@ -2424,9 +2438,10 @@
 // make use of their TrustedParams' |isolation_info|.
 TEST_F(CorsURLLoaderTest, RestrictedPrefetchFailsWithoutNIK) {
   url::Origin initiator = url::Origin::Create(GURL("https://example.com"));
-  ResetFactory(initiator, kRendererProcessId, true /* is_trusted */,
-               true /* ignore_isolated_world_origin */,
-               false /* skip_cors_enabled_scheme_check */);
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator, kRendererProcessId, factory_params);
 
   BadMessageTestHelper bad_message_helper;
 
@@ -2626,9 +2641,11 @@
 TEST_F(CorsURLLoaderTest, DevToolsObserverOnCorsErrorCallback) {
   const GURL origin("https://example.com");
   const url::Origin initiator_origin = url::Origin::Create(origin);
-  ResetFactory(initiator_origin, kRendererProcessId, true /* is_trusted */,
-               true /* ignore_isolated_world_origin */,
-               false /* skip_cors_enabled_scheme_check */);
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
   const GURL url("http://other.example.com/foo.png");
   MockDevToolsObserver devtools_observer;
   set_devtools_observer_for_next_request(&devtools_observer);
@@ -3395,6 +3412,597 @@
   EXPECT_EQ(GetRequest().method, "OPTIONS");
 }
 
+mojom::ClientSecurityStatePtr
+MakeClientSecurityStateWithPrivateNetworkRequestPolicy(
+    mojom::PrivateNetworkRequestPolicy policy) {
+  auto state = mojom::ClientSecurityState::New();
+  state->private_network_request_policy = policy;
+  return state;
+}
+
+ResourceRequest::TrustedParams MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+    mojom::PrivateNetworkRequestPolicy policy) {
+  ResourceRequest::TrustedParams params;
+  params.client_security_state =
+      MakeClientSecurityStateWithPrivateNetworkRequestPolicy(policy);
+  return params;
+}
+
+// The following `PrivateNetworkAccessPolicyWarn*` tests verify the correct
+// functioning of the `kPreflightWarn` private network request policy. That is,
+// preflight errors caused exclusively by Private Network Access logic should
+// be ignored.
+//
+// The `*PolicyWarnSimple*` variants test what happens in the "simple request"
+// case, when a preflight would not have been sent were it not for Private
+// Network Access. The `*PolicyWarnPreflight*` variants test what happens when
+// a preflight was attempted before noticing the private network access.
+//
+// TODO(https://crbug.com/1268378): Remove these tests once the policy is never
+// set to `kPreflightWarn` anymore.
+
+// This test verifies that when:
+//
+//  - the private network request policy is set to `kPreflightWarn`
+//  - a simple request detects a private network request
+//  - the following PNA preflight fails due to a network error
+//
+// ... the error is ignored and the request proceeds.
+TEST_F(CorsURLLoaderTest, PrivateNetworkAccessPolicyWarnSimpleNetError) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "GET";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+  request.trusted_params = MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+      mojom::PrivateNetworkRequestPolicy::kPreflightWarn);
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(net::ERR_INVALID_ARGUMENT);
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnReceiveResponse();
+  NotifyLoaderClientOnComplete(net::OK);
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::OK);
+}
+
+// This test verifies that when:
+//
+//  - the private network request policy is set to `kPreflightWarn`
+//  - a simple request detects a private network request
+//  - the following PNA preflight fails due to a non-PNA CORS error
+//
+// ... the error is ignored and the request proceeds.
+TEST_F(CorsURLLoaderTest, PrivateNetworkAccessPolicyWarnSimpleCorsError) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "GET";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+  request.trusted_params = MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+      mojom::PrivateNetworkRequestPolicy::kPreflightWarn);
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(
+      CorsErrorStatus(mojom::CorsError::kMissingAllowOriginHeader));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnReceiveResponse();
+  NotifyLoaderClientOnComplete(net::OK);
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::OK);
+}
+
+// This test verifies that when:
+//
+//  - the private network request policy is set to `kPreflightWarn`
+//  - a simple request detects a private network request
+//  - the following PNA preflight fails due to a missing PNA header
+//
+// ... the error is ignored and the request proceeds.
+TEST_F(CorsURLLoaderTest,
+       PrivateNetworkAccessPolicyWarnSimpleMissingAllowPrivateNetwork) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "GET";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+  request.trusted_params = MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+      mojom::PrivateNetworkRequestPolicy::kPreflightWarn);
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnReceiveResponse({
+      {"Access-Control-Allow-Methods", "GET"},
+      {"Access-Control-Allow-Origin", "https://example.com"},
+      {"Access-Control-Allow-Credentials", "true"},
+  });
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnReceiveResponse();
+  NotifyLoaderClientOnComplete(net::OK);
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::OK);
+}
+
+// This test verifies that when:
+//
+//  - the private network request policy is set to `kPreflightWarn`
+//  - a simple request detects a private network request
+//  - the following PNA preflight fails due to an invalid PNA header
+//
+// ... the error is ignored and the request proceeds.
+TEST_F(CorsURLLoaderTest,
+       PrivateNetworkAccessPolicyWarnSimpleInvalidAllowPrivateNetwork) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "GET";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+  request.trusted_params = MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+      mojom::PrivateNetworkRequestPolicy::kPreflightWarn);
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnReceiveResponse({
+      {"Access-Control-Allow-Methods", "GET"},
+      {"Access-Control-Allow-Origin", "https://example.com"},
+      {"Access-Control-Allow-Credentials", "true"},
+      {"Access-Control-Allow-Private-Network", "invalid-value"},
+  });
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnReceiveResponse();
+  NotifyLoaderClientOnComplete(net::OK);
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::OK);
+}
+
+// This test verifies that when:
+//
+//  - the private network request policy is set to `kPreflightWarn`
+//  - a CORS preflight request detects a private network request
+//  - the following PNA preflight fails due to a network error
+//
+// ... the error is not ignored and the request is failed.
+TEST_F(CorsURLLoaderTest, PrivateNetworkAccessPolicyWarnPreflightNetError) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "PUT";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+  request.trusted_params = MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+      mojom::PrivateNetworkRequestPolicy::kPreflightWarn);
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(net::ERR_INVALID_ARGUMENT);
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::ERR_INVALID_ARGUMENT);
+}
+
+// This test verifies that when:
+//
+//  - the private network request policy is set to `kPreflightWarn`
+//  - a CORS preflight request detects a private network request
+//  - the following PNA preflight fails due to a non-PNA CORS error
+//
+// ... the error is not ignored and the request is failed.
+TEST_F(CorsURLLoaderTest, PrivateNetworkAccessPolicyWarnPreflightCorsError) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "PUT";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+  request.trusted_params = MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+      mojom::PrivateNetworkRequestPolicy::kPreflightWarn);
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(
+      CorsErrorStatus(mojom::CorsError::kMissingAllowOriginHeader));
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::ERR_FAILED);
+  EXPECT_THAT(
+      client().completion_status().cors_error_status,
+      Optional(CorsErrorStatus(mojom::CorsError::kMissingAllowOriginHeader)));
+}
+
+// This test verifies that when:
+//
+//  - the private network request policy is set to `kPreflightWarn`
+//  - a CORS preflight request detects a private network request
+//  - the following PNA preflight fails due to a missing PNA header
+//
+// ... the error is ignored and the request proceeds.
+TEST_F(CorsURLLoaderTest,
+       PrivateNetworkAccessPolicyWarnPreflightMissingAllowPrivateNetwork) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "PUT";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+  request.trusted_params = MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+      mojom::PrivateNetworkRequestPolicy::kPreflightWarn);
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnReceiveResponse({
+      {"Access-Control-Allow-Methods", "PUT"},
+      {"Access-Control-Allow-Origin", "https://example.com"},
+      {"Access-Control-Allow-Credentials", "true"},
+  });
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnReceiveResponse();
+  NotifyLoaderClientOnComplete(net::OK);
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::OK);
+}
+
+// The following `PrivateNetworkAccessPolicyBlock*` tests verify that PNA
+// preflights must succeed for the overall request to succeed when the private
+// network request policy is set to `kPreflightBlock`.
+
+// This test verifies that when:
+//
+//  - the private network request policy is set to `kPreflightBlock`
+//  - a private network request is detected
+//  - the following PNA preflight fails due to a network error
+//
+// ... the error is not ignored and the request is failed.
+TEST_F(CorsURLLoaderTest, PrivateNetworkAccessPolicyBlockNetError) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "GET";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+  request.trusted_params = MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+      mojom::PrivateNetworkRequestPolicy::kPreflightBlock);
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(net::ERR_INVALID_ARGUMENT);
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::ERR_INVALID_ARGUMENT);
+}
+
+// This test verifies that when:
+//
+//  - the private network request policy is set to `kPreflightBlock`
+//  - a simple request detects a private network request
+//  - the following PNA preflight fails due to a non-PNA CORS error
+//
+// ... the error is not ignored and the request is failed.
+TEST_F(CorsURLLoaderTest, PrivateNetworkAccessPolicyBlockCorsError) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "GET";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+  request.trusted_params = MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+      mojom::PrivateNetworkRequestPolicy::kPreflightBlock);
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(
+      CorsErrorStatus(mojom::CorsError::kMissingAllowOriginHeader));
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::ERR_FAILED);
+  EXPECT_THAT(
+      client().completion_status().cors_error_status,
+      Optional(CorsErrorStatus(mojom::CorsError::kMissingAllowOriginHeader)));
+}
+
+// This test verifies that when:
+//
+//  - the private network request policy is set to `kPreflightBlock`
+//  - a simple request detects a private network request
+//  - the following PNA preflight fails due to a missing PNA header
+//
+// ... the error is ignored and the request proceeds.
+TEST_F(CorsURLLoaderTest,
+       PrivateNetworkAccessPolicyBlockMissingAllowPrivateNetwork) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "GET";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+  request.trusted_params = MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+      mojom::PrivateNetworkRequestPolicy::kPreflightBlock);
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnReceiveResponse({
+      {"Access-Control-Allow-Methods", "GET"},
+      {"Access-Control-Allow-Origin", "https://example.com"},
+      {"Access-Control-Allow-Credentials", "true"},
+  });
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::ERR_FAILED);
+  EXPECT_THAT(client().completion_status().cors_error_status,
+              Optional(CorsErrorStatus(
+                  mojom::CorsError::kPreflightMissingAllowExternal)));
+}
+
+// This test verifies that when:
+//
+//  - the private network request policy is set to `kPreflightWarn`
+//  - a simple request detects a private network request
+//  - the following PNA preflight fails due to an invalid PNA header
+//
+// ... the error is ignored and the request proceeds.
+TEST_F(CorsURLLoaderTest,
+       PrivateNetworkAccessPolicyBlockInvalidAllowPrivateNetwork) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "GET";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+  request.trusted_params = MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+      mojom::PrivateNetworkRequestPolicy::kPreflightBlock);
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnReceiveResponse({
+      {"Access-Control-Allow-Methods", "GET"},
+      {"Access-Control-Allow-Origin", "https://example.com"},
+      {"Access-Control-Allow-Credentials", "true"},
+      {"Access-Control-Allow-Private-Network", "invalid-value"},
+  });
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::ERR_FAILED);
+  EXPECT_THAT(
+      client().completion_status().cors_error_status,
+      Optional(CorsErrorStatus(mojom::CorsError::kPreflightInvalidAllowExternal,
+                               "invalid-value")));
+}
+
+// The following `PrivateNetworkAccessPolicyOn*` tests verify that the private
+// network request policy can be set on the loader factory params or the request
+// itself, with preference given to the factory params.
+
+// This test verifies that when the `ResourceRequest` carries a client security
+// state and the loader factory params do not, the private network request
+// policy is taken from the request.
+//
+// This is achieved by setting the request policy to `kPreflightBlock` and
+// checking that preflight results are respected.
+TEST_F(CorsURLLoaderTest, PrivateNetworkAccessPolicyOnRequestOnly) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "GET";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+  request.trusted_params = MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+      mojom::PrivateNetworkRequestPolicy::kPreflightBlock);
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(net::ERR_INVALID_ARGUMENT);
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::ERR_INVALID_ARGUMENT);
+}
+
+// This test verifies that when the loader factory params carry a client
+// security state and the `ResourceRequest` does not, the private network
+// request policy is taken from the factory params.
+//
+// This is achieved by setting the factory policy to `kPreflightBlock` and
+// checking that preflight results are respected.
+TEST_F(CorsURLLoaderTest, PrivateNetworkAccessPolicyOnFactoryOnly) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.client_security_state =
+      MakeClientSecurityStateWithPrivateNetworkRequestPolicy(
+          mojom::PrivateNetworkRequestPolicy::kPreflightBlock);
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "GET";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(net::ERR_INVALID_ARGUMENT);
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::ERR_INVALID_ARGUMENT);
+}
+
+// This test verifies that when both the `ResourceRequest`  and the loader
+// factory params carry a client security state, the private network request
+// policy is taken from the factory.
+//
+// This is achieved by setting the factory policy to `kPreflightBlock`,
+// the request policy to `kPreflightWarn, and checking that preflight results
+// are respected.
+TEST_F(CorsURLLoaderTest, PrivateNetworkAccessPolicyOnFactoryAndRequest) {
+  auto initiator_origin = url::Origin::Create(GURL("https://example.com"));
+
+  ResetFactoryParams factory_params;
+  factory_params.is_trusted = true;
+  factory_params.client_security_state =
+      MakeClientSecurityStateWithPrivateNetworkRequestPolicy(
+          mojom::PrivateNetworkRequestPolicy::kPreflightBlock);
+  ResetFactory(initiator_origin, kRendererProcessId, factory_params);
+
+  ResourceRequest request;
+  request.method = "GET";
+  request.mode = mojom::RequestMode::kCors;
+  request.url = GURL("https://example.com/");
+  request.request_initiator = initiator_origin;
+  request.trusted_params = MakeTrustedParamsWithPrivateNetworkRequestPolicy(
+      mojom::PrivateNetworkRequestPolicy::kPreflightWarn);
+
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(CorsErrorStatus(
+      mojom::CorsError::kUnexpectedPrivateNetworkAccess,
+      mojom::IPAddressSpace::kUnknown, mojom::IPAddressSpace::kPrivate));
+
+  RunUntilCreateLoaderAndStartCalled();
+  NotifyLoaderClientOnComplete(net::ERR_INVALID_ARGUMENT);
+  RunUntilComplete();
+
+  EXPECT_EQ(client().completion_status().error_code, net::ERR_INVALID_ARGUMENT);
+}
+
 }  // namespace
 
 }  // namespace cors
diff --git a/services/network/cors/preflight_controller.cc b/services/network/cors/preflight_controller.cc
index daca658..a0e73416 100644
--- a/services/network/cors/preflight_controller.cc
+++ b/services/network/cors/preflight_controller.cc
@@ -274,6 +274,8 @@
     const mojom::URLResponseHead& head,
     const ResourceRequest& original_request,
     bool tainted,
+    PreflightController::EnforcePrivateNetworkAccessHeader
+        enforce_private_network_access_header,
     absl::optional<CorsErrorStatus>* detected_error_status) {
   DCHECK(detected_error_status);
 
@@ -298,8 +300,9 @@
   // See the CORS-preflight fetch algorithm modifications laid out in the
   // Private Network Access spec, in step 4 of the CORS preflight section as of
   // writing: https://wicg.github.io/private-network-access/#cors-preflight
-  if (original_request.target_ip_address_space !=
-      mojom::IPAddressSpace::kUnknown) {
+  if (enforce_private_network_access_header &&
+      original_request.target_ip_address_space !=
+          mojom::IPAddressSpace::kUnknown) {
     *detected_error_status = CheckExternalPreflight(GetHeaderString(
         head.headers, header_names::kAccessControlAllowPrivateNetwork));
     if (*detected_error_status)
@@ -344,6 +347,7 @@
       const ResourceRequest& request,
       WithTrustedHeaderClient with_trusted_header_client,
       NonWildcardRequestHeadersSupport non_wildcard_request_headers_support,
+      EnforcePrivateNetworkAccessHeader enforce_private_network_access_header,
       bool tainted,
       const net::NetworkTrafficAnnotationTag& annotation_tag,
       const net::NetworkIsolationKey& network_isolation_key,
@@ -354,6 +358,8 @@
         original_request_(request),
         non_wildcard_request_headers_support_(
             non_wildcard_request_headers_support),
+        enforce_private_network_access_header_(
+            enforce_private_network_access_header),
         tainted_(tainted),
         network_isolation_key_(network_isolation_key),
         devtools_observer_(std::move(devtools_observer)),
@@ -434,7 +440,8 @@
     absl::optional<CorsErrorStatus> detected_error_status;
     bool has_authorization_covered_by_wildcard = false;
     std::unique_ptr<PreflightResult> result = CreatePreflightResult(
-        final_url, head, original_request_, tainted_, &detected_error_status);
+        final_url, head, original_request_, tainted_,
+        enforce_private_network_access_header_, &detected_error_status);
 
     if (result) {
       // Only log if there is a result to log.
@@ -505,6 +512,8 @@
   const ResourceRequest original_request_;
 
   const NonWildcardRequestHeadersSupport non_wildcard_request_headers_support_;
+  const EnforcePrivateNetworkAccessHeader
+      enforce_private_network_access_header_;
   const bool tainted_;
   absl::optional<base::UnguessableToken> devtools_request_id_;
   const net::NetworkIsolationKey network_isolation_key_;
@@ -531,8 +540,10 @@
     const mojom::URLResponseHead& head,
     const ResourceRequest& original_request,
     bool tainted,
+    EnforcePrivateNetworkAccessHeader enforce_private_network_access_header,
     absl::optional<CorsErrorStatus>* detected_error_status) {
   return CreatePreflightResult(final_url, head, original_request, tainted,
+                               enforce_private_network_access_header,
                                detected_error_status);
 }
 
@@ -567,6 +578,7 @@
     const ResourceRequest& request,
     WithTrustedHeaderClient with_trusted_header_client,
     NonWildcardRequestHeadersSupport non_wildcard_request_headers_support,
+    EnforcePrivateNetworkAccessHeader enforce_private_network_access_header,
     bool tainted,
     const net::NetworkTrafficAnnotationTag& annotation_tag,
     mojom::URLLoaderFactory* loader_factory,
@@ -597,7 +609,8 @@
 
   auto emplaced_pair = loaders_.emplace(std::make_unique<PreflightLoader>(
       this, std::move(callback), request, with_trusted_header_client,
-      non_wildcard_request_headers_support, tainted, annotation_tag,
+      non_wildcard_request_headers_support,
+      enforce_private_network_access_header, tainted, annotation_tag,
       network_isolation_key, std::move(devtools_observer), net_log));
   (*emplaced_pair.first)->Request(loader_factory);
 }
diff --git a/services/network/cors/preflight_controller.h b/services/network/cors/preflight_controller.h
index 0292a8bf..dd48c65 100644
--- a/services/network/cors/preflight_controller.h
+++ b/services/network/cors/preflight_controller.h
@@ -38,20 +38,29 @@
  public:
   using CompletionCallback = base::OnceCallback<
       void(int net_error, absl::optional<CorsErrorStatus>, bool)>;
+
   using WithTrustedHeaderClient =
       base::StrongAlias<class WithTrustedHeaderClientTag, bool>;
+
+  // TODO(https://crbug.com/1268378): Remove this once enforcement is always on.
+  using EnforcePrivateNetworkAccessHeader =
+      base::StrongAlias<class EnforcePrivateNetworkAccessHeaderTag, bool>;
+
   // Creates a CORS-preflight ResourceRequest for a specified |request| for a
   // URL that is originally requested.
   static std::unique_ptr<ResourceRequest> CreatePreflightRequestForTesting(
       const ResourceRequest& request,
       bool tainted = false);
+
   // Creates a PreflightResult for a specified response parameters for testing.
   static std::unique_ptr<PreflightResult> CreatePreflightResultForTesting(
       const GURL& final_url,
       const mojom::URLResponseHead& head,
       const ResourceRequest& original_request,
       bool tainted,
+      EnforcePrivateNetworkAccessHeader enforce_private_network_access_header,
       absl::optional<CorsErrorStatus>* detected_error_status);
+
   // Checks CORS aceess on the CORS-preflight response parameters for testing.
   static absl::optional<CorsErrorStatus> CheckPreflightAccessForTesting(
       const GURL& response_url,
@@ -60,6 +69,7 @@
       const absl::optional<std::string>& allow_credentials_header,
       mojom::CredentialsMode actual_credentials_mode,
       const url::Origin& origin);
+
   // Checks errors for the currently experimental
   // "Access-Control-Allow-External" header for testing.
   static absl::optional<CorsErrorStatus> CheckExternalPreflightForTesting(
@@ -80,6 +90,7 @@
       const ResourceRequest& resource_request,
       WithTrustedHeaderClient with_trusted_header_client,
       NonWildcardRequestHeadersSupport non_wildcard_request_headers_support,
+      EnforcePrivateNetworkAccessHeader enforce_private_network_access_header,
       bool tainted,
       const net::NetworkTrafficAnnotationTag& traffic_annotation,
       mojom::URLLoaderFactory* loader_factory,
diff --git a/services/network/cors/preflight_controller_unittest.cc b/services/network/cors/preflight_controller_unittest.cc
index 5518fef..4ae271b 100644
--- a/services/network/cors/preflight_controller_unittest.cc
+++ b/services/network/cors/preflight_controller_unittest.cc
@@ -42,6 +42,8 @@
 namespace {
 
 using WithTrustedHeaderClient = PreflightController::WithTrustedHeaderClient;
+using EnforcePrivateNetworkAccessHeader =
+    PreflightController::EnforcePrivateNetworkAccessHeader;
 
 TEST(PreflightControllerCreatePreflightRequestTest, LexicographicalOrder) {
   ResourceRequest request;
@@ -229,14 +231,16 @@
   preflight_controller.PerformPreflightCheck(
       base::BindOnce([](int, absl::optional<CorsErrorStatus>, bool) {}),
       request, WithTrustedHeaderClient(false),
-      NonWildcardRequestHeadersSupport(false), false /* tainted */,
+      NonWildcardRequestHeadersSupport(false),
+      EnforcePrivateNetworkAccessHeader(false), false /* tainted */,
       TRAFFIC_ANNOTATION_FOR_TESTS, &url_loader_factory, net::IsolationInfo(),
       /*devtools_observer=*/mojo::NullRemote(), net_log);
 
   preflight_controller.PerformPreflightCheck(
       base::BindOnce([](int, absl::optional<CorsErrorStatus>, bool) {}),
       request, WithTrustedHeaderClient(true),
-      NonWildcardRequestHeadersSupport(false), false /* tainted */,
+      NonWildcardRequestHeadersSupport(false),
+      EnforcePrivateNetworkAccessHeader(false), false /* tainted */,
       TRAFFIC_ANNOTATION_FOR_TESTS, &url_loader_factory, net::IsolationInfo(),
       /*devtools_observer=*/mojo::NullRemote(), net_log);
 
@@ -443,7 +447,8 @@
         base::BindOnce(&PreflightControllerTest::HandleRequestCompletion,
                        base::Unretained(this)),
         request, WithTrustedHeaderClient(false),
-        non_wildcard_request_headers_support_, tainted,
+        non_wildcard_request_headers_support_,
+        EnforcePrivateNetworkAccessHeader(false), tainted,
         TRAFFIC_ANNOTATION_FOR_TESTS, url_loader_factory_remote_.get(),
         isolation_info, devtools_observer_->Bind(),
         net::NetLogWithSource::Make(net::NetLog::Get(),
@@ -683,7 +688,9 @@
 
   std::unique_ptr<PreflightResult> result =
       PreflightController::CreatePreflightResultForTesting(
-          url, response_head, request, tainted, &detected_error_status);
+          url, response_head, request, tainted,
+          PreflightController::EnforcePrivateNetworkAccessHeader(true),
+          &detected_error_status);
 
   EXPECT_FALSE(result);
 }
diff --git a/services/network/public/cpp/content_security_policy/content_security_policy.cc b/services/network/public/cpp/content_security_policy/content_security_policy.cc
index 9aa0502..051eb8f 100644
--- a/services/network/public/cpp/content_security_policy/content_security_policy.cc
+++ b/services/network/public/cpp/content_security_policy/content_security_policy.cc
@@ -194,8 +194,10 @@
   GURL blocked_url = (directive_name == CSPDirectiveName::FrameAncestors)
                          ? GURL(ToString(*policy->self_origin))
                          : url;
+  std::string blocked_url_scheme = blocked_url.scheme();
   auto safe_source_location =
       source_location ? source_location->Clone() : mojom::SourceLocation::New();
+
   context->SanitizeDataForUseInCspViolation(has_followed_redirect,
                                             directive_name, &blocked_url,
                                             safe_source_location.get());
@@ -218,6 +220,18 @@
             << ToString(effective_directive_name) << "' is used as a fallback.";
   }
 
+  // Wildcards match network schemes ('http', 'https', 'ws', 'wss'), and the
+  // scheme of the protected resource:
+  // https://w3c.github.io/webappsec-csp/#match-url-to-source-expression. Other
+  // schemes, including custom schemes, must be explicitly listed in a source
+  // list.
+  if (policy->directives[effective_directive_name]->allow_star) {
+    message << " Note that '*' matches only URLs with network schemes ('http', "
+               "'https', 'ws', 'wss'), or URLs whose scheme matches `self`'s "
+               "scheme. "
+            << blocked_url_scheme << ":' must be added explicitely.";
+  }
+
   message << "\n";
 
   context->ReportContentSecurityPolicyViolation(mojom::CSPViolation::New(
diff --git a/services/network/public/cpp/content_security_policy/csp_context_unittest.cc b/services/network/public/cpp/content_security_policy/csp_context_unittest.cc
index ab13222..9043c45 100644
--- a/services/network/public/cpp/content_security_policy/csp_context_unittest.cc
+++ b/services/network/public/cpp/content_security_policy/csp_context_unittest.cc
@@ -335,4 +335,24 @@
   EXPECT_EQ(console_message_a, context.violations()[0]->console_message);
 }
 
+TEST(CSPContextTest, BlockedDespiteWildcard) {
+  CSPContextTest context;
+  auto policies = ParseContentSecurityPolicies(
+      "frame-src *", mojom::ContentSecurityPolicyType::kEnforce,
+      mojom::ContentSecurityPolicySource::kMeta,
+      GURL("https://www.example.org"));
+
+  EXPECT_FALSE(context.IsAllowedByCsp(policies, CSPDirectiveName::FrameSrc,
+                                      GURL("data:text/html,<html></html>"),
+                                      GURL(), false, false, SourceLocation(),
+                                      CSPContext::CHECK_ALL_CSP, false));
+  EXPECT_EQ(context.violations().size(), 1u);
+  EXPECT_EQ(context.violations()[0]->console_message,
+            "Refused to frame 'data:text/html,<html></html>' because it "
+            "violates the following Content Security Policy directive: "
+            "\"frame-src *\". Note that '*' matches only URLs with network "
+            "schemes ('http', 'https', 'ws', 'wss'), or URLs whose scheme "
+            "matches `self`'s scheme. data:' must be added explicitely.\n");
+}
+
 }  // namespace network
diff --git a/services/video_capture/broadcasting_receiver.cc b/services/video_capture/broadcasting_receiver.cc
index 30498d1..18b211b 100644
--- a/services/video_capture/broadcasting_receiver.cc
+++ b/services/video_capture/broadcasting_receiver.cc
@@ -222,7 +222,15 @@
       }
       break;
     case media::VideoCaptureBufferType::kGpuMemoryBuffer:
+#if defined(OS_WIN)
+      // On windows with MediaFoundationD3D11VideoCapture if the
+      // texture capture path fails, a ShMem buffer might be produced instead.
+      DCHECK(buffer_handle_->is_shared_buffer_handle());
+      CloneSharedBufferHandle(buffer_handle_->get_shared_buffer_handle(),
+                              &result);
+#else
       NOTREACHED() << "Unexpected GpuMemoryBuffer handle type";
+#endif
       break;
   }
   return result;
diff --git a/storage/browser/quota/README.md b/storage/browser/quota/README.md
index b1f532f..c94d182a 100644
--- a/storage/browser/quota/README.md
+++ b/storage/browser/quota/README.md
@@ -30,7 +30,7 @@
 
 ### PaddingKey
 Helpers for computing quota usage for opaque resources. Features that store
-opaque resources (AppCache, Cache Storage) should use these helpers to avoid
+opaque resources (e.g. Cache Storage) should use these helpers to avoid
 leaking cross-origin information via the quota usage they report.
 
 ### SpecialStoragePolicy
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 26fc0940..b08876d 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -1193,7 +1193,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android31.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android31.textpb",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.cc_unittests.filter"
         ],
         "merge": {
           "args": [
@@ -2484,7 +2485,8 @@
           "--use-cmd-decoder=validating",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android31.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android31.textpb",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.gl_tests.filter"
         ],
         "merge": {
           "args": [
@@ -5791,7 +5793,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M96",
-              "revision": "version:96.0.4664.57"
+              "revision": "version:96.0.4664.70"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -5879,7 +5881,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M97",
-              "revision": "version:97.0.4692.23"
+              "revision": "version:97.0.4692.26"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -6055,7 +6057,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M96",
-              "revision": "version:96.0.4664.57"
+              "revision": "version:96.0.4664.70"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -6143,7 +6145,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M97",
-              "revision": "version:97.0.4692.23"
+              "revision": "version:97.0.4692.26"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 59ee5ff..31d7789e 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -11719,7 +11719,7 @@
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
           "--avd-config=../../tools/android/avd/proto/generic_android30.textpb",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11.cc_unittests.filter"
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.cc_unittests.filter"
         ],
         "merge": {
           "args": [
@@ -43662,7 +43662,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M96",
-              "revision": "version:96.0.4664.57"
+              "revision": "version:96.0.4664.70"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -43750,7 +43750,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M97",
-              "revision": "version:97.0.4692.23"
+              "revision": "version:97.0.4692.26"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -43926,7 +43926,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M96",
-              "revision": "version:96.0.4664.57"
+              "revision": "version:96.0.4664.70"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -44014,7 +44014,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M97",
-              "revision": "version:97.0.4692.23"
+              "revision": "version:97.0.4692.26"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -44265,7 +44265,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M96",
-              "revision": "version:96.0.4664.57"
+              "revision": "version:96.0.4664.70"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -44353,7 +44353,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M97",
-              "revision": "version:97.0.4692.23"
+              "revision": "version:97.0.4692.26"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -44529,7 +44529,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M96",
-              "revision": "version:96.0.4664.57"
+              "revision": "version:96.0.4664.70"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -44617,7 +44617,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M97",
-              "revision": "version:97.0.4692.23"
+              "revision": "version:97.0.4692.26"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -44868,7 +44868,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M96",
-              "revision": "version:96.0.4664.57"
+              "revision": "version:96.0.4664.70"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -44956,7 +44956,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M97",
-              "revision": "version:97.0.4692.23"
+              "revision": "version:97.0.4692.26"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -45132,7 +45132,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M96",
-              "revision": "version:96.0.4664.57"
+              "revision": "version:96.0.4664.70"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -45220,7 +45220,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M97",
-              "revision": "version:97.0.4692.23"
+              "revision": "version:97.0.4692.26"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 832e1102..a4873bf 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -13775,7 +13775,8 @@
           "--passthrough",
           "-v",
           "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough --force_high_performance_gpu",
-          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json"
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json",
+          "--is-asan"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -17813,7 +17814,8 @@
           "-v",
           "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=metal --use-cmd-decoder=passthrough --force_high_performance_gpu",
           "--webgl-conformance-version=2.0.1",
-          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json",
+          "--is-asan"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -17895,7 +17897,8 @@
           "--passthrough",
           "-v",
           "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough --force_high_performance_gpu",
-          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json"
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json",
+          "--is-asan"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -17935,7 +17938,8 @@
           "--passthrough",
           "-v",
           "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=metal --use-cmd-decoder=passthrough --force_high_performance_gpu",
-          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json"
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json",
+          "--is-asan"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index fa674782..78addf1 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -21,7 +21,7 @@
 
   data = [
     "//testing/buildbot/filters/android.emulator.cc_unittests.filter",
-    "//testing/buildbot/filters/android.emulator_11.cc_unittests.filter",
+    "//testing/buildbot/filters/android.emulator_11_12.cc_unittests.filter",
     "//testing/buildbot/filters/fuchsia.debug.cc_unittests.filter",
     "//testing/buildbot/filters/gpu.linux.skiarenderer_dawn_cc_unittests.filter",
     "//testing/buildbot/filters/gpu.skiarenderer_dawn_cc_unittests.filter",
@@ -199,6 +199,7 @@
   data = [
     "//testing/buildbot/filters/android.emulator.gl_tests.filter",
     "//testing/buildbot/filters/android.emulator_11.gl_tests.filter",
+    "//testing/buildbot/filters/android.emulator_12.gl_tests.filter",
     "//testing/buildbot/filters/android.pie_arm64_rel.gl_tests.filter",
   ]
 }
diff --git a/testing/buildbot/filters/android.emulator_11.cc_unittests.filter b/testing/buildbot/filters/android.emulator_11_12.cc_unittests.filter
similarity index 100%
rename from testing/buildbot/filters/android.emulator_11.cc_unittests.filter
rename to testing/buildbot/filters/android.emulator_11_12.cc_unittests.filter
diff --git a/testing/buildbot/filters/android.emulator_12.gl_tests.filter b/testing/buildbot/filters/android.emulator_12.gl_tests.filter
new file mode 100644
index 0000000..23ed8e0
--- /dev/null
+++ b/testing/buildbot/filters/android.emulator_12.gl_tests.filter
@@ -0,0 +1,12 @@
+# https://crbug.com/1189284
+-CopyType/GLCopyTextureCHROMIUMES3Test.CopyTextureCubeMap/0
+-CopyType/GLCopyTextureCHROMIUMES3Test.CopyTextureLevel/0
+-CopyType/GLCopyTextureCHROMIUMES3Test.FormatCombinations/0
+-CopyType/GLCopyTextureCHROMIUMES3Test.FormatCombinations/1
+-CopyType/GLCopyTextureCHROMIUMTest.CopyTextureLevel/1
+-CopyType/GLCopyTextureCHROMIUMTest.ImmutableTexture/1
+-GLBGRAMipMapTest.GenerateMipmapsSucceeds
+-RasterInProcessCommandBufferTest.AllowedBetweenBeginEndRasterCHROMIUM
+
+# crbug.com/1271745
+-ES3MapBufferRangeTest.CopyBufferSubData
diff --git a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter
index 8ab5af5..739072d 100644
--- a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter
+++ b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter
@@ -49,7 +49,10 @@
 -DemoSetupArcUnsupportedTest.*
 -DemoSetupFRETest.*
 -DemoSetupProgressStepsTest.*
+-DemoSetupRegionCodeNotExistTest.*
 -DemoSetupTestBase.*
+-DemoSetupVariantCountryCodeRegionTest.*
+-DemoSetupVirtualSetRegionCodeTest.*
 -DeviceDisablingBeforeLoginHostCreated.*
 -DeviceDisablingTest.*
 -DeviceIDTest.*
diff --git a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter
index 3ece1b6..d60cfa6 100644
--- a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter
+++ b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter
@@ -49,7 +49,10 @@
 DemoSetupArcUnsupportedTest.*
 DemoSetupFRETest.*
 DemoSetupProgressStepsTest.*
+DemoSetupRegionCodeNotExistTest.*
 DemoSetupTestBase.*
+DemoSetupVariantCountryCodeRegionTest.*
+DemoSetupVirtualSetRegionCodeTest.*
 DeviceDisablingBeforeLoginHostCreated.*
 DeviceDisablingTest.*
 DeviceIDTest.*
diff --git a/testing/buildbot/filters/mac.mac11-arm64-rel.browser_tests.filter b/testing/buildbot/filters/mac.mac11-arm64-rel.browser_tests.filter
index fd8de02..6eec4e1 100644
--- a/testing/buildbot/filters/mac.mac11-arm64-rel.browser_tests.filter
+++ b/testing/buildbot/filters/mac.mac11-arm64-rel.browser_tests.filter
@@ -18,3 +18,4 @@
 -WebAppBrowserTest.WebAppCreateAndDeleteShortcut
 -SaveAsMhtml/SavePageOriginalVsSavedComparisonTest.NestedFrames/0
 -WorkerDevToolsTest.PauseInSharedWorkerInitialization
+-GetDisplayMediaChangeSourceBrowserTest.ChangeSource
diff --git a/testing/buildbot/filters/ozone-linux.wayland_views_unittests.filter b/testing/buildbot/filters/ozone-linux.wayland_views_unittests.filter
index 809a776..90c1bd8 100644
--- a/testing/buildbot/filters/ozone-linux.wayland_views_unittests.filter
+++ b/testing/buildbot/filters/ozone-linux.wayland_views_unittests.filter
@@ -2,6 +2,8 @@
 
 # Tests activation of windows.  Wayland doesn't allow the client to activate its
 # windows so this test makes no sense.
+# TODO(crbug.com/1175327): maybe re-evaluate the above after xdg-activation is
+# supported.
 -DesktopWidgetFocusManagerTest.AnchoredDialogInDesktopNativeWidgetAura
 
 # Tests behaviour that is specific for X11.
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index c8b41107..019d083 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -784,7 +784,13 @@
       'android-11-x86-rel': {
         # https://crbug.com/1039860
         'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11.cc_unittests.filter',
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.cc_unittests.filter',
+        ],
+      },
+      'android-12-x64-fyi-rel': {
+        # https://crbug.com/1039860
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.cc_unittests.filter',
         ],
       },
       'android-marshmallow-x86-rel': {
@@ -1670,6 +1676,11 @@
           '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11.gl_tests.filter',
         ],
       },
+      'android-12-x64-fyi-rel': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.gl_tests.filter',
+        ],
+      },
       'android-marshmallow-x86-rel': {
         'args': [
           '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.gl_tests.filter',
@@ -3170,6 +3181,18 @@
     },
   },
   'webgl2_conformance_metal_passthrough_tests': {
+    'modifications': {
+      'Mac FYI ASAN (Intel)': {
+        'args': [
+          '--is-asan',
+        ]
+      },
+      'Mac FYI Retina ASAN (AMD)': {
+        'args': [
+          '--is-asan',
+        ]
+      },
+    },
     'remove_from': [
       # crbug.com/1270755: failing entire shards on Intel ASAN bot.
       'Mac FYI ASAN (Intel)',
@@ -3213,6 +3236,18 @@
     },
   },
   'webgl_conformance_gl_passthrough_tests': {
+    'modifications': {
+      'Mac FYI ASAN (Intel)': {
+        'args': [
+          '--is-asan',
+        ]
+      },
+      'Mac FYI Retina ASAN (AMD)': {
+        'args': [
+          '--is-asan',
+        ]
+      },
+    },
     'remove_from': [
       # crbug.com/555545 and crbug.com/649824:
       # Disable webgl_conformance_gl_tests on some Win/AMD cards.
@@ -3221,6 +3256,18 @@
     ],
   },
   'webgl_conformance_metal_passthrough_tests': {
+    'modifications': {
+      'Mac FYI ASAN (Intel)': {
+        'args': [
+          '--is-asan',
+        ]
+      },
+      'Mac FYI Retina ASAN (AMD)': {
+        'args': [
+          '--is-asan',
+        ]
+      },
+    },
     'remove_from': [
       # crbug.com/1270755: failing entire shards on Intel ASAN bot.
       'Mac FYI ASAN (Intel)',
@@ -3229,6 +3276,18 @@
     ],
   },
   'webgl_conformance_tests': {
+    'modifications': {
+      'Mac FYI ASAN (Intel)': {
+        'args': [
+          '--is-asan',
+        ]
+      },
+      'Mac FYI Retina ASAN (AMD)': {
+        'args': [
+          '--is-asan',
+        ]
+      },
+    },
     'remove_from': [
       # Too slow on this configuration, which is severely hardware
       # constrained. crbug.com/950690
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 50200165..ac879589 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -363,7 +363,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M97',
-          'revision': 'version:97.0.4692.23',
+          'revision': 'version:97.0.4692.26',
         }
       ],
     },
@@ -387,7 +387,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M96',
-          'revision': 'version:96.0.4664.57',
+          'revision': 'version:96.0.4664.70',
         }
       ],
     },
@@ -435,7 +435,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M97',
-          'revision': 'version:97.0.4692.23',
+          'revision': 'version:97.0.4692.26',
         }
       ],
     },
@@ -459,7 +459,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M96',
-          'revision': 'version:96.0.4664.57',
+          'revision': 'version:96.0.4664.70',
         }
       ],
     },
@@ -507,7 +507,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M97',
-          'revision': 'version:97.0.4692.23',
+          'revision': 'version:97.0.4692.26',
         }
       ],
     },
@@ -531,7 +531,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M96',
-          'revision': 'version:96.0.4664.57',
+          'revision': 'version:96.0.4664.70',
         }
       ],
     },
diff --git a/testing/scripts/run_finch_smoke_tests_android.py b/testing/scripts/run_finch_smoke_tests_android.py
index 2cda6249..ac0b4c7 100755
--- a/testing/scripts/run_finch_smoke_tests_android.py
+++ b/testing/scripts/run_finch_smoke_tests_android.py
@@ -82,7 +82,6 @@
         self._device, '%s-command-line' % self.product_name())
     self.browser_package_name = apk_helper.GetPackageName(
         self.options.browser_apk)
-    self.flags.ReplaceFlags(self.browser_command_line_args())
     self.browser_activity_name = (self.options.browser_activity_name or
                                   self.default_browser_activity_name)
     self.log_mon = None
@@ -168,6 +167,9 @@
       '--mojojs-path=' + self.mojo_js_directory,
     ])
 
+    for binary_arg in self.browser_command_line_args():
+      rest_args.append('--binary-arg=%s' % binary_arg)
+
     for test in self.tests:
       rest_args.extend(['--include', test])
 
@@ -202,6 +204,10 @@
     parser.add_argument('--webview-provider-apk',
                         type=os.path.realpath,
                         help='Path to the WebView provider apk')
+    parser.add_argument('--additional-apk',
+                        action='append',
+                        type=os.path.realpath,
+                        help='List of additional apk\'s to install')
     parser.add_argument('--browser-activity-name',
                         action='store',
                         help='Browser activity name')
@@ -224,6 +230,8 @@
     """Install apks for testing"""
     self._device.Uninstall(self.browser_package_name)
     self._device.Install(self.options.browser_apk, reinstall=True)
+    for apk_path in self.options.additional_apk:
+      self._device.Install(apk_path)
     yield
 
   def browser_command_line_args(self):
@@ -242,6 +250,9 @@
     """
     self.layout_test_results_subdir = ('%s_smoke_test_artifacts' %
                                        test_run_variation)
+
+    # Make sure the browser is not running before the tests run
+    self.stop_browser()
     ret = super(FinchTestCase, self).run_test()
     self.stop_browser()
 
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 7d78e50..b42bab1 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1823,6 +1823,34 @@
             ]
         }
     ],
+    "CacheCodeOnIdle": [
+        {
+            "platforms": [
+                "android",
+                "android_weblayer",
+                "android_webview",
+                "chromeos",
+                "chromeos_lacros",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "CacheCodeOnIdle"
+                    ]
+                },
+                {
+                    "name": "Disabled",
+                    "disable_features": [
+                        "CacheCodeOnIdle"
+                    ]
+                }
+            ]
+        }
+    ],
     "CanvasOutOfProcessRasterization": [
         {
             "platforms": [
@@ -3710,6 +3738,21 @@
             ]
         }
     ],
+    "FeedLoadingPlaceholderStudy": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled_20211118",
+                    "enable_features": [
+                        "FeedLoadingPlaceholder"
+                    ]
+                }
+            ]
+        }
+    ],
     "FeedPullToRefresh": [
         {
             "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 5caff80..7d66acc 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -265,6 +265,10 @@
 #endif
 };
 
+// Enables new behavior for window.open() and BarProp properties.
+const base::Feature kWindowOpenNewPopupBehavior{
+    "WindowOpenNewPopupBehavior", base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Changes the default RTCPeerConnection constructor behavior to use Unified
 // Plan as the SDP semantics. When the feature is enabled, Unified Plan is used
 // unless the default is overridden (by passing {sdpSemantics:'plan-b'} as the
@@ -1131,5 +1135,11 @@
 const base::Feature kClientHintThirdPartyDelegation{
     "ClientHintThirdPartyDelegation", base::FEATURE_DISABLED_BY_DEFAULT};
 
+#if defined(OS_ANDROID)
+// Enables prefetching Android fonts on renderer startup.
+const base::Feature kPrefetchAndroidFonts{"PrefetchAndroidFonts",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
 }  // namespace features
 }  // namespace blink
diff --git a/third_party/blink/perf_tests/css/HighlightInheritanceRecalc.html b/third_party/blink/perf_tests/css/HighlightInheritanceRecalc.html
new file mode 100644
index 0000000..947558a
--- /dev/null
+++ b/third_party/blink/perf_tests/css/HighlightInheritanceRecalc.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script src="../resources/runner.js"></script>
+<script src="resources/utils.js"></script>
+<body>
+<main></main>
+<style>
+/* non-::selection rules required when HighlightInheritance is disabled */
+:root, :root::selection { --bg: blue; }
+.green:root, .green:root::selection { --bg: green; }
+*::selection /* same as ::selection */ {
+    /* explicitly inherit all for worst case scenario */
+    all: inherit;
+    background-color: var(--bg);
+}
+</style>
+<script>
+createDOMTree(document.querySelector("main"), 4, 6);
+PerfTestRunner.measureTime({
+    description: 'Measure impact of highlight inheritance on content with universal ::selection rules',
+    run: () => {
+        document.documentElement.classList.toggle("green");
+        forceStyleRecalc(document.documentElement);
+    },
+});
+</script>
+</body>
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 29e78446..121360f 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -7,6 +7,7 @@
 
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
+#include "build/build_config.h"
 #include "media/media_buildflags.h"
 #include "third_party/blink/public/common/buildflags.h"
 #include "third_party/blink/public/common/common_export.h"
@@ -97,6 +98,7 @@
     kPreviewsResourceLoadingHintsSpecificResourceTypes;
 BLINK_COMMON_EXPORT extern const base::Feature
     kPurgeRendererMemoryWhenBackgrounded;
+BLINK_COMMON_EXPORT extern const base::Feature kWindowOpenNewPopupBehavior;
 BLINK_COMMON_EXPORT extern const base::Feature kRTCUnifiedPlanByDefault;
 BLINK_COMMON_EXPORT extern const base::Feature
     kRTCDisallowPlanBOutsideDeprecationTrial;
@@ -535,6 +537,10 @@
 
 BLINK_COMMON_EXPORT extern const base::Feature kClientHintThirdPartyDelegation;
 
+#if defined(OS_ANDROID)
+BLINK_COMMON_EXPORT extern const base::Feature kPrefetchAndroidFonts;
+#endif
+
 }  // namespace features
 }  // namespace blink
 
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index b515c5f..d84641fc 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -8929,6 +8929,8 @@
       optional string proxyServer
       # Proxy bypass list, similar to the one passed to --proxy-bypass-list
       optional string proxyBypassList
+      # An optional list of origins to grant unlimited cross-origin access to.
+      optional array of string originsWithUniversalNetworkAccess
 
     returns
       # The id of the context created.
diff --git a/third_party/blink/public/mojom/android_font_lookup/android_font_lookup.mojom b/third_party/blink/public/mojom/android_font_lookup/android_font_lookup.mojom
index b8c41e41..a60abeba 100644
--- a/third_party/blink/public/mojom/android_font_lookup/android_font_lookup.mojom
+++ b/third_party/blink/public/mojom/android_font_lookup/android_font_lookup.mojom
@@ -20,7 +20,14 @@
   // full font name or null if the font is not available. Although the
   // implementation posts to a user-blocking background thread, this interface
   // is synchronous for the renderer to avoid unnecessary re-layout jank.
+  // TODO(crbug.com/1270949): This may be able to be removed if
+  // FetchAllFontFiles() can be used to get the font file handles.
   [Sync]
   MatchLocalFontByUniqueName(string font_unique_name)
     => (mojo_base.mojom.ReadOnlyFile? font_file_handle);
+
+  // Fetches all available font files and returns a map of ICU case folded full
+  // font name to file.
+  FetchAllFontFiles()
+    => (map<string, mojo_base.mojom.ReadOnlyFile> font_files);
 };
diff --git a/third_party/blink/public/mojom/drag/drag.mojom b/third_party/blink/public/mojom/drag/drag.mojom
index f0e05d63..f79084f 100644
--- a/third_party/blink/public/mojom/drag/drag.mojom
+++ b/third_party/blink/public/mojom/drag/drag.mojom
@@ -44,8 +44,9 @@
 struct DragItemBinary {
   // Image data.
   mojo_base.mojom.BigBuffer data;
-  // True if image is same origin (or allowed crossorigin) as drag start frame.
-  bool is_accessible_from_start_frame;
+  // True if image is same origin (or allowed crossorigin) in the source frame,
+  // or is being dragged to a different page.
+  bool is_image_accessible;
   url.mojom.Url source_url;
   mojo_base.mojom.FilePath filename_extension;
   // Content-Disposition response header.
diff --git a/third_party/blink/public/mojom/mediastream/media_devices.mojom b/third_party/blink/public/mojom/mediastream/media_devices.mojom
index 05596f9..7af1b96db 100644
--- a/third_party/blink/public/mojom/mediastream/media_devices.mojom
+++ b/third_party/blink/public/mojom/mediastream/media_devices.mojom
@@ -129,6 +129,12 @@
   // to close the window early.)
   [EnableIfNot=is_android]
   CloseFocusWindowOfOpportunity(string label);
+
+  // Mints a new crop-ID, associates it with the browsing context in which
+  // it was produced, and returns it. This crop-ID can later be used as the
+  // input for BrowserCaptureMediaStreamTrack.cropTo().
+  [EnableIfNot=is_android]
+  ProduceCropId() => (string crop_id);
 };
 
 // This object lives in the renderer process and is used by the browser process
diff --git a/third_party/blink/public/platform/media/multi_buffer_data_source.h b/third_party/blink/public/platform/media/multi_buffer_data_source.h
index 274308e..3224b0c 100644
--- a/third_party/blink/public/platform/media/multi_buffer_data_source.h
+++ b/third_party/blink/public/platform/media/multi_buffer_data_source.h
@@ -137,6 +137,8 @@
 
   bool cancel_on_defer_for_testing() const { return cancel_on_defer_; }
 
+  const std::string& mime_type() const { return url_data_->mime_type(); }
+
  protected:
   void OnRedirected(const scoped_refptr<UrlData>& new_destination);
 
diff --git a/third_party/blink/public/platform/media/url_index.h b/third_party/blink/public/platform/media/url_index.h
index bb83fbc..e5aad8b 100644
--- a/third_party/blink/public/platform/media/url_index.h
+++ b/third_party/blink/public/platform/media/url_index.h
@@ -80,6 +80,8 @@
 
   bool has_access_control() const { return has_access_control_; }
 
+  const std::string& mime_type() const { return mime_type_; }
+
   // Are HTTP range requests supported?
   bool range_supported() const { return range_supported_; }
 
@@ -136,6 +138,7 @@
   void set_etag(const std::string& etag);
   void set_is_cors_cross_origin(bool is_cors_cross_origin);
   void set_has_access_control();
+  void set_mime_type(std::string mime_type);
 
   // A redirect has occurred (or we've found a better UrlData for the same
   // resource).
@@ -192,6 +195,9 @@
   const CorsMode cors_mode_;
   bool has_access_control_;
 
+  // Mime type category (stashed for UMA / metrics).
+  std::string mime_type_;
+
   UrlIndex* const url_index_;
 
   // Length of resource this url points to. (in bytes)
diff --git a/third_party/blink/public/platform/web_drag_data.h b/third_party/blink/public/platform/web_drag_data.h
index 54af322..2f539a7 100644
--- a/third_party/blink/public/platform/web_drag_data.h
+++ b/third_party/blink/public/platform/web_drag_data.h
@@ -88,7 +88,7 @@
 
     // Only valid when storage_type == kStorageTypeBinaryData.
     WebData binary_data;
-    bool binary_data_accessible_from_start_frame;
+    bool binary_data_image_accessible;
     WebURL binary_data_source_url;
     WebString binary_data_filename_extension;
     WebString binary_data_content_disposition;
diff --git a/third_party/blink/renderer/bindings/core/v8/idl_dictionary_base.cc b/third_party/blink/renderer/bindings/core/v8/idl_dictionary_base.cc
index 11b7f0d..4365d67 100644
--- a/third_party/blink/renderer/bindings/core/v8/idl_dictionary_base.cc
+++ b/third_party/blink/renderer/bindings/core/v8/idl_dictionary_base.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/bindings/core/v8/idl_dictionary_base.h"
 
+#include "base/notreached.h"
+
 namespace blink {
 
 v8::Local<v8::Value> IDLDictionaryBase::ToV8Impl(v8::Local<v8::Object>,
diff --git a/third_party/blink/renderer/bindings/core/v8/idl_types.h b/third_party/blink/renderer/bindings/core/v8/idl_types.h
index 978923a..e9ad3f7 100644
--- a/third_party/blink/renderer/bindings/core/v8/idl_types.h
+++ b/third_party/blink/renderer/bindings/core/v8/idl_types.h
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/idl_types_base.h"
 #include "third_party/blink/renderer/bindings/core/v8/native_value_traits.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/heap_traits.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/module_record_test.cc b/third_party/blink/renderer/bindings/core/v8/module_record_test.cc
index e4358db..2820a117 100644
--- a/third_party/blink/renderer/bindings/core/v8/module_record_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/module_record_test.cc
@@ -21,6 +21,7 @@
 #include "third_party/blink/renderer/core/testing/module_test_base.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "v8/include/v8.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h b/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
index a43626e..26581399 100644
--- a/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
+++ b/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
@@ -23,6 +23,7 @@
 #include "third_party/blink/renderer/core/typed_arrays/dom_data_view.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
+#include "third_party/blink/renderer/platform/heap/heap_traits.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/bindings/core/v8/profiler_trace_builder.h b/third_party/blink/renderer/bindings/core/v8/profiler_trace_builder.h
index 6bf4464..6f2cf40d 100644
--- a/third_party/blink/renderer/bindings/core/v8/profiler_trace_builder.h
+++ b/third_party/blink/renderer/bindings/core/v8/profiler_trace_builder.h
@@ -7,8 +7,8 @@
 
 #include "base/time/time.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/script_promise.h b/third_party/blink/renderer/bindings/core/v8/script_promise.h
index 3b7d6d5..e92cb04 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_promise.h
+++ b/third_party/blink/renderer/bindings/core/v8/script_promise.h
@@ -34,6 +34,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/transferables.h b/third_party/blink/renderer/bindings/core/v8/serialization/transferables.h
index 850f500b..9d64d37 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/transferables.h
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/transferables.h
@@ -6,8 +6,9 @@
 #define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SERIALIZATION_TRANSFERABLES_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/unpacked_serialized_script_value.h b/third_party/blink/renderer/bindings/core/v8/serialization/unpacked_serialized_script_value.h
index 45a0fce1..73b5f22 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/unpacked_serialized_script_value.h
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/unpacked_serialized_script_value.h
@@ -8,10 +8,9 @@
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/bindings/core/v8/trace_wrapper_v8_reference_test.cc b/third_party/blink/renderer/bindings/core/v8/trace_wrapper_v8_reference_test.cc
index 349df1c..fc02996 100644
--- a/third_party/blink/renderer/bindings/core/v8/trace_wrapper_v8_reference_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/trace_wrapper_v8_reference_test.cc
@@ -6,6 +6,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h
index 0bbe582..6d792ef 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h
+++ b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h
@@ -52,6 +52,7 @@
 #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
 #include "third_party/blink/renderer/platform/bindings/v8_value_cache.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/heap_traits.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
 #include "v8/include/v8.h"
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index 5752c7d..f92e2e1e 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -2520,6 +2520,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_boolean_mediatrackconstraints.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_canvasfilter_string.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_canvasfilter_string.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_htmlvideoelement_videoframe.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_htmlvideoelement_videoframe.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_canvasrenderingcontext2d_gpucanvascontext_imagebitmaprenderingcontext_webgl2renderingcontext_webglrenderingcontext.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_canvasrenderingcontext2d_gpucanvascontext_imagebitmaprenderingcontext_webgl2renderingcontext_webglrenderingcontext.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_client_messageport_serviceworker.cc",
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py b/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
index f7ef925..de1e3b4 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
@@ -92,7 +92,8 @@
         elif (idl_type.is_sequence or idl_type.is_frozen_array
               or idl_type.is_record or idl_type.is_variadic):
             header_include_headers.add(
-                "third_party/blink/renderer/platform/heap/heap_allocator.h")
+                "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
+            )
         elif idl_type.is_string:
             header_include_headers.add(
                 "third_party/blink/renderer/platform/wtf/text/wtf_string.h")
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py b/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py
index 4f118b80..eac3100b 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py
@@ -1039,9 +1039,10 @@
     # Assemble the parts.
     header_node.accumulator.add_class_decls(["ExceptionState"])
     header_node.accumulator.add_include_headers([
-        (PathManager(dictionary.inherited).api_path(ext="h")
-         if dictionary.inherited else
+        (PathManager(dictionary.inherited).api_path(
+            ext="h") if dictionary.inherited else
          "third_party/blink/renderer/platform/bindings/dictionary_base.h"),
+        "base/containers/span.h",
         component_export_header(api_component, for_testing),
     ])
     source_node.accumulator.add_include_headers([
diff --git a/third_party/blink/renderer/build/scripts/templates/instrumenting_probes_inl.h.tmpl b/third_party/blink/renderer/build/scripts/templates/instrumenting_probes_inl.h.tmpl
index e85b68c..00432fa 100644
--- a/third_party/blink/renderer/build/scripts/templates/instrumenting_probes_inl.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/instrumenting_probes_inl.h.tmpl
@@ -8,7 +8,7 @@
 #ifndef {{header_guard}}
 #define {{header_guard}}
 
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 {% for include in config["settings"]["includes"] %}
 #include "{{include}}"
 {% endfor %}
diff --git a/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.cc b/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.cc
index c0c2317b..9f14c75f 100644
--- a/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.cc
+++ b/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.cc
@@ -13,7 +13,6 @@
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
 #include "third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h"
 #include "third_party/blink/renderer/core/workers/worker_thread.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index c007905..cf645c79 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1573,7 +1573,10 @@
     "//components/shared_highlighting/core/common",
     "//components/shared_highlighting/core/common:data_driven_testing",
     "//components/ukm:test_support",
+    "//components/viz/test:test_support",
     "//content/test:test_support",
+    "//gpu/command_buffer/client:raster",
+    "//gpu/config",
     "//mojo/public/cpp/system",
     "//mojo/public/cpp/test_support:test_utils",
     "//services/metrics/public/cpp:ukm_builders",
diff --git a/third_party/blink/renderer/core/DEPS b/third_party/blink/renderer/core/DEPS
index 529d0bd1..f603c132 100644
--- a/third_party/blink/renderer/core/DEPS
+++ b/third_party/blink/renderer/core/DEPS
@@ -146,11 +146,15 @@
         # Test harness may use cc directly instead of going through WebViewImpl etc.
         "+cc",
         "+components/ukm/test_ukm_recorder.h",
+        "+components/viz/test",
 	# TODO(crbug.com/838693): Test harnesses use LayerTreeView
 	# from content instead of a fake WebLayerTreeView implementation, so
 	# that the Web abstraction can go away.
         "+content/renderer/compositor",
         "+content/test",
+        # Unit tests may use gpu/ for mocking and faking and for config tweaks.
+        "+gpu/command_buffer/client/raster_implementation_gles.h",
+        "+gpu/config",
         "+testing/perf/perf_result_reporter.h",
         "+third_party/blink/renderer/core/frame/web_local_frame_impl.h",
         "+third_party/blink/renderer/core/frame/web_remote_frame_impl.h",
diff --git a/third_party/blink/renderer/core/animation/animatable.h b/third_party/blink/renderer/core/animation/animatable.h
index 03d9603..568af80 100644
--- a/third_party/blink/renderer/core/animation/animatable.h
+++ b/third_party/blink/renderer/core/animation/animatable.h
@@ -32,7 +32,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_ANIMATABLE_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/animation/css/css_animation_update_scope.h b/third_party/blink/renderer/core/animation/css/css_animation_update_scope.h
index 50f420f..557a4154 100644
--- a/third_party/blink/renderer/core/animation/css/css_animation_update_scope.h
+++ b/third_party/blink/renderer/core/animation/css/css_animation_update_scope.h
@@ -6,7 +6,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_CSS_ANIMATION_UPDATE_SCOPE_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
diff --git a/third_party/blink/renderer/core/animation/element_animations.h b/third_party/blink/renderer/core/animation/element_animations.h
index e9289f27..d9a1780 100644
--- a/third_party/blink/renderer/core/animation/element_animations.h
+++ b/third_party/blink/renderer/core/animation/element_animations.h
@@ -37,6 +37,8 @@
 #include "third_party/blink/renderer/core/animation/effect_stack.h"
 #include "third_party/blink/renderer/core/animation/worklet_animation_base.h"
 #include "third_party/blink/renderer/core/css/properties/css_bitset.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/hash_counted_set.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
diff --git a/third_party/blink/renderer/core/animation/worklet_animation_controller.h b/third_party/blink/renderer/core/animation/worklet_animation_controller.h
index be9a8dae..6cf5dcda 100644
--- a/third_party/blink/renderer/core/animation/worklet_animation_controller.h
+++ b/third_party/blink/renderer/core/animation/worklet_animation_controller.h
@@ -11,8 +11,9 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/graphics/animation_worklet_mutators_state.h"
 #include "third_party/blink/renderer/platform/graphics/mutator_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.h b/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.h
index 99c5df0..18f9a26 100644
--- a/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.h
+++ b/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.h
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/frame_request_callback_collection.h"
 #include "third_party/blink/renderer/platform/graphics/begin_frame_provider.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
diff --git a/third_party/blink/renderer/core/app_history/app_history.h b/third_party/blink/renderer/core/app_history/app_history.h
index 9603e6de10..8734dd8 100644
--- a/third_party/blink/renderer/core/app_history/app_history.h
+++ b/third_party/blink/renderer/core/app_history/app_history.h
@@ -13,7 +13,7 @@
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 
diff --git a/third_party/blink/renderer/core/app_history/app_history_api_navigation.h b/third_party/blink/renderer/core/app_history/app_history_api_navigation.h
index d906c4a..6bff9525 100644
--- a/third_party/blink/renderer/core/app_history/app_history_api_navigation.h
+++ b/third_party/blink/renderer/core/app_history/app_history_api_navigation.h
@@ -7,7 +7,6 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
diff --git a/third_party/blink/renderer/core/app_history/app_history_current_change_event.h b/third_party/blink/renderer/core/app_history/app_history_current_change_event.h
index ddcf2a7..18644fe 100644
--- a/third_party/blink/renderer/core/app_history/app_history_current_change_event.h
+++ b/third_party/blink/renderer/core/app_history/app_history_current_change_event.h
@@ -6,7 +6,6 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_APP_HISTORY_APP_HISTORY_CURRENT_CHANGE_EVENT_H_
 
 #include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
diff --git a/third_party/blink/renderer/core/app_history/app_history_destination.h b/third_party/blink/renderer/core/app_history/app_history_destination.h
index ff6010d..35e2bb8 100644
--- a/third_party/blink/renderer/core/app_history/app_history_destination.h
+++ b/third_party/blink/renderer/core/app_history/app_history_destination.h
@@ -10,7 +10,6 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 
diff --git a/third_party/blink/renderer/core/app_history/app_history_entry.h b/third_party/blink/renderer/core/app_history/app_history_entry.h
index c0578772..d0199c73 100644
--- a/third_party/blink/renderer/core/app_history/app_history_entry.h
+++ b/third_party/blink/renderer/core/app_history/app_history_entry.h
@@ -8,7 +8,6 @@
 #include "third_party/blink/renderer/core/core_export.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/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 
diff --git a/third_party/blink/renderer/core/app_history/app_history_navigate_event.h b/third_party/blink/renderer/core/app_history/app_history_navigate_event.h
index d776ca0..bd2310f 100644
--- a/third_party/blink/renderer/core/app_history/app_history_navigate_event.h
+++ b/third_party/blink/renderer/core/app_history/app_history_navigate_event.h
@@ -11,7 +11,7 @@
 #include "third_party/blink/renderer/core/app_history/app_history.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
diff --git a/third_party/blink/renderer/core/clipboard/data_object.cc b/third_party/blink/renderer/core/clipboard/data_object.cc
index bc72cb1..d3fcc09 100644
--- a/third_party/blink/renderer/core/clipboard/data_object.cc
+++ b/third_party/blink/renderer/core/clipboard/data_object.cc
@@ -258,13 +258,13 @@
 }
 
 void DataObject::AddFileSharedBuffer(scoped_refptr<SharedBuffer> buffer,
-                                     bool is_accessible_from_start_frame,
+                                     bool is_image_accessible,
                                      const KURL& source_url,
                                      const String& filename_extension,
                                      const AtomicString& content_disposition) {
   InternalAddFileItem(DataObjectItem::CreateFromFileSharedBuffer(
-      std::move(buffer), is_accessible_from_start_frame, source_url,
-      filename_extension, content_disposition));
+      std::move(buffer), is_image_accessible, source_url, filename_extension,
+      content_disposition));
 }
 
 DataObject::DataObject() : modifiers_(0) {}
@@ -335,7 +335,7 @@
         break;
       case WebDragData::Item::kStorageTypeBinaryData:
         data_object->AddFileSharedBuffer(
-            item.binary_data, item.binary_data_accessible_from_start_frame,
+            item.binary_data, item.binary_data_image_accessible,
             item.binary_data_source_url, item.binary_data_filename_extension,
             item.binary_data_content_disposition);
         break;
@@ -379,8 +379,7 @@
       if (original_item->GetSharedBuffer()) {
         item.storage_type = WebDragData::Item::kStorageTypeBinaryData;
         item.binary_data = original_item->GetSharedBuffer();
-        item.binary_data_accessible_from_start_frame =
-            original_item->IsAccessibleFromStartFrame();
+        item.binary_data_image_accessible = original_item->IsImageAccessible();
         item.binary_data_source_url = original_item->BaseURL();
         item.binary_data_filename_extension =
             original_item->FilenameExtension();
diff --git a/third_party/blink/renderer/core/clipboard/data_object_item.cc b/third_party/blink/renderer/core/clipboard/data_object_item.cc
index 2db1904..1b85e6c 100644
--- a/third_party/blink/renderer/core/clipboard/data_object_item.cc
+++ b/third_party/blink/renderer/core/clipboard/data_object_item.cc
@@ -98,7 +98,7 @@
 // static
 DataObjectItem* DataObjectItem::CreateFromFileSharedBuffer(
     scoped_refptr<SharedBuffer> buffer,
-    bool is_accessible_from_start_frame,
+    bool is_image_accessible,
     const KURL& source_url,
     const String& filename_extension,
     const AtomicString& content_disposition) {
@@ -106,7 +106,7 @@
       kFileKind,
       MIMETypeRegistry::GetWellKnownMIMETypeForExtension(filename_extension));
   item->shared_buffer_ = std::move(buffer);
-  item->is_accessible_from_start_frame = is_accessible_from_start_frame;
+  item->is_image_accessible_ = is_image_accessible;
   item->filename_extension_ = filename_extension;
   // TODO(dcheng): Rename these fields to be more generically named.
   item->title_ = content_disposition;
@@ -157,6 +157,9 @@
 
     // If this file is not backed by |file_| then it must be a |shared_buffer_|.
     DCHECK(shared_buffer_);
+    // If dragged image is cross-origin, do not allow access to it.
+    if (!is_image_accessible_)
+      return nullptr;
     auto data = std::make_unique<BlobData>();
     data->SetContentType(type_);
     for (const auto& span : *shared_buffer_)
diff --git a/third_party/blink/renderer/core/clipboard/data_object_item.h b/third_party/blink/renderer/core/clipboard/data_object_item.h
index 31e44c13..95b6615 100644
--- a/third_party/blink/renderer/core/clipboard/data_object_item.h
+++ b/third_party/blink/renderer/core/clipboard/data_object_item.h
@@ -65,7 +65,7 @@
                                         const KURL& base_url);
   static DataObjectItem* CreateFromFileSharedBuffer(
       scoped_refptr<SharedBuffer>,
-      bool is_accessible_from_start_frame,
+      bool is_image_accessible,
       const KURL&,
       const String& file_extension,
       const AtomicString& content_disposition);
@@ -88,9 +88,7 @@
   // Used to support legacy DataTransfer APIs and renderer->browser
   // serialization.
   scoped_refptr<SharedBuffer> GetSharedBuffer() const { return shared_buffer_; }
-  bool IsAccessibleFromStartFrame() const {
-    return is_accessible_from_start_frame;
-  }
+  bool IsImageAccessible() const { return is_image_accessible_; }
   String FilenameExtension() const { return filename_extension_; }
   String Title() const { return title_; }
   KURL BaseURL() const { return base_url_; }
@@ -119,7 +117,7 @@
   String data_;
   Member<File> file_;
   scoped_refptr<SharedBuffer> shared_buffer_;
-  bool is_accessible_from_start_frame;
+  bool is_image_accessible_ = false;
   // Optional metadata. Currently used for URL, HTML, and dragging files in.
   String filename_extension_;
   String title_;
diff --git a/third_party/blink/renderer/core/content_capture/task_session.h b/third_party/blink/renderer/core/content_capture/task_session.h
index 1d610a1..52e0f8e3 100644
--- a/third_party/blink/renderer/core/content_capture/task_session.h
+++ b/third_party/blink/renderer/core/content_capture/task_session.h
@@ -14,7 +14,6 @@
 #include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/renderer/core/content_capture/content_holder.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
diff --git a/third_party/blink/renderer/core/core_initializer.cc b/third_party/blink/renderer/core/core_initializer.cc
index 280eb2c..d83b2dd4 100644
--- a/third_party/blink/renderer/core/core_initializer.cc
+++ b/third_party/blink/renderer/core/core_initializer.cc
@@ -62,6 +62,8 @@
 #include "third_party/blink/renderer/core/xml_names.h"
 #include "third_party/blink/renderer/core/xmlns_names.h"
 #include "third_party/blink/renderer/platform/font_family_names.h"
+#include "third_party/blink/renderer/platform/fonts/font_global_context.h"
+#include "third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
 #include "third_party/blink/renderer/platform/network/http_names.h"
 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
@@ -158,6 +160,10 @@
   BindingSecurity::Init();
 
   TimeZoneController::Init();
+
+  auto* name_lookup = FontGlobalContext::Get()->GetFontUniqueNameLookup();
+  if (name_lookup)
+    name_lookup->Init();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/active_style_sheets.h b/third_party/blink/renderer/core/css/active_style_sheets.h
index ce4d711..5735d06 100644
--- a/third_party/blink/renderer/core/css/active_style_sheets.h
+++ b/third_party/blink/renderer/core/css/active_style_sheets.h
@@ -7,6 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/media_value_change.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/css/build.gni b/third_party/blink/renderer/core/css/build.gni
index 058cc23..57abf1e 100644
--- a/third_party/blink/renderer/core/css/build.gni
+++ b/third_party/blink/renderer/core/css/build.gni
@@ -482,6 +482,8 @@
   "parser/font_variant_numeric_parser.h",
   "parser/media_query_parser.cc",
   "parser/media_query_parser.h",
+  "parser/container_query_parser.cc",
+  "parser/container_query_parser.h",
   "parser/sizes_attribute_parser.cc",
   "parser/sizes_attribute_parser.h",
   "parser/sizes_math_function_parser.cc",
@@ -718,6 +720,7 @@
   "parser/media_condition_test.cc",
   "parser/sizes_attribute_parser_test.cc",
   "parser/sizes_math_function_parser_test.cc",
+  "parser/container_query_parser_test.cc",
   "properties/computed_style_utils_test.cc",
   "properties/css_bitset_test.cc",
   "properties/css_exposure_test.cc",
diff --git a/third_party/blink/renderer/core/css/computed_style_css_value_mapping.h b/third_party/blink/renderer/core/css/computed_style_css_value_mapping.h
index 53ff7960..c1bd5ae 100644
--- a/third_party/blink/renderer/core/css/computed_style_css_value_mapping.h
+++ b/third_party/blink/renderer/core/css/computed_style_css_value_mapping.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_COMPUTED_STYLE_CSS_VALUE_MAPPING_H_
 
 #include "third_party/blink/renderer/core/css/css_value.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/css/container_query.cc b/third_party/blink/renderer/core/css/container_query.cc
index 387131f9..dde26450 100644
--- a/third_party/blink/renderer/core/css/container_query.cc
+++ b/third_party/blink/renderer/core/css/container_query.cc
@@ -4,21 +4,50 @@
 
 #include "third_party/blink/renderer/core/css/container_query.h"
 #include "third_party/blink/renderer/core/css/media_query_exp.h"
+#include "third_party/blink/renderer/core/style/computed_style_constants.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
 namespace blink {
 
-ContainerQuery::ContainerQuery(const AtomicString& name,
-                               scoped_refptr<MediaQuerySet> media_queries)
-    : name_(name),
-      media_queries_(media_queries),
-      queried_axes_(media_queries->QueriedAxes()) {}
+String ContainerSelector::ToString() const {
+  StringBuilder builder;
+
+  if (!name_.IsNull()) {
+    if (type_)
+      builder.Append("name(");
+    builder.Append(name_);
+    if (type_)
+      builder.Append(") ");
+  }
+
+  if (type_) {
+    builder.Append("type(");
+    if ((type_ & kContainerTypeSize) == kContainerTypeSize) {
+      builder.Append("size");
+    } else if (type_ & kContainerTypeInlineSize) {
+      builder.Append("inline-size");
+    } else if (type_ & kContainerTypeBlockSize) {
+      builder.Append("block-size");
+    }
+    builder.Append(")");
+  }
+
+  return builder.ReleaseString();
+}
+
+ContainerQuery::ContainerQuery(const ContainerSelector& selector,
+                               std::unique_ptr<MediaQueryExpNode> query)
+    : selector_(selector),
+      query_(std::move(query)),
+      queried_axes_(query_->QueriedAxes()) {}
 
 ContainerQuery::ContainerQuery(const ContainerQuery& other)
-    : media_queries_(other.media_queries_->Copy()),
+    : selector_(other.selector_),
+      query_(other.query_->Copy()),
       queried_axes_(other.queried_axes_) {}
 
 String ContainerQuery::ToString() const {
-  return media_queries_->MediaText();
+  return query_->Serialize();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/container_query.h b/third_party/blink/renderer/core/css/container_query.h
index f4aed0d..dd7b3c79 100644
--- a/third_party/blink/renderer/core/css/container_query.h
+++ b/third_party/blink/renderer/core/css/container_query.h
@@ -6,18 +6,45 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CONTAINER_QUERY_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/css/media_list.h"
+#include "third_party/blink/renderer/core/css/media_query_exp.h"
 #include "third_party/blink/renderer/core/layout/geometry/axis.h"
 
 namespace blink {
 
+// Not to be confused with regular selectors. This refers to container
+// selection by e.g. name() or type().
+//
+// https://drafts.csswg.org/css-contain-3/#container-rule
+class CORE_EXPORT ContainerSelector {
+ public:
+  ContainerSelector() = default;
+  ContainerSelector(const ContainerSelector&) = default;
+  explicit ContainerSelector(const AtomicString& name) : name_(name) {}
+  explicit ContainerSelector(unsigned type) : type_(type) {}
+  explicit ContainerSelector(const AtomicString& name, unsigned type)
+      : name_(name), type_(type) {}
+
+  bool IsNearest() const { return name_.IsNull() && type_ == 0; }
+
+  const AtomicString& Name() const { return name_; }
+  unsigned Type() const { return type_; }
+
+  String ToString() const;
+
+ private:
+  AtomicString name_;
+  // EContainerType
+  unsigned type_ = 0;
+};
+
 class CORE_EXPORT ContainerQuery final
     : public GarbageCollected<ContainerQuery> {
  public:
-  ContainerQuery(const AtomicString& name, scoped_refptr<MediaQuerySet>);
+  ContainerQuery(const ContainerSelector&,
+                 std::unique_ptr<MediaQueryExpNode> query);
   ContainerQuery(const ContainerQuery&);
 
-  const AtomicString& Name() const { return name_; }
+  const ContainerSelector& Selector() const { return selector_; }
   PhysicalAxes QueriedAxes() const { return queried_axes_; }
 
   String ToString() const;
@@ -30,11 +57,10 @@
   friend class CSSContainerRule;
   friend class StyleRuleContainer;
 
-  scoped_refptr<MediaQuerySet> MediaQueries() const { return media_queries_; }
+  const MediaQueryExpNode& Query() const { return *query_; }
 
-  AtomicString name_;
-  // TODO(crbug.com/1214810): Refactor to avoid internal MediaQuerySet.
-  scoped_refptr<MediaQuerySet> media_queries_;
+  ContainerSelector selector_;
+  std::unique_ptr<MediaQueryExpNode> query_;
   PhysicalAxes queried_axes_{kPhysicalAxisNone};
 };
 
diff --git a/third_party/blink/renderer/core/css/container_query_evaluator.cc b/third_party/blink/renderer/core/css/container_query_evaluator.cc
index 783d3ef6..31dec3c5 100644
--- a/third_party/blink/renderer/core/css/container_query_evaluator.cc
+++ b/third_party/blink/renderer/core/css/container_query_evaluator.cc
@@ -15,30 +15,6 @@
 
 namespace blink {
 
-// static
-Element* ContainerQueryEvaluator::FindContainer(
-    const StyleRecalcContext& context,
-    const AtomicString& container_name) {
-  Element* container = context.container;
-  if (!container)
-    return nullptr;
-
-  if (container_name == g_null_atom)
-    return container;
-
-  // TODO(crbug.com/1213888): Cache results.
-  for (Element* element = container; element;
-       element = LayoutTreeBuilderTraversal::ParentElement(*element)) {
-    if (const ComputedStyle* style = element->GetComputedStyle()) {
-      if (style->IsContainerForContainerQueries() &&
-          style->ContainerName() == container_name)
-        return element;
-    }
-  }
-
-  return nullptr;
-}
-
 namespace {
 
 bool IsSufficientlyContained(PhysicalAxes contained_axes,
@@ -46,8 +22,51 @@
   return (contained_axes & queried_axes) == queried_axes;
 }
 
+bool NameMatches(const ComputedStyle& style,
+                 const ContainerSelector& container_selector) {
+  const AtomicString& name = container_selector.Name();
+  return name.IsNull() || (style.ContainerName() == name);
+}
+
+bool TypeMatches(const ComputedStyle& style,
+                 const ContainerSelector& container_selector) {
+  unsigned type = container_selector.Type();
+  return !type || ((style.ContainerType() & type) == type);
+}
+
+bool Matches(const ComputedStyle& style,
+             const ContainerSelector& container_selector) {
+  return NameMatches(style, container_selector) &&
+         TypeMatches(style, container_selector);
+}
+
 }  // namespace
 
+// static
+Element* ContainerQueryEvaluator::FindContainer(
+    const StyleRecalcContext& context,
+    const ContainerSelector& container_selector) {
+  Element* container = context.container;
+  if (!container)
+    return nullptr;
+
+  if (container_selector.IsNearest())
+    return container;
+
+  // TODO(crbug.com/1213888): Cache results.
+  for (Element* element = container; element;
+       element = LayoutTreeBuilderTraversal::ParentElement(*element)) {
+    if (const ComputedStyle* style = element->GetComputedStyle()) {
+      if (style->IsContainerForContainerQueries() &&
+          Matches(*style, container_selector)) {
+        return element;
+      }
+    }
+  }
+
+  return nullptr;
+}
+
 double ContainerQueryEvaluator::Width() const {
   return size_.width.ToDouble();
 }
@@ -68,7 +87,8 @@
   if (!IsSufficientlyContained(contained_axes_, container_query.QueriedAxes()))
     return false;
   DCHECK(media_query_evaluator_);
-  return media_query_evaluator_->Eval(*container_query.media_queries_, results);
+  return media_query_evaluator_->Eval(*container_query.query_, results) ==
+         KleeneValue::kTrue;
 }
 
 void ContainerQueryEvaluator::Add(const ContainerQuery& query, bool result) {
@@ -146,7 +166,7 @@
 
   for (const auto& result : results_) {
     if (Eval(*result.key) != result.value) {
-      change = std::max(change, result.key->Name() == g_null_atom
+      change = std::max(change, result.key->Selector().IsNearest()
                                     ? Change::kNearestContainer
                                     : Change::kDescendantContainers);
     }
diff --git a/third_party/blink/renderer/core/css/container_query_evaluator.h b/third_party/blink/renderer/core/css/container_query_evaluator.h
index fde2daa..8066b2c 100644
--- a/third_party/blink/renderer/core/css/container_query_evaluator.h
+++ b/third_party/blink/renderer/core/css/container_query_evaluator.h
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/core/css/media_query_evaluator.h"
 #include "third_party/blink/renderer/core/layout/geometry/axis.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_size.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
@@ -19,12 +20,13 @@
 class Element;
 class MatchResult;
 class StyleRecalcContext;
+class ContainerSelector;
 
 class CORE_EXPORT ContainerQueryEvaluator final
     : public GarbageCollected<ContainerQueryEvaluator> {
  public:
   static Element* FindContainer(const StyleRecalcContext& context,
-                                const AtomicString& container_name);
+                                const ContainerSelector&);
 
   // Creates an evaluator with no containment, hence all queries evaluated
   // against it will fail.
diff --git a/third_party/blink/renderer/core/css/container_query_test.cc b/third_party/blink/renderer/core/css/container_query_test.cc
index 6e850aff..f95274e 100644
--- a/third_party/blink/renderer/core/css/container_query_test.cc
+++ b/third_party/blink/renderer/core/css/container_query_test.cc
@@ -27,9 +27,19 @@
  public:
   ContainerQueryTest() : ScopedCSSContainerQueriesForTest(true) {}
 
+  bool HasUnknown(StyleRuleContainer* rule) {
+    return rule && rule->GetContainerQuery().Query().HasUnknown();
+  }
+
+  // Note that these parsing utils treat "unknown" values as parse
+  // errors.
+  //
+  // https://drafts.csswg.org/mediaqueries-4/#evaluating
+
   StyleRuleContainer* ParseAtContainer(String rule_string) {
-    return DynamicTo<StyleRuleContainer>(
+    auto* rule = DynamicTo<StyleRuleContainer>(
         css_test_helpers::ParseRule(GetDocument(), rule_string));
+    return HasUnknown(rule) ? nullptr : rule;
   }
 
   ContainerQuery* ParseContainerQuery(String query) {
@@ -52,10 +62,8 @@
     return container->GetContainerQuery().ToString();
   }
 
-  // TODO(crbug.com/1145970): Remove this when ContainerQuery no longer
-  // relies on MediaQuerySet.
-  MediaQuerySet& GetMediaQuerySet(ContainerQuery& container_query) {
-    return *container_query.media_queries_;
+  const MediaQueryExpNode& GetInnerQuery(ContainerQuery& container_query) {
+    return container_query.Query();
   }
 
   const CSSValue* ComputedValue(Element* element, String property_name) {
@@ -99,16 +107,24 @@
   EXPECT_EQ(
       "(max-width: 500px)",
       SerializeCondition(ParseAtContainer("@container (max-width: 500px) {}")));
-
-  // TODO(crbug.com/1145970): The MediaQuery parser emits a "not all"
-  // MediaQuery for parse failures. When ContainerQuery has its own parser,
-  // it should probably return nullptr instead.
+  EXPECT_EQ("(not (max-width: 500px))",
+            SerializeCondition(
+                ParseAtContainer("@container (not (max-width: 500px)) {}")));
+  EXPECT_EQ("(max-width: 500px) and (max-height: 500px)",
+            SerializeCondition(ParseAtContainer(
+                "@container (max-width: 500px) and (max-height: 500px) {}")));
+  EXPECT_EQ("(max-width: 500px) or (max-height: 500px)",
+            SerializeCondition(ParseAtContainer(
+                "@container (max-width: 500px) or (max-height: 500px) {}")));
+  EXPECT_EQ(
+      "(width < 300px)",
+      SerializeCondition(ParseAtContainer("@container (width < 300px) {}")));
 
   // Invalid:
-  EXPECT_EQ("not all",
-            SerializeCondition(ParseAtContainer("@container 100px {}")));
-  EXPECT_EQ("not all",
-            SerializeCondition(ParseAtContainer("@container calc(1) {}")));
+  EXPECT_FALSE(ParseAtContainer("@container 100px {}"));
+  EXPECT_FALSE(ParseAtContainer("@container calc(1) {}"));
+  EXPECT_FALSE(ParseAtContainer("@container {}"));
+  EXPECT_FALSE(ParseAtContainer("@container (min-width: 300px) nonsense {}"));
 }
 
 TEST_F(ContainerQueryTest, RuleParsing) {
@@ -161,9 +177,9 @@
   // The ContainerQuery should be copied.
   EXPECT_NE(&container->GetContainerQuery(), &copy->GetContainerQuery());
 
-  // The inner MediaQuerySet should be copied.
-  EXPECT_NE(&GetMediaQuerySet(container->GetContainerQuery()),
-            &GetMediaQuerySet(copy->GetContainerQuery()));
+  // The inner MediaQueryExpNode should be copied.
+  EXPECT_NE(&GetInnerQuery(container->GetContainerQuery()),
+            &GetInnerQuery(copy->GetContainerQuery()));
 }
 
 TEST_F(ContainerQueryTest, ContainerQueryEvaluation) {
diff --git a/third_party/blink/renderer/core/css/counter_style.h b/third_party/blink/renderer/core/css/counter_style.h
index 003a50b..8065188 100644
--- a/third_party/blink/renderer/core/css/counter_style.h
+++ b/third_party/blink/renderer/core/css/counter_style.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_COUNTER_STYLE_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 
diff --git a/third_party/blink/renderer/core/css/counter_style_map.h b/third_party/blink/renderer/core/css/counter_style_map.h
index 226a851..dca90a8 100644
--- a/third_party/blink/renderer/core/css/counter_style_map.h
+++ b/third_party/blink/renderer/core/css/counter_style_map.h
@@ -7,6 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/counter_style.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
 
diff --git a/third_party/blink/renderer/core/css/css_container_rule.cc b/third_party/blink/renderer/core/css/css_container_rule.cc
index e1b62f28..1d10531 100644
--- a/third_party/blink/renderer/core/css/css_container_rule.cc
+++ b/third_party/blink/renderer/core/css/css_container_rule.cc
@@ -19,14 +19,13 @@
 String CSSContainerRule::cssText() const {
   StringBuilder result;
   result.Append("@container ");
-  if (!Name().IsNull()) {
-    result.Append(Name());
+  const ContainerSelector& selector = ContainerQuery().Selector();
+  if (!selector.IsNearest()) {
+    result.Append(selector.ToString());
     result.Append(' ');
   }
-  if (ContainerQueries()) {
-    result.Append(ContainerQueries()->MediaText());
-    result.Append(' ');
-  }
+  result.Append(ContainerQuery().ToString());
+  result.Append(' ');
   result.Append("{\n");
   AppendCSSTextForItems(result);
   result.Append('}');
@@ -34,11 +33,7 @@
 }
 
 const AtomicString& CSSContainerRule::Name() const {
-  return To<StyleRuleContainer>(group_rule_.Get())->GetContainerQuery().Name();
-}
-
-bool CSSContainerRule::IsEmpty() const {
-  return ContainerQueries()->QueryVector().IsEmpty();
+  return ContainerQuery().Selector().Name();
 }
 
 void CSSContainerRule::SetConditionText(
@@ -49,10 +44,8 @@
       ->SetConditionText(execution_context, value);
 }
 
-scoped_refptr<MediaQuerySet> CSSContainerRule::ContainerQueries() const {
-  return To<StyleRuleContainer>(group_rule_.Get())
-      ->GetContainerQuery()
-      .MediaQueries();
+const ContainerQuery& CSSContainerRule::ContainerQuery() const {
+  return To<StyleRuleContainer>(group_rule_.Get())->GetContainerQuery();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_container_rule.h b/third_party/blink/renderer/core/css/css_container_rule.h
index 9d21ce4..55dd56c 100644
--- a/third_party/blink/renderer/core/css/css_container_rule.h
+++ b/third_party/blink/renderer/core/css/css_container_rule.h
@@ -11,6 +11,7 @@
 namespace blink {
 
 class StyleRuleContainer;
+class ContainerQuery;
 
 class CSSContainerRule final : public CSSConditionRule {
   DEFINE_WRAPPERTYPEINFO();
@@ -22,12 +23,11 @@
   String cssText() const override;
 
   const AtomicString& Name() const;
-  bool IsEmpty() const;
   void SetConditionText(const ExecutionContext*, String);
 
  private:
   CSSRule::Type GetType() const override { return kContainerRule; }
-  scoped_refptr<MediaQuerySet> ContainerQueries() const;
+  const ContainerQuery& ContainerQuery() const;
 };
 
 template <>
diff --git a/third_party/blink/renderer/core/css/css_font_face.h b/third_party/blink/renderer/core/css/css_font_face.h
index 705ff8aa..97924a85 100644
--- a/third_party/blink/renderer/core/css/css_font_face.h
+++ b/third_party/blink/renderer/core/css/css_font_face.h
@@ -34,6 +34,8 @@
 #include "third_party/blink/renderer/core/css/font_face_source.h"
 #include "third_party/blink/renderer/platform/fonts/segmented_font_data.h"
 #include "third_party/blink/renderer/platform/fonts/unicode_range_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/core/css/css_image_generator_value.h b/third_party/blink/renderer/core/css/css_image_generator_value.h
index 5460a10b..723857af 100644
--- a/third_party/blink/renderer/core/css/css_image_generator_value.h
+++ b/third_party/blink/renderer/core/css/css_image_generator_value.h
@@ -34,6 +34,7 @@
 #include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
+#include "third_party/blink/renderer/platform/wtf/hash_counted_set.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/css/css_segmented_font_face.h b/third_party/blink/renderer/core/css/css_segmented_font_face.h
index f343ceb..dc106d1 100644
--- a/third_party/blink/renderer/core/css/css_segmented_font_face.h
+++ b/third_party/blink/renderer/core/css/css_segmented_font_face.h
@@ -30,6 +30,7 @@
 #include "third_party/blink/renderer/platform/fonts/font_cache_key.h"
 #include "third_party/blink/renderer/platform/fonts/font_selection_types.h"
 #include "third_party/blink/renderer/platform/fonts/segmented_font_data.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/lru_cache.h"
diff --git a/third_party/blink/renderer/core/css/css_style_sheet.h b/third_party/blink/renderer/core/css/css_style_sheet.h
index 88499100..efd86ef 100644
--- a/third_party/blink/renderer/core/css/css_style_sheet.h
+++ b/third_party/blink/renderer/core/css/css_style_sheet.h
@@ -28,8 +28,10 @@
 #include "third_party/blink/renderer/core/css/media_query_evaluator.h"
 #include "third_party/blink/renderer/core/css/style_sheet.h"
 #include "third_party/blink/renderer/core/dom/tree_scope.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_position.h"
 
diff --git a/third_party/blink/renderer/core/css/css_value.h b/third_party/blink/renderer/core/css/css_value.h
index 238f0151..95a7dca 100644
--- a/third_party/blink/renderer/core/css/css_value.h
+++ b/third_party/blink/renderer/core/css/css_value.h
@@ -23,6 +23,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/style/data_equivalency.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/custom_spaces.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
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 e7132b4..615e854 100644
--- a/third_party/blink/renderer/core/css/css_value_keywords.json5
+++ b/third_party/blink/renderer/core/css/css_value_keywords.json5
@@ -1331,6 +1331,10 @@
     "block-size",
     "inline-size",
 
+    // @container
+    "name",
+    "type",
+
     // grid auto-repeat
     "auto-fill",
     "auto-fit",
diff --git a/third_party/blink/renderer/core/css/css_value_pool.h b/third_party/blink/renderer/core/css/css_value_pool.h
index b7f63b9..0f96d859 100644
--- a/third_party/blink/renderer/core/css/css_value_pool.h
+++ b/third_party/blink/renderer/core/css/css_value_pool.h
@@ -45,6 +45,7 @@
 #include "third_party/blink/renderer/core/css/css_unset_value.h"
 #include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css_value_keywords.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
 
diff --git a/third_party/blink/renderer/core/css/cssom/css_transform_value.h b/third_party/blink/renderer/core/css/cssom/css_transform_value.h
index 2e0d968..9c321712 100644
--- a/third_party/blink/renderer/core/css/cssom/css_transform_value.h
+++ b/third_party/blink/renderer/core/css/cssom/css_transform_value.h
@@ -10,7 +10,7 @@
 #include "third_party/blink/renderer/core/css/cssom/css_transform_component.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/css/element_rule_collector.cc b/third_party/blink/renderer/core/css/element_rule_collector.cc
index 4784466..d43d913a 100644
--- a/third_party/blink/renderer/core/css/element_rule_collector.cc
+++ b/third_party/blink/renderer/core/css/element_rule_collector.cc
@@ -63,10 +63,10 @@
 }
 
 ContainerQueryEvaluator* FindContainerQueryEvaluator(
-    const AtomicString& name,
+    const ContainerSelector& selector,
     const StyleRecalcContext& style_recalc_context) {
-  if (auto* element =
-          ContainerQueryEvaluator::FindContainer(style_recalc_context, name)) {
+  if (auto* element = ContainerQueryEvaluator::FindContainer(
+          style_recalc_context, selector)) {
     return element->GetContainerQueryEvaluator();
   }
 
@@ -302,8 +302,8 @@
           result.dynamic_pseudo == kPseudoIdNone) {
         result_.SetDependsOnContainerQueries();
 
-        auto* evaluator = FindContainerQueryEvaluator(container_query->Name(),
-                                                      style_recalc_context_);
+        auto* evaluator = FindContainerQueryEvaluator(
+            container_query->Selector(), style_recalc_context_);
 
         if (!evaluator || !evaluator->EvalAndAdd(*container_query, result_)) {
           rejected++;
diff --git a/third_party/blink/renderer/core/css/font_face_set.h b/third_party/blink/renderer/core/css/font_face_set.h
index bb03fee..477fa05 100644
--- a/third_party/blink/renderer/core/css/font_face_set.h
+++ b/third_party/blink/renderer/core/css/font_face_set.h
@@ -16,6 +16,7 @@
 #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/fonts/font_selector.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/css/invalidation/node_invalidation_sets.h b/third_party/blink/renderer/core/css/invalidation/node_invalidation_sets.h
index 78254454..0d8ea7d5 100644
--- a/third_party/blink/renderer/core/css/invalidation/node_invalidation_sets.h
+++ b/third_party/blink/renderer/core/css/invalidation/node_invalidation_sets.h
@@ -6,7 +6,6 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_INVALIDATION_NODE_INVALIDATION_SETS_H_
 
 #include "third_party/blink/renderer/core/css/invalidation/invalidation_set.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/css/invalidation/pending_invalidations.h b/third_party/blink/renderer/core/css/invalidation/pending_invalidations.h
index 78105194..dcdfcff 100644
--- a/third_party/blink/renderer/core/css/invalidation/pending_invalidations.h
+++ b/third_party/blink/renderer/core/css/invalidation/pending_invalidations.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_INVALIDATION_PENDING_INVALIDATIONS_H_
 
 #include "third_party/blink/renderer/core/css/invalidation/node_invalidation_sets.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/css/media_query_list.h b/third_party/blink/renderer/core/css/media_query_list.h
index 31b65c5..7ed9f8ef 100644
--- a/third_party/blink/renderer/core/css/media_query_list.h
+++ b/third_party/blink/renderer/core/css/media_query_list.h
@@ -25,6 +25,7 @@
 #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/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
diff --git a/third_party/blink/renderer/core/css/media_query_matcher.h b/third_party/blink/renderer/core/css/media_query_matcher.h
index 1256c289..b2bc400 100644
--- a/third_party/blink/renderer/core/css/media_query_matcher.h
+++ b/third_party/blink/renderer/core/css/media_query_matcher.h
@@ -21,6 +21,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_MEDIA_QUERY_MATCHER_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
diff --git a/third_party/blink/renderer/core/css/parser/container_query_parser.cc b/third_party/blink/renderer/core/css/parser/container_query_parser.cc
new file mode 100644
index 0000000..3cd3e3d
--- /dev/null
+++ b/third_party/blink/renderer/core/css/parser/container_query_parser.cc
@@ -0,0 +1,103 @@
+// 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/core/css/parser/container_query_parser.h"
+#include "third_party/blink/renderer/core/css/css_identifier_value.h"
+#include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h"
+#include "third_party/blink/renderer/core/css/css_value_list.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
+#include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
+#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
+#include "third_party/blink/renderer/core/css/resolver/style_builder_converter.h"
+
+namespace blink {
+
+namespace {
+
+bool IsNone(const CSSValue& value) {
+  const auto* ident = DynamicTo<CSSIdentifierValue>(value);
+  return ident && ident->GetValueID() == CSSValueID::kNone;
+}
+
+AtomicString ConsumeContainerName(CSSParserTokenRange& range,
+                                  const CSSParserContext& context) {
+  CSSValue* name = css_parsing_utils::ConsumeContainerName(range, context);
+  if (auto* custom_ident = DynamicTo<CSSCustomIdentValue>(name))
+    return custom_ident->Value();
+  return g_null_atom;
+}
+
+unsigned ConsumeContainerType(CSSParserTokenRange& range) {
+  unsigned result = 0;
+  CSSValue* type = css_parsing_utils::ConsumeContainerType(range);
+  if (!type || IsNone(*type))
+    return kContainerTypeNone;
+  for (const CSSValue* item : To<CSSValueList>(*type))
+    result |= To<CSSIdentifierValue>(*item).ConvertTo<EContainerType>();
+  return result;
+}
+
+}  // namespace
+
+ContainerQueryParser::ContainerQueryParser(const CSSParserContext& context)
+    : context_(context),
+      media_query_parser_(MediaQueryParser::kMediaQuerySetParser,
+                          kHTMLStandardMode,
+                          context.GetExecutionContext(),
+                          MediaQueryParser::SyntaxLevel::kLevel4) {}
+
+absl::optional<ContainerSelector> ContainerQueryParser::ConsumeSelector(
+    CSSParserTokenRange& range) {
+  AtomicString bare_name = ConsumeContainerName(range, context_);
+  if (!bare_name.IsNull())
+    return ContainerSelector(bare_name);
+
+  absl::optional<AtomicString> name;
+  absl::optional<unsigned> type;
+
+  for (int i = 0; i < 2; i++) {
+    if (range.Peek().FunctionId() == CSSValueID::kName && !name) {
+      auto block = range.ConsumeBlock();
+      block.ConsumeWhitespace();
+      range.ConsumeWhitespace();
+      name = ConsumeContainerName(block, context_);
+      if (name->IsNull() || !block.AtEnd())
+        return absl::nullopt;
+      continue;
+    }
+
+    if (range.Peek().FunctionId() == CSSValueID::kType && !type) {
+      auto block = range.ConsumeBlock();
+      block.ConsumeWhitespace();
+      range.ConsumeWhitespace();
+      type = ConsumeContainerType(block);
+      if (!*type || !block.AtEnd())
+        return absl::nullopt;
+      continue;
+    }
+
+    break;
+  }
+
+  return ContainerSelector(name.value_or(g_null_atom), type.value_or(0));
+}
+
+std::unique_ptr<MediaQueryExpNode> ContainerQueryParser::ParseQuery(
+    String value) {
+  auto tokens = CSSTokenizer(value).TokenizeToEOF();
+  CSSParserTokenRange range(tokens);
+  return ParseQuery(range);
+}
+
+std::unique_ptr<MediaQueryExpNode> ContainerQueryParser::ParseQuery(
+    CSSParserTokenRange range) {
+  range.ConsumeWhitespace();
+  auto node = media_query_parser_.ConsumeCondition(range);
+  if (!range.AtEnd())
+    return nullptr;
+  return node;
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/parser/container_query_parser.h b/third_party/blink/renderer/core/css/parser/container_query_parser.h
new file mode 100644
index 0000000..40f42f9d
--- /dev/null
+++ b/third_party/blink/renderer/core/css/parser/container_query_parser.h
@@ -0,0 +1,38 @@
+// 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_CORE_CSS_PARSER_CONTAINER_QUERY_PARSER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PARSER_CONTAINER_QUERY_PARSER_H_
+
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/container_query.h"
+#include "third_party/blink/renderer/core/css/media_query_exp.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
+#include "third_party/blink/renderer/core/css/parser/media_query_parser.h"
+
+namespace blink {
+
+class CSSParserContext;
+
+class CORE_EXPORT ContainerQueryParser {
+  STACK_ALLOCATED();
+
+ public:
+  explicit ContainerQueryParser(const CSSParserContext&);
+
+  absl::optional<ContainerSelector> ConsumeSelector(CSSParserTokenRange&);
+
+  // https://drafts.csswg.org/css-contain-3/#typedef-container-query
+  std::unique_ptr<MediaQueryExpNode> ParseQuery(String);
+  std::unique_ptr<MediaQueryExpNode> ParseQuery(CSSParserTokenRange);
+
+ private:
+  const CSSParserContext& context_;
+  MediaQueryParser media_query_parser_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PARSER_CONTAINER_QUERY_PARSER_H_
diff --git a/third_party/blink/renderer/core/css/parser/container_query_parser_test.cc b/third_party/blink/renderer/core/css/parser/container_query_parser_test.cc
new file mode 100644
index 0000000..951cb13
--- /dev/null
+++ b/third_party/blink/renderer/core/css/parser/container_query_parser_test.cc
@@ -0,0 +1,59 @@
+// 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/core/css/parser/container_query_parser.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
+#include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+
+namespace blink {
+
+class ContainerQueryParserTest : public PageTestBase {
+ public:
+  String ParseSelector(String string) {
+    const auto* context = MakeGarbageCollected<CSSParserContext>(GetDocument());
+    auto tokens = CSSTokenizer(string).TokenizeToEOF();
+    CSSParserTokenRange range(tokens);
+    absl::optional<ContainerSelector> selector =
+        ContainerQueryParser(*context).ConsumeSelector(range);
+    if (!selector || !range.AtEnd())
+      return g_null_atom;
+    return selector->ToString();
+  }
+};
+
+TEST_F(ContainerQueryParserTest, ConsumeSelector) {
+  struct {
+    const char* input;
+    const char* output;
+  } valid_tests[] = {
+      {"foo", nullptr},
+      {"foo ", "foo"},
+      {"name(foo)", "foo"},
+      {"type(inline-size)", nullptr},
+      {"type(block-size)", nullptr},
+      {"type(size)", nullptr},
+      {"name(foo) type(inline-size)", nullptr},
+  };
+
+  for (const auto& test : valid_tests) {
+    String actual = ParseSelector(test.input);
+    String expected(test.output ? test.output : test.input);
+    EXPECT_EQ(expected, actual);
+  }
+
+  // Invalid:
+  EXPECT_EQ(g_null_atom, ParseSelector(" foo"));
+  EXPECT_EQ(g_null_atom, ParseSelector("name()"));
+  EXPECT_EQ(g_null_atom, ParseSelector("name(50px)"));
+  EXPECT_EQ(g_null_atom, ParseSelector("type()"));
+  EXPECT_EQ(g_null_atom, ParseSelector("type(unknown)"));
+  EXPECT_EQ(g_null_atom, ParseSelector("name(foo) name(bar)"));
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_impl.cc b/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
index 54cdb75f..3573a87 100644
--- a/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
+++ b/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/css/css_keyframes_rule.h"
 #include "third_party/blink/renderer/core/css/css_style_sheet.h"
 #include "third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.h"
+#include "third_party/blink/renderer/core/css/parser/container_query_parser.h"
 #include "third_party/blink/renderer/core/css/parser/css_at_rule_id.h"
 #include "third_party/blink/renderer/core/css/parser/css_lazy_parsing_state.h"
 #include "third_party/blink/renderer/core/css/parser/css_lazy_property_parser_impl.h"
@@ -67,14 +68,6 @@
   return result;
 }
 
-AtomicString ConsumeContainerName(CSSParserTokenRange& range,
-                                  const CSSParserContext& context) {
-  CSSValue* name = css_parsing_utils::ConsumeContainerName(range, context);
-  if (auto* custom_ident = DynamicTo<CSSCustomIdentValue>(name))
-    return custom_ident->Value();
-  return g_null_atom;
-}
-
 // Finds the longest prefix of |range| that matches a <layer-name> and parses
 // it. Returns an empty result with |range| unmodified if parsing fails.
 StyleRuleBase::LayerName ConsumeCascadeLayerName(CSSParserTokenRange& range) {
@@ -1070,16 +1063,18 @@
     observer_->StartRuleBody(stream.Offset());
   }
 
-  AtomicString name = ConsumeContainerName(prelude, *context_);
+  ContainerQueryParser query_parser(*context_);
 
-  // TODO(crbug.com/1145970): Restrict what is allowed by @container.
-  scoped_refptr<MediaQuerySet> media_queries =
-      MediaQueryParser::ParseMediaQuerySet(prelude,
-                                           context_->GetExecutionContext());
-  if (!media_queries)
+  absl::optional<ContainerSelector> selector =
+      query_parser.ConsumeSelector(prelude);
+  if (!selector)
+    return nullptr;
+
+  std::unique_ptr<MediaQueryExpNode> query = query_parser.ParseQuery(prelude);
+  if (!query)
     return nullptr;
   ContainerQuery* container_query =
-      MakeGarbageCollected<ContainerQuery>(name, media_queries);
+      MakeGarbageCollected<ContainerQuery>(*selector, std::move(query));
 
   HeapVector<Member<StyleRuleBase>> rules;
   ConsumeRuleList(stream, kRegularRuleList,
diff --git a/third_party/blink/renderer/core/css/parser/media_query_parser.cc b/third_party/blink/renderer/core/css/parser/media_query_parser.cc
index c563030..c92a6a1 100644
--- a/third_party/blink/renderer/core/css/parser/media_query_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/media_query_parser.cc
@@ -52,11 +52,13 @@
 
 MediaQueryParser::MediaQueryParser(ParserType parser_type,
                                    CSSParserMode mode,
-                                   const ExecutionContext* execution_context)
+                                   const ExecutionContext* execution_context,
+                                   SyntaxLevel syntax_level)
     : parser_type_(parser_type),
       query_set_(MediaQuerySet::Create()),
       mode_(mode),
       execution_context_(execution_context),
+      syntax_level_(syntax_level),
       fake_context_(*MakeGarbageCollected<CSSParserContext>(
           kHTMLStandardMode,
           SecureContextMode::kInsecureContext)) {}
@@ -257,7 +259,7 @@
     return std::make_unique<MediaQueryFeatureExpNode>(exp);
   }
 
-  if (!RuntimeEnabledFeatures::CSSMediaQueries4Enabled())
+  if (!IsMediaQueries4SyntaxEnabled())
     return nullptr;
 
   // Otherwise <mf-range>:
@@ -349,8 +351,7 @@
           MediaQueryExpNode::And(std::move(result), ConsumeInParens(range));
     }
   } else if (result && AtIdent(range.Peek(), "or") &&
-             mode == ConditionMode::kNormal &&
-             RuntimeEnabledFeatures::CSSMediaQueries4Enabled()) {
+             mode == ConditionMode::kNormal && IsMediaQueries4SyntaxEnabled()) {
     while (result && ConsumeIfIdent(range, "or")) {
       result = MediaQueryExpNode::Or(std::move(result), ConsumeInParens(range));
     }
@@ -365,7 +366,7 @@
 
   // ( <media-condition> )
   if (range.Peek().GetType() == kLeftParenthesisToken &&
-      RuntimeEnabledFeatures::CSSMediaQueries4Enabled()) {
+      IsMediaQueries4SyntaxEnabled()) {
     CSSParserTokenRange block = range.ConsumeBlock();
     block.ConsumeWhitespace();
     range.ConsumeWhitespace();
@@ -492,7 +493,16 @@
   // RuntimeEnabledFeatures::CSSMediaQueries4 existed, hence it's always
   // enabled for that parser type.
   return (parser_type_ == kMediaConditionParser) ||
-         RuntimeEnabledFeatures::CSSMediaQueries4Enabled();
+         IsMediaQueries4SyntaxEnabled();
+}
+
+bool MediaQueryParser::IsMediaQueries4SyntaxEnabled() const {
+  switch (syntax_level_) {
+    case SyntaxLevel::kAuto:
+      return RuntimeEnabledFeatures::CSSMediaQueries4Enabled();
+    case SyntaxLevel::kLevel4:
+      return true;
+  }
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/parser/media_query_parser.h b/third_party/blink/renderer/core/css/parser/media_query_parser.h
index 944d93d..859a632 100644
--- a/third_party/blink/renderer/core/css/parser/media_query_parser.h
+++ b/third_party/blink/renderer/core/css/parser/media_query_parser.h
@@ -18,6 +18,7 @@
 
 class MediaQuerySet;
 class CSSParserContext;
+class ContainerQueryParser;
 
 class CORE_EXPORT MediaQueryParser {
   STACK_ALLOCATED();
@@ -38,12 +39,24 @@
       const ExecutionContext*);
 
  private:
+  friend class ContainerQueryParser;
+
   enum ParserType {
     kMediaQuerySetParser,
     kMediaConditionParser,
   };
 
-  MediaQueryParser(ParserType, CSSParserMode, const ExecutionContext*);
+  enum class SyntaxLevel {
+    // Determined by CSSMediaQueries4 flag.
+    kAuto,
+    // Use mediaqueries-4 syntax regardless of flags.
+    kLevel4,
+  };
+
+  MediaQueryParser(ParserType,
+                   CSSParserMode,
+                   const ExecutionContext*,
+                   SyntaxLevel = SyntaxLevel::kAuto);
   MediaQueryParser(const MediaQueryParser&) = delete;
   MediaQueryParser& operator=(const MediaQueryParser&) = delete;
   virtual ~MediaQueryParser();
@@ -130,10 +143,16 @@
   // True if <media-not> is enabled.
   bool IsNotKeywordEnabled() const;
 
+  // Media Queries Level 4 added 'or', 'not', nesting, and ranges. These
+  // features are normally controlled by a runtime flag, but are always
+  // enabled by ContainerQueryParser.
+  bool IsMediaQueries4SyntaxEnabled() const;
+
   ParserType parser_type_;
   scoped_refptr<MediaQuerySet> query_set_;
   CSSParserMode mode_;
   const ExecutionContext* execution_context_;
+  SyntaxLevel syntax_level_;
   // A fake CSSParserContext for use counter only.
   // TODO(xiaochengh): Plumb the real CSSParserContext from the document.
   const CSSParserContext& fake_context_;
diff --git a/third_party/blink/renderer/core/css/properties/css_property.h b/third_party/blink/renderer/core/css/properties/css_property.h
index d95ce1d..c9b6fee 100644
--- a/third_party/blink/renderer/core/css/properties/css_property.h
+++ b/third_party/blink/renderer/core/css/properties/css_property.h
@@ -10,7 +10,6 @@
 #include "third_party/blink/renderer/core/css/css_value.h"
 #include "third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.h"
 #include "third_party/blink/renderer/core/css/properties/css_unresolved_property.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/text/writing_mode.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
diff --git a/third_party/blink/renderer/core/css/property_registry.h b/third_party/blink/renderer/core/css/property_registry.h
index 9c94f78..1df6009 100644
--- a/third_party/blink/renderer/core/css/property_registry.h
+++ b/third_party/blink/renderer/core/css/property_registry.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PROPERTY_REGISTRY_H_
 
 #include "third_party/blink/renderer/core/css/property_registration.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index 9771487..df6915fe 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -1282,7 +1282,8 @@
     Element* element,
     const AtomicString& container_name) {
   auto context = StyleRecalcContext::FromAncestors(*element);
-  return ContainerQueryEvaluator::FindContainer(context, container_name);
+  return ContainerQueryEvaluator::FindContainer(
+      context, ContainerSelector(container_name));
 }
 
 RuleIndexList* StyleResolver::PseudoCSSRulesForElement(
@@ -1723,10 +1724,8 @@
   if (!watched_selectors_rule_set)
     return;
 
-  // TODO(crbug.com/1145970): Use actual StyleRecalcContext.
-  StyleRecalcContext style_recalc_context;
   MatchResult match_result;
-  ElementRuleCollector collector(state.ElementContext(), style_recalc_context,
+  ElementRuleCollector collector(state.ElementContext(), StyleRecalcContext(),
                                  selector_filter_, match_result, state.Style(),
                                  state.Style()->InsideLink());
   collector.SetMode(SelectorChecker::kCollectingStyleRules);
diff --git a/third_party/blink/renderer/core/css/style_rule.cc b/third_party/blink/renderer/core/css/style_rule.cc
index bb6ae4b..d73ea79 100644
--- a/third_party/blink/renderer/core/css/style_rule.cc
+++ b/third_party/blink/renderer/core/css/style_rule.cc
@@ -37,6 +37,8 @@
 #include "third_party/blink/renderer/core/css/css_scroll_timeline_rule.h"
 #include "third_party/blink/renderer/core/css/css_style_rule.h"
 #include "third_party/blink/renderer/core/css/css_supports_rule.h"
+#include "third_party/blink/renderer/core/css/parser/container_query_parser.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
 #include "third_party/blink/renderer/core/css/style_rule_counter_style.h"
 #include "third_party/blink/renderer/core/css/style_rule_import.h"
 #include "third_party/blink/renderer/core/css/style_rule_keyframe.h"
@@ -588,9 +590,14 @@
 void StyleRuleContainer::SetConditionText(
     const ExecutionContext* execution_context,
     String value) {
-  if (container_query_->MediaQueries())
-    container_query_->MediaQueries()->Set(value, execution_context);
-  condition_text_ = container_query_->ToString();
+  auto* context = MakeGarbageCollected<CSSParserContext>(*execution_context);
+  ContainerQueryParser parser(*context);
+
+  if (auto exp_node = parser.ParseQuery(value)) {
+    condition_text_ = exp_node->Serialize();
+    container_query_ = MakeGarbageCollected<ContainerQuery>(
+        container_query_->Selector(), std::move(exp_node));
+  }
 }
 
 void StyleRuleContainer::TraceAfterDispatch(blink::Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
index d6efdce..3240860 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -3407,4 +3407,33 @@
   EXPECT_TRUE(HasSelection(context));
 }
 
+TEST_F(DisplayLockContextTest, BlockedReattachOfSlotted) {
+  GetDocument().body()->setInnerHTMLWithDeclarativeShadowDOMForTesting(R"HTML(
+    <div id="host">
+      <template shadowroot="open">
+        <style>
+          slot { display: block; }
+          .locked {
+            content-visibility: hidden;
+          }
+        </style>
+        <slot id="slot"></slot>
+      </template>
+      <span id="slotted"></span>
+    </div>
+  )HTML");
+  UpdateAllLifecyclePhasesForTest();
+
+  auto* host = GetDocument().getElementById("host");
+  auto* slotted = GetDocument().getElementById("slotted");
+  auto* slot = host->GetShadowRoot()->getElementById("slot");
+
+  EXPECT_TRUE(slot->GetLayoutObject());
+
+  slot->classList().Add("locked");
+  GetDocument().documentElement()->SetForceReattachLayoutTree();
+  UpdateAllLifecyclePhasesForTest();
+  EXPECT_FALSE(slotted->GetLayoutObject());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_document_state.h b/third_party/blink/renderer/core/display_lock/display_lock_document_state.h
index 3b6b77cb..0bd5e05 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_document_state.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_document_state.h
@@ -7,8 +7,8 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 
 namespace blink {
@@ -196,8 +196,8 @@
 
   // Contains all of the currently forced node infos, each of which represents
   // the node that caused the scope to be created.
-  VectorOf<ForcedNodeInfo> forced_node_infos_;
-  VectorOf<ForcedRangeInfo> forced_range_infos_;
+  HeapVector<ForcedNodeInfo> forced_node_infos_;
+  HeapVector<ForcedRangeInfo> forced_range_infos_;
 
   bool printing_ = false;
 
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
index d8b2950..c44d01f 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
@@ -796,7 +796,7 @@
   // Since setting the open attribute fires mutation events which could mess
   // with the FlatTreeTraversal iterator, we should first iterate details
   // elements to open and then open them all.
-  VectorOf<HTMLElement> elements_to_reveal;
+  HeapVector<Member<HTMLElement>> elements_to_reveal;
 
   for (Node& parent : FlatTreeTraversal::AncestorsOf(node)) {
     if (HTMLElement* element = DynamicTo<HTMLElement>(parent)) {
diff --git a/third_party/blink/renderer/core/dom/abort_signal.h b/third_party/blink/renderer/core/dom/abort_signal.h
index a9c77a34..7e9a6b16 100644
--- a/third_party/blink/renderer/core/dom/abort_signal.h
+++ b/third_party/blink/renderer/core/dom/abort_signal.h
@@ -8,7 +8,7 @@
 #include "base/callback_forward.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 3461bb0..edce656 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -70,6 +70,7 @@
 #include "third_party/blink/renderer/core/html/forms/listed_element.h"
 #include "third_party/blink/renderer/core/html/parser/parser_synchronization_policy.h"
 #include "third_party/blink/renderer/core/loader/font_preload_manager.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap_observer_set.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
diff --git a/third_party/blink/renderer/core/dom/document_parser.h b/third_party/blink/renderer/core/dom/document_parser.h
index 6799862..da85a20d 100644
--- a/third_party/blink/renderer/core/dom/document_parser.h
+++ b/third_party/blink/renderer/core/dom/document_parser.h
@@ -27,6 +27,7 @@
 #include <memory>
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
diff --git a/third_party/blink/renderer/core/dom/dom_exception.cc b/third_party/blink/renderer/core/dom/dom_exception.cc
index 27e3295..9eca533 100644
--- a/third_party/blink/renderer/core/dom/dom_exception.cc
+++ b/third_party/blink/renderer/core/dom/dom_exception.cc
@@ -28,6 +28,7 @@
 
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 
+#include "base/notreached.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 2dd8c127..8543f9a 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3628,8 +3628,13 @@
 
   SetNeedsStyleRecalc(kLocalStyleChange, StyleChangeReasonForTracing::Create(
                                              style_change_reason::kAnimation));
-  if (NeedsStyleRecalc())
+
+  // Setting this flag to 'true' only makes sense if there's an existing style,
+  // otherwise there is no previous style to use as the basis for the new one.
+  if (NeedsStyleRecalc() && GetComputedStyle() &&
+      !GetComputedStyle()->IsEnsuredInDisplayNone()) {
     SetAnimationStyleChange(true);
+  }
 }
 
 void Element::SetNeedsCompositingUpdate() {
diff --git a/third_party/blink/renderer/core/dom/element_data_cache.h b/third_party/blink/renderer/core/dom/element_data_cache.h
index f8d00e8..b495431 100644
--- a/third_party/blink/renderer/core/dom/element_data_cache.h
+++ b/third_party/blink/renderer/core/dom/element_data_cache.h
@@ -27,6 +27,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_ELEMENT_DATA_CACHE_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_ELEMENT_DATA_CACHE_H_
 
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
diff --git a/third_party/blink/renderer/core/dom/events/event.h b/third_party/blink/renderer/core/dom/events/event.h
index d6a612f..d4817f6 100644
--- a/third_party/blink/renderer/core/dom/events/event.h
+++ b/third_party/blink/renderer/core/dom/events/event.h
@@ -29,6 +29,7 @@
 #include "third_party/blink/renderer/core/dom/events/event_dispatch_result.h"
 #include "third_party/blink/renderer/core/probe/async_task_id.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 
diff --git a/third_party/blink/renderer/core/dom/events/event_listener_map.h b/third_party/blink/renderer/core/dom/events/event_listener_map.h
index 797ee13..8a6c42dc 100644
--- a/third_party/blink/renderer/core/dom/events/event_listener_map.h
+++ b/third_party/blink/renderer/core/dom/events/event_listener_map.h
@@ -36,6 +36,7 @@
 #include "base/dcheck_is_on.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/events/registered_event_listener.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/dom/events/event_queue.h b/third_party/blink/renderer/core/dom/events/event_queue.h
index 56f427f..99cdcb1 100644
--- a/third_party/blink/renderer/core/dom/events/event_queue.h
+++ b/third_party/blink/renderer/core/dom/events/event_queue.h
@@ -30,6 +30,7 @@
 #include "base/location.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/dom/id_target_observer_registry.h b/third_party/blink/renderer/core/dom/id_target_observer_registry.h
index 4d8b18ed..7ea4050e 100644
--- a/third_party/blink/renderer/core/dom/id_target_observer_registry.h
+++ b/third_party/blink/renderer/core/dom/id_target_observer_registry.h
@@ -27,10 +27,10 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_ID_TARGET_OBSERVER_REGISTRY_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/dom/live_node_list_registry.h b/third_party/blink/renderer/core/dom/live_node_list_registry.h
index ab9fc00..2e9a13c 100644
--- a/third_party/blink/renderer/core/dom/live_node_list_registry.h
+++ b/third_party/blink/renderer/core/dom/live_node_list_registry.h
@@ -9,7 +9,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
diff --git a/third_party/blink/renderer/core/dom/node_rare_data.h b/third_party/blink/renderer/core/dom/node_rare_data.h
index 97c9a47..9206c778 100644
--- a/third_party/blink/renderer/core/dom/node_rare_data.h
+++ b/third_party/blink/renderer/core/dom/node_rare_data.h
@@ -22,6 +22,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_NODE_RARE_DATA_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_NODE_RARE_DATA_H_
 
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
diff --git a/third_party/blink/renderer/core/dom/scripted_animation_controller.h b/third_party/blink/renderer/core/dom/scripted_animation_controller.h
index 7507e35..98d9d2c 100644
--- a/third_party/blink/renderer/core/dom/scripted_animation_controller.h
+++ b/third_party/blink/renderer/core/dom/scripted_animation_controller.h
@@ -30,6 +30,8 @@
 #include "third_party/blink/renderer/core/dom/frame_request_callback_collection.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
diff --git a/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h b/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h
index 0444edfe..45fd399 100644
--- a/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h
+++ b/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h"
 #include "third_party/blink/renderer/core/probe/async_task_id.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/timer.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/core/dom/slot_assignment.h b/third_party/blink/renderer/core/dom/slot_assignment.h
index 1e7bf79..78a0ffb 100644
--- a/third_party/blink/renderer/core/dom/slot_assignment.h
+++ b/third_party/blink/renderer/core/dom/slot_assignment.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_SLOT_ASSIGNMENT_H_
 
 #include "third_party/blink/renderer/core/dom/tree_ordered_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 
diff --git a/third_party/blink/renderer/core/dom/slot_assignment_engine.h b/third_party/blink/renderer/core/dom/slot_assignment_engine.h
index 7c0d862..9ca79dd 100644
--- a/third_party/blink/renderer/core/dom/slot_assignment_engine.h
+++ b/third_party/blink/renderer/core/dom/slot_assignment_engine.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_SLOT_ASSIGNMENT_ENGINE_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/dom/tree_ordered_list.h b/third_party/blink/renderer/core/dom/tree_ordered_list.h
index cf12572..4d070ea 100644
--- a/third_party/blink/renderer/core/dom/tree_ordered_list.h
+++ b/third_party/blink/renderer/core/dom/tree_ordered_list.h
@@ -31,8 +31,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_TREE_ORDERED_LIST_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/dom/tree_ordered_map.h b/third_party/blink/renderer/core/dom/tree_ordered_map.h
index c8431ac..e3132a3 100644
--- a/third_party/blink/renderer/core/dom/tree_ordered_map.h
+++ b/third_party/blink/renderer/core/dom/tree_ordered_map.h
@@ -34,6 +34,7 @@
 
 #include "base/dcheck_is_on.h"
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
diff --git a/third_party/blink/renderer/core/dom/user_action_element_set.h b/third_party/blink/renderer/core/dom/user_action_element_set.h
index 96b75d99..c30fff60 100644
--- a/third_party/blink/renderer/core/dom/user_action_element_set.h
+++ b/third_party/blink/renderer/core/dom/user_action_element_set.h
@@ -27,6 +27,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_USER_ACTION_ELEMENT_SET_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_USER_ACTION_ELEMENT_SET_H_
 
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
diff --git a/third_party/blink/renderer/core/dom/weak_identifier_map.h b/third_party/blink/renderer/core/dom/weak_identifier_map.h
index 0a30937..a24fe0c 100644
--- a/third_party/blink/renderer/core/dom/weak_identifier_map.h
+++ b/third_party/blink/renderer/core/dom/weak_identifier_map.h
@@ -6,10 +6,10 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_WEAK_IDENTIFIER_MAP_H_
 
 #include <limits>
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/editing/caret_display_item_client.cc b/third_party/blink/renderer/core/editing/caret_display_item_client.cc
index d5b5edc0..8e885463 100644
--- a/third_party/blink/renderer/core/editing/caret_display_item_client.cc
+++ b/third_party/blink/renderer/core/editing/caret_display_item_client.cc
@@ -268,7 +268,7 @@
   IntRect paint_rect = PixelSnappedIntRect(drawing_rect);
   context.FillRect(paint_rect, is_visible_if_active_ ? color_ : Color(),
                    PaintAutoDarkMode(layout_block_->StyleRef(),
-                                     DarkModeFilter::ElementRole::kText));
+                                     DarkModeFilter::ElementRole::kForeground));
 }
 
 void CaretDisplayItemClient::RecordSelection(
diff --git a/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.h b/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.h
index cd4c6139..17ae045f 100644
--- a/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.h
+++ b/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.h
@@ -31,6 +31,7 @@
 #include "third_party/blink/renderer/core/dom/range.h"
 #include "third_party/blink/renderer/core/editing/forward.h"
 #include "third_party/blink/renderer/core/editing/spellcheck/text_checking.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/core/execution_context/agent.h b/third_party/blink/renderer/core/execution_context/agent.h
index 914f11c..2a5c15d 100644
--- a/third_party/blink/renderer/core/execution_context/agent.h
+++ b/third_party/blink/renderer/core/execution_context/agent.h
@@ -10,7 +10,6 @@
 #include "base/unguessable_token.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "v8/include/v8.h"
 
diff --git a/third_party/blink/renderer/core/execution_context/window_agent_factory.h b/third_party/blink/renderer/core/execution_context/window_agent_factory.h
index 61a256d..b2bbb76 100644
--- a/third_party/blink/renderer/core/execution_context/window_agent_factory.h
+++ b/third_party/blink/renderer/core/execution_context/window_agent_factory.h
@@ -6,8 +6,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_WINDOW_AGENT_FACTORY_H_
 
 #include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin_hash.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/core/exported/web_form_element_observer_impl.h b/third_party/blink/renderer/core/exported/web_form_element_observer_impl.h
index f55f66d..752eb936 100644
--- a/third_party/blink/renderer/core/exported/web_form_element_observer_impl.h
+++ b/third_party/blink/renderer/core/exported/web_form_element_observer_impl.h
@@ -8,7 +8,6 @@
 #include "base/types/pass_key.h"
 #include "third_party/blink/public/web/modules/autofill/web_form_element_observer.h"
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
 
diff --git a/third_party/blink/renderer/core/fetch/bytes_consumer_tee.cc b/third_party/blink/renderer/core/fetch/bytes_consumer_tee.cc
index 865df14..fbda4f4a 100644
--- a/third_party/blink/renderer/core/fetch/bytes_consumer_tee.cc
+++ b/third_party/blink/renderer/core/fetch/bytes_consumer_tee.cc
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/core/fetch/blob_bytes_consumer.h"
 #include "third_party/blink/renderer/core/fetch/form_data_bytes_consumer.h"
 #include "third_party/blink/renderer/platform/blob/blob_data.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/loader/fetch/bytes_consumer.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
diff --git a/third_party/blink/renderer/core/fetch/fetch_manager.h b/third_party/blink/renderer/core/fetch/fetch_manager.h
index de95cc2..a2b72866 100644
--- a/third_party/blink/renderer/core/fetch/fetch_manager.h
+++ b/third_party/blink/renderer/core/fetch/fetch_manager.h
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/fileapi/public_url_manager.cc b/third_party/blink/renderer/core/fileapi/public_url_manager.cc
index eead04ff..b2a3c87 100644
--- a/third_party/blink/renderer/core/fileapi/public_url_manager.cc
+++ b/third_party/blink/renderer/core/fileapi/public_url_manager.cc
@@ -37,6 +37,7 @@
 #include "third_party/blink/renderer/platform/blob/blob_data.h"
 #include "third_party/blink/renderer/platform/blob/blob_url.h"
 #include "third_party/blink/renderer/platform/blob/blob_url_null_origin_map.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
diff --git a/third_party/blink/renderer/core/frame/ad_tracker.h b/third_party/blink/renderer/core/frame/ad_tracker.h
index 2cf8330..14c5e13c 100644
--- a/third_party/blink/renderer/core/frame/ad_tracker.h
+++ b/third_party/blink/renderer/core/frame/ad_tracker.h
@@ -9,10 +9,10 @@
 
 #include "base/feature_list.h"
 #include "third_party/blink/renderer/core/probe/async_task_id.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_info.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 #include "v8/include/v8.h"
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
index 52b6cf7..35e21f9 100644
--- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
+++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
@@ -574,6 +574,19 @@
              "' is used as a fallback.";
   }
 
+  // Wildcards match network schemes ('http', 'https', 'ws', 'wss'), and the
+  // scheme of the protected resource:
+  // https://w3c.github.io/webappsec-csp/#match-url-to-source-expression. Other
+  // schemes, including custom schemes, must be explicitly listed in a source
+  // list.
+  if (directive.source_list->allow_star) {
+    suffix = suffix +
+             " Note that '*' matches only URLs with network schemes ('http', "
+             "'https', 'ws', 'wss'), or URLs whose scheme matches `self`'s "
+             "scheme. " +
+             url.Protocol() + ":' must be added explicitely.";
+  }
+
   String raw_directive =
       GetRawDirectiveForMessage(csp.raw_directives, directive.type);
   ReportViolation(csp, policy, raw_directive, effective_type,
diff --git a/third_party/blink/renderer/core/frame/directive.cc b/third_party/blink/renderer/core/frame/directive.cc
index b0b5b1b..d2cf21c 100644
--- a/third_party/blink/renderer/core/frame/directive.cc
+++ b/third_party/blink/renderer/core/frame/directive.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/core/frame/directive.h"
 
+#include "base/notreached.h"
+
 namespace blink {
 
 Directive::Directive(Type type) : type_(type) {}
diff --git a/third_party/blink/renderer/core/frame/dom_timer_coordinator.h b/third_party/blink/renderer/core/frame/dom_timer_coordinator.h
index 342297e57..3ce83fde 100644
--- a/third_party/blink/renderer/core/frame/dom_timer_coordinator.h
+++ b/third_party/blink/renderer/core/frame/dom_timer_coordinator.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_DOM_TIMER_COORDINATOR_H_
 
 #include "base/task/single_thread_task_runner.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.h b/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.h
index b1baeae..16039cf 100644
--- a/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.h
+++ b/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.h
@@ -9,7 +9,6 @@
 
 #include "third_party/blink/public/web/web_frame_serializer.h"
 #include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/frame/fullscreen_controller.h b/third_party/blink/renderer/core/frame/fullscreen_controller.h
index 713a398..6a11f7e 100644
--- a/third_party/blink/renderer/core/frame/fullscreen_controller.h
+++ b/third_party/blink/renderer/core/frame/fullscreen_controller.h
@@ -34,7 +34,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/geometry/int_size.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "ui/gfx/geometry/point_f.h"
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
index e1fa20b..f434c969 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -52,6 +52,7 @@
 #include "third_party/blink/renderer/platform/storage/blink_storage_key.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.h b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.h
index d9f3be61..b92f80e 100644
--- a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.h
+++ b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.h
@@ -13,6 +13,7 @@
 #include "third_party/blink/public/mojom/media/fullscreen_video_element.mojom-blink.h"
 #include "third_party/blink/public/mojom/reporting/reporting.mojom-blink.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
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 aae32b8..80c016d4 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2526,13 +2526,17 @@
   DisallowLayoutInvalidationScope disallow_layout_invalidation(this);
 #endif
 
+  // This needs to be done prior to paint: it will update the cc::Layer bounds
+  // for the remote frame views, which will be wrapped during paint in
+  // ForeignLayerDisplayItem's whose visual rect is set at construction based
+  // on cc::Layer bounds.
+  ForAllRemoteFrameViews(
+      [](RemoteFrameView& frame_view) { frame_view.UpdateCompositingRect(); });
+
   DCHECK_EQ(target_state, DocumentLifecycle::kPaintClean);
   RunPaintLifecyclePhase(PaintBenchmarkMode::kNormal);
   DCHECK(ShouldThrottleRendering() || AnyFrameIsPrintingOrPaintingPreview() ||
          Lifecycle().GetState() == DocumentLifecycle::kPaintClean);
-
-  ForAllRemoteFrameViews(
-      [](RemoteFrameView& frame_view) { frame_view.UpdateCompositingRect(); });
 }
 
 bool LocalFrameView::RunScrollTimelineSteps() {
diff --git a/third_party/blink/renderer/core/frame/opened_frame_tracker.h b/third_party/blink/renderer/core/frame/opened_frame_tracker.h
index 8411255..b407af3f 100644
--- a/third_party/blink/renderer/core/frame/opened_frame_tracker.h
+++ b/third_party/blink/renderer/core/frame/opened_frame_tracker.h
@@ -5,9 +5,9 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_OPENED_FRAME_TRACKER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_OPENED_FRAME_TRACKER_H_
 
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/frame/pausable_script_executor.cc b/third_party/blink/renderer/core/frame/pausable_script_executor.cc
index c981c50..6a23505 100644
--- a/third_party/blink/renderer/core/frame/pausable_script_executor.cc
+++ b/third_party/blink/renderer/core/frame/pausable_script_executor.cc
@@ -25,8 +25,8 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/script/classic_script.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
diff --git a/third_party/blink/renderer/core/frame/platform_event_dispatcher.h b/third_party/blink/renderer/core/frame/platform_event_dispatcher.h
index f26ca35..6f45c50b 100644
--- a/third_party/blink/renderer/core/frame/platform_event_dispatcher.h
+++ b/third_party/blink/renderer/core/frame/platform_event_dispatcher.h
@@ -6,7 +6,9 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_PLATFORM_EVENT_DISPATCHER_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
 
 namespace blink {
 class PlatformEventController;
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc
index bb758c5..9b0cc05b 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -56,8 +56,8 @@
 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
 #include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
@@ -369,12 +369,6 @@
         .SetHasPointerEventsNone(IsIgnoredForHitTest());
   }
 
-  // If we now have a CC layer make sure its bounds match previously sent visual
-  // properties. This is necessary for the crash ui layer to be shown.
-  if (cc_layer_ && sent_visual_properties_) {
-    cc_layer_->SetBounds(sent_visual_properties_->local_frame_size);
-  }
-
   HTMLFrameOwnerElement* owner = To<HTMLFrameOwnerElement>(Owner());
   owner->SetNeedsCompositingUpdate();
 
@@ -970,17 +964,9 @@
 }
 
 bool RemoteFrame::SynchronizeVisualProperties(bool propagate) {
-  if (!GetFrameSinkId().is_valid())
+  if (!GetFrameSinkId().is_valid() || remote_process_gone_)
     return false;
 
-  // If the remote process is gone and we have new bounds adjust the
-  // crash ui layer so at least it tracks the new size.
-  if (remote_process_gone_) {
-    if (cc_layer_)
-      cc_layer_->SetBounds(pending_visual_properties_.local_frame_size);
-    return false;
-  }
-
   bool capture_sequence_number_changed =
       sent_visual_properties_ &&
       sent_visual_properties_->capture_sequence_number !=
@@ -1036,26 +1022,19 @@
 
   compositing_helper_->SetSurfaceId(surface_id,
                                     capture_sequence_number_changed);
-  DCHECK(cc_layer_);
-  // Note that in pre-CompositeAfterPaint, CompositedLayerMapping/GraphicsLayer
-  // will set the bounds again with the same value.
-  cc_layer_->SetBounds(pending_visual_properties_.local_frame_size);
 
   bool rect_changed = !sent_visual_properties_ ||
                       sent_visual_properties_->screen_space_rect !=
                           pending_visual_properties_.screen_space_rect;
   bool visual_properties_changed = synchronized_props_changed || rect_changed;
 
-  if (!visual_properties_changed)
-    return false;
-
-  if (propagate) {
+  if (visual_properties_changed && propagate) {
     GetRemoteFrameHostRemote().SynchronizeVisualProperties(
         pending_visual_properties_);
     RecordSentVisualProperties();
   }
 
-  return true;
+  return visual_properties_changed;
 }
 
 void RemoteFrame::RecordSentVisualProperties() {
@@ -1098,6 +1077,11 @@
       intersection_state.Clone(), visual_properties);
 }
 
+void RemoteFrame::UpdateCompositedLayerBounds() {
+  if (cc_layer_)
+    cc_layer_->SetBounds(pending_visual_properties_.local_frame_size);
+}
+
 void RemoteFrame::DidChangeScreenInfos(
     const display::ScreenInfos& screen_infos) {
   pending_visual_properties_.screen_infos = screen_infos;
diff --git a/third_party/blink/renderer/core/frame/remote_frame.h b/third_party/blink/renderer/core/frame/remote_frame.h
index 50ffc35..82608cf 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.h
+++ b/third_party/blink/renderer/core/frame/remote_frame.h
@@ -126,6 +126,7 @@
   bool SynchronizeVisualProperties(bool propagate = true);
   void ResendVisualProperties();
   void SetViewportIntersection(const mojom::blink::ViewportIntersectionState&);
+  void UpdateCompositedLayerBounds();
 
   // Called when the local root's screen infos change.
   void DidChangeScreenInfos(const display::ScreenInfos& screen_info);
diff --git a/third_party/blink/renderer/core/frame/remote_frame_view.cc b/third_party/blink/renderer/core/frame/remote_frame_view.cc
index 2c35962..c7bfcc1 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame_view.cc
@@ -110,7 +110,6 @@
   new_state.compositor_visible_rect = ToGfxRect(compositing_rect_);
   if (!last_intersection_state_.Equals(new_state)) {
     last_intersection_state_ = new_state;
-    GetFrame().SynchronizeVisualProperties();
     remote_frame_->SetViewportIntersection(new_state);
   } else if (needs_frame_rect_propagation_) {
     PropagateFrameRects();
@@ -128,6 +127,7 @@
 }
 
 void RemoteFrameView::UpdateCompositingRect() {
+  remote_frame_->UpdateCompositedLayerBounds();
   IntRect previous_rect = compositing_rect_;
   compositing_rect_ = IntRect();
   LocalFrameView* local_root_view = ParentLocalRootFrameView();
diff --git a/third_party/blink/renderer/core/frame/reporting_context.h b/third_party/blink/renderer/core/frame/reporting_context.h
index c2f7760..36b03122 100644
--- a/third_party/blink/renderer/core/frame/reporting_context.h
+++ b/third_party/blink/renderer/core/frame/reporting_context.h
@@ -9,6 +9,7 @@
 #include "third_party/blink/public/mojom/reporting/reporting.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
diff --git a/third_party/blink/renderer/core/frame/use_counter_impl.h b/third_party/blink/renderer/core/frame/use_counter_impl.h
index 05e2a97..029b26f5 100644
--- a/third_party/blink/renderer/core/frame/use_counter_impl.h
+++ b/third_party/blink/renderer/core/frame/use_counter_impl.h
@@ -33,6 +33,7 @@
 #include "third_party/blink/renderer/core/css/css_property_names.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_mode.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
diff --git a/third_party/blink/renderer/core/highlight/highlight.h b/third_party/blink/renderer/core/highlight/highlight.h
index d7b083c8..72f34eb 100644
--- a/third_party/blink/renderer/core/highlight/highlight.h
+++ b/third_party/blink/renderer/core/highlight/highlight.h
@@ -9,7 +9,8 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/abstract_range.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/highlight/highlight_registry.h b/third_party/blink/renderer/core/highlight/highlight_registry.h
index fc212467..9023b8c 100644
--- a/third_party/blink/renderer/core/highlight/highlight_registry.h
+++ b/third_party/blink/renderer/core/highlight/highlight_registry.h
@@ -10,7 +10,7 @@
 #include "third_party/blink/renderer/core/highlight/highlight.h"
 #include "third_party/blink/renderer/core/highlight/highlight_registry_map_entry.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
 
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 8aa0fe30..ffcb600 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -661,8 +661,8 @@
   if (had_resource_provider && old_size == new_size && IsRenderingContext2D()) {
     if (!canvas_is_clear_) {
       canvas_is_clear_ = true;
-      if (canvas2d_bridge_)
-        canvas2d_bridge_->ClearFrame();
+      if (ResourceProvider())
+        ResourceProvider()->ClearFrame();
       context_->ClearRect(0, 0, width(), height());
     }
     return;
@@ -858,12 +858,12 @@
     // display list or image snapshot. Display list allows better PDF printing
     // and we prefer this method.
     // Here are the requirements for display list to be used:
-    //    1. We must have had a full repaint of the Canvas after beginprint
+    //    1. We must have had a full repaint of the Canvas after beforeprint
     //       event has been fired. Otherwise, we don't have a PaintRecord.
     //    2. CSS property 'image-rendering' must not be 'pixelated'.
 
     // display list rendering: we replay the last full PaintRecord, if Canvas
-    // has been redraw since beginprint happened.
+    // has been redraw since beforeprint happened.
     if (IsPrinting() && IsRenderingContext2D() && canvas2d_bridge_) {
       canvas2d_bridge_->FlushRecording();
       if (canvas2d_bridge_->getLastRecord()) {
@@ -1475,7 +1475,7 @@
 
 ScriptPromise HTMLCanvasElement::CreateImageBitmap(
     ScriptState* script_state,
-    absl::optional<IntRect> crop_rect,
+    absl::optional<gfx::Rect> crop_rect,
     const ImageBitmapOptions* options,
     ExceptionState& exception_state) {
   return ImageBitmapSource::FulfillImageBitmap(
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
index e135b67..0fbe38c 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
@@ -238,7 +238,7 @@
   // ImageBitmapSource implementation
   IntSize BitmapSourceSize() const override;
   ScriptPromise CreateImageBitmap(ScriptState*,
-                                  absl::optional<IntRect> crop_rect,
+                                  absl::optional<gfx::Rect> crop_rect,
                                   const ImageBitmapOptions*,
                                   ExceptionState&) override;
 
diff --git a/third_party/blink/renderer/core/html/canvas/image_data.cc b/third_party/blink/renderer/core/html/canvas/image_data.cc
index cd56b35..645d84f5 100644
--- a/third_party/blink/renderer/core/html/canvas/image_data.cc
+++ b/third_party/blink/renderer/core/html/canvas/image_data.cc
@@ -288,7 +288,7 @@
 }
 
 ScriptPromise ImageData::CreateImageBitmap(ScriptState* script_state,
-                                           absl::optional<IntRect> crop_rect,
+                                           absl::optional<gfx::Rect> crop_rect,
                                            const ImageBitmapOptions* options,
                                            ExceptionState& exception_state) {
   if (IsBufferBaseDetached()) {
diff --git a/third_party/blink/renderer/core/html/canvas/image_data.h b/third_party/blink/renderer/core/html/canvas/image_data.h
index 08d00ff..fc9ae946 100644
--- a/third_party/blink/renderer/core/html/canvas/image_data.h
+++ b/third_party/blink/renderer/core/html/canvas/image_data.h
@@ -224,7 +224,7 @@
   // ImageBitmapSource implementation
   IntSize BitmapSourceSize() const override { return size_; }
   ScriptPromise CreateImageBitmap(ScriptState*,
-                                  absl::optional<IntRect> crop_rect,
+                                  absl::optional<gfx::Rect> crop_rect,
                                   const ImageBitmapOptions*,
                                   ExceptionState&) override;
 
diff --git a/third_party/blink/renderer/core/html/canvas/image_element_base.cc b/third_party/blink/renderer/core/html/canvas/image_element_base.cc
index 673d2a08..5b6d4ffa6 100644
--- a/third_party/blink/renderer/core/html/canvas/image_element_base.cc
+++ b/third_party/blink/renderer/core/html/canvas/image_element_base.cc
@@ -125,7 +125,7 @@
 }
 
 static bool HasDimensionsForImage(SVGImage* svg_image,
-                                  absl::optional<IntRect> crop_rect,
+                                  absl::optional<gfx::Rect> crop_rect,
                                   const ImageBitmapOptions* options) {
   if (!svg_image->ConcreteObjectSize(FloatSize()).IsEmpty())
     return true;
@@ -138,7 +138,7 @@
 
 ScriptPromise ImageElementBase::CreateImageBitmap(
     ScriptState* script_state,
-    absl::optional<IntRect> crop_rect,
+    absl::optional<gfx::Rect> crop_rect,
     const ImageBitmapOptions* options,
     ExceptionState& exception_state) {
   ImageResourceContent* image_content = CachedImage();
diff --git a/third_party/blink/renderer/core/html/canvas/image_element_base.h b/third_party/blink/renderer/core/html/canvas/image_element_base.h
index fb4af93..9b526f56 100644
--- a/third_party/blink/renderer/core/html/canvas/image_element_base.h
+++ b/third_party/blink/renderer/core/html/canvas/image_element_base.h
@@ -28,7 +28,7 @@
 
   IntSize BitmapSourceSize() const override;
   ScriptPromise CreateImageBitmap(ScriptState*,
-                                  absl::optional<IntRect>,
+                                  absl::optional<gfx::Rect>,
                                   const ImageBitmapOptions*,
                                   ExceptionState&) override;
 
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h b/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h
index 5da2b00..2b8cc343 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h
+++ b/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h
@@ -7,6 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_upgrade_sorter.h b/third_party/blink/renderer/core/html/custom/custom_element_upgrade_sorter.h
index 12aba6e..658685d3 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_upgrade_sorter.h
+++ b/third_party/blink/renderer/core/html/custom/custom_element_upgrade_sorter.h
@@ -6,6 +6,9 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_UPGRADE_SORTER_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/html/forms/radio_button_group_scope.h b/third_party/blink/renderer/core/html/forms/radio_button_group_scope.h
index 8205162..43550f7 100644
--- a/third_party/blink/renderer/core/html/forms/radio_button_group_scope.h
+++ b/third_party/blink/renderer/core/html/forms/radio_button_group_scope.h
@@ -21,9 +21,9 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_RADIO_BUTTON_GROUP_SCOPE_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_RADIO_BUTTON_GROUP_SCOPE_H_
 
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/html/html_details_element.cc b/third_party/blink/renderer/core/html/html_details_element.cc
index 45d74e88..6474712 100644
--- a/third_party/blink/renderer/core/html/html_details_element.cc
+++ b/third_party/blink/renderer/core/html/html_details_element.cc
@@ -221,7 +221,7 @@
   // Since setting the open attribute fires mutation events which could mess
   // with the FlatTreeTraversal iterator, we should first iterate details
   // elements to open and then open them all.
-  VectorOf<HTMLDetailsElement> details_to_open;
+  HeapVector<Member<HTMLDetailsElement>> details_to_open;
 
   for (Node& parent : FlatTreeTraversal::AncestorsOf(node)) {
     if (HTMLDetailsElement* details = DynamicTo<HTMLDetailsElement>(parent)) {
diff --git a/third_party/blink/renderer/core/html/html_frame_owner_element.cc b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
index b7c229e4..07e51b5 100644
--- a/third_party/blink/renderer/core/html/html_frame_owner_element.cc
+++ b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
@@ -58,7 +58,6 @@
 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
 #include "third_party/blink/renderer/core/timing/window_performance.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/network/network_state_notifier.h"
diff --git a/third_party/blink/renderer/core/html/html_image_element.h b/third_party/blink/renderer/core/html/html_image_element.h
index 3d6b773..ae0c6c4 100644
--- a/third_party/blink/renderer/core/html/html_image_element.h
+++ b/third_party/blink/renderer/core/html/html_image_element.h
@@ -37,7 +37,6 @@
 #include "third_party/blink/renderer/platform/geometry/int_size.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_types.h"
 #include "third_party/blink/renderer/platform/graphics/image_orientation.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
 
diff --git a/third_party/blink/renderer/core/html/html_slot_element.cc b/third_party/blink/renderer/core/html/html_slot_element.cc
index cbaf036a..7f12ee7d 100644
--- a/third_party/blink/renderer/core/html/html_slot_element.cc
+++ b/third_party/blink/renderer/core/html/html_slot_element.cc
@@ -319,6 +319,9 @@
 void HTMLSlotElement::AttachLayoutTree(AttachContext& context) {
   HTMLElement::AttachLayoutTree(context);
 
+  if (ChildStyleRecalcBlockedByDisplayLock())
+    return;
+
   if (SupportsAssignment()) {
     LayoutObject* layout_object = GetLayoutObject();
     AttachContext children_context(context);
diff --git a/third_party/blink/renderer/core/html/lazy_load_frame_observer.h b/third_party/blink/renderer/core/html/lazy_load_frame_observer.h
index 32ba21826..1aa0c011 100644
--- a/third_party/blink/renderer/core/html/lazy_load_frame_observer.h
+++ b/third_party/blink/renderer/core/html/lazy_load_frame_observer.h
@@ -8,8 +8,8 @@
 #include <memory>
 
 #include "third_party/blink/public/web/web_frame_load_type.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 
diff --git a/third_party/blink/renderer/core/html/lazy_load_image_observer.h b/third_party/blink/renderer/core/html/lazy_load_image_observer.h
index 7f19c88..f597f8a2 100644
--- a/third_party/blink/renderer/core/html/lazy_load_image_observer.h
+++ b/third_party/blink/renderer/core/html/lazy_load_image_observer.h
@@ -5,8 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_LAZY_LOAD_IMAGE_OBSERVER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_LAZY_LOAD_IMAGE_OBSERVER_H_
 
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.cc b/third_party/blink/renderer/core/html/media/html_video_element.cc
index bcf4235..294e5e2 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_video_element.cc
@@ -587,7 +587,7 @@
 
 ScriptPromise HTMLVideoElement::CreateImageBitmap(
     ScriptState* script_state,
-    absl::optional<IntRect> crop_rect,
+    absl::optional<gfx::Rect> crop_rect,
     const ImageBitmapOptions* options,
     ExceptionState& exception_state) {
   if (getNetworkState() == HTMLMediaElement::kNetworkEmpty) {
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.h b/third_party/blink/renderer/core/html/media/html_video_element.h
index 4296694..132a032 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.h
+++ b/third_party/blink/renderer/core/html/media/html_video_element.h
@@ -126,7 +126,7 @@
   // ImageBitmapSource implementation
   IntSize BitmapSourceSize() const override;
   ScriptPromise CreateImageBitmap(ScriptState*,
-                                  absl::optional<IntRect> crop_rect,
+                                  absl::optional<gfx::Rect> crop_rect,
                                   const ImageBitmapOptions*,
                                   ExceptionState&) override;
 
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.cc b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
index 15497e4..8be87ab7 100644
--- a/third_party/blink/renderer/core/html/parser/html_document_parser.cc
+++ b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
@@ -1052,7 +1052,7 @@
   }
 
 
-  if (IsStopped()) {
+  if (IsStopped() || IsParsingFragment()) {
     if (metrics_reporter_ && tokens_parsed) {
       metrics_reporter_->AddChunk(chunk_parsing_timer_.Elapsed(),
                                   tokens_parsed);
@@ -1500,6 +1500,14 @@
 }
 
 bool HTMLDocumentParser::IsWaitingForScripts() const {
+  if (IsParsingFragment()) {
+    // HTMLTreeBuilder may have a parser blocking script element, but we
+    // ignore it during fragment parsing.
+    DCHECK(!(tree_builder_->HasParserBlockingScript() || (script_runner_ &&
+    script_runner_->HasParserBlockingScript()) || reentry_permit_->ParserPauseFlag()));
+    return false;
+  }
+
   // When the TreeBuilder encounters a </script> tag, it returns to the
   // HTMLDocumentParser where the script is transfered from the treebuilder to
   // the script runner. The script runner will hold the script until its loaded
diff --git a/third_party/blink/renderer/core/html/portal/portal_activate_event.h b/third_party/blink/renderer/core/html/portal/portal_activate_event.h
index c0576bc..a1cad919 100644
--- a/third_party/blink/renderer/core/html/portal/portal_activate_event.h
+++ b/third_party/blink/renderer/core/html/portal/portal_activate_event.h
@@ -19,7 +19,6 @@
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
index f83a84e..b404bad77 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
@@ -53,25 +53,8 @@
 
 namespace {
 
-// The following two functions are helpers used in cropImage
-static inline IntRect NormalizeRect(const IntRect& rect) {
-  int x = rect.x();
-  int y = rect.y();
-  int width = rect.width();
-  int height = rect.height();
-  if (width < 0) {
-    x = base::ClampAdd(x, width);
-    width = -width;
-  }
-  if (height < 0) {
-    y = base::ClampAdd(y, height);
-    height = -height;
-  }
-  return IntRect(x, y, width, height);
-}
-
 ImageBitmap::ParsedOptions ParseOptions(const ImageBitmapOptions* options,
-                                        absl::optional<IntRect> crop_rect,
+                                        absl::optional<gfx::Rect> crop_rect,
                                         IntSize source_size) {
   ImageBitmap::ParsedOptions parsed_options;
   if (options->imageOrientation() == kImageOrientationFlipY) {
@@ -101,9 +84,9 @@
   int source_width = source_size.width();
   int source_height = source_size.height();
   if (!crop_rect) {
-    parsed_options.crop_rect = IntRect(0, 0, source_width, source_height);
+    parsed_options.crop_rect = gfx::Rect(0, 0, source_width, source_height);
   } else {
-    parsed_options.crop_rect = NormalizeRect(*crop_rect);
+    parsed_options.crop_rect = *crop_rect;
   }
   if (!options->hasResizeWidth() && !options->hasResizeHeight()) {
     parsed_options.resize_width = parsed_options.crop_rect.width();
@@ -512,7 +495,7 @@
 }
 
 ImageBitmap::ImageBitmap(ImageElementBase* image,
-                         absl::optional<IntRect> crop_rect,
+                         absl::optional<gfx::Rect> crop_rect,
                          const ImageBitmapOptions* options) {
   scoped_refptr<Image> input = image->CachedImage()->GetImage();
   DCHECK(!input->IsTextureBacked());
@@ -581,7 +564,7 @@
 }
 
 ImageBitmap::ImageBitmap(HTMLVideoElement* video,
-                         absl::optional<IntRect> crop_rect,
+                         absl::optional<gfx::Rect> crop_rect,
                          const ImageBitmapOptions* options) {
   ParsedOptions parsed_options =
       ParseOptions(options, crop_rect, video->BitmapSourceSize());
@@ -607,7 +590,7 @@
 }
 
 ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas,
-                         absl::optional<IntRect> crop_rect,
+                         absl::optional<gfx::Rect> crop_rect,
                          const ImageBitmapOptions* options) {
   SourceImageStatus status;
   scoped_refptr<Image> image_input =
@@ -633,7 +616,7 @@
 }
 
 ImageBitmap::ImageBitmap(OffscreenCanvas* offscreen_canvas,
-                         absl::optional<IntRect> crop_rect,
+                         absl::optional<gfx::Rect> crop_rect,
                          const ImageBitmapOptions* options) {
   SourceImageStatus status;
   scoped_refptr<Image> raw_input = offscreen_canvas->GetSourceImageForCanvas(
@@ -672,7 +655,7 @@
 }
 
 ImageBitmap::ImageBitmap(ImageData* data,
-                         absl::optional<IntRect> crop_rect,
+                         absl::optional<gfx::Rect> crop_rect,
                          const ImageBitmapOptions* options) {
   ParsedOptions parsed_options =
       ParseOptions(options, crop_rect, data->BitmapSourceSize());
@@ -753,7 +736,7 @@
 }
 
 ImageBitmap::ImageBitmap(ImageBitmap* bitmap,
-                         absl::optional<IntRect> crop_rect,
+                         absl::optional<gfx::Rect> crop_rect,
                          const ImageBitmapOptions* options) {
   scoped_refptr<StaticBitmapImage> input = bitmap->BitmapImage();
   if (!input)
@@ -776,7 +759,7 @@
 }
 
 ImageBitmap::ImageBitmap(scoped_refptr<StaticBitmapImage> image,
-                         absl::optional<IntRect> crop_rect,
+                         absl::optional<gfx::Rect> crop_rect,
                          const ImageBitmapOptions* options) {
   bool origin_clean = image->OriginClean();
   ParsedOptions parsed_options =
@@ -894,7 +877,7 @@
 }
 
 ScriptPromise ImageBitmap::CreateAsync(ImageElementBase* image,
-                                       absl::optional<IntRect> crop_rect,
+                                       absl::optional<gfx::Rect> crop_rect,
                                        ScriptState* script_state,
                                        const ImageBitmapOptions* options) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
@@ -916,7 +899,7 @@
   // In the case when |crop_rect| doesn't intersect the source image, we return
   // a transparent black image, respecting the color_params but ignoring
   // premultiply_alpha.
-  if (!parsed_options.crop_rect.Intersects(input_rect)) {
+  if (!parsed_options.crop_rect.Intersects(ToGfxRect(input_rect))) {
     ImageBitmap* bitmap =
         MakeGarbageCollected<ImageBitmap>(MakeBlankImage(parsed_options));
     if (bitmap->BitmapImage()) {
@@ -1009,10 +992,11 @@
   return image_->PreferredDisplaySize();
 }
 
-ScriptPromise ImageBitmap::CreateImageBitmap(ScriptState* script_state,
-                                             absl::optional<IntRect> crop_rect,
-                                             const ImageBitmapOptions* options,
-                                             ExceptionState& exception_state) {
+ScriptPromise ImageBitmap::CreateImageBitmap(
+    ScriptState* script_state,
+    absl::optional<gfx::Rect> crop_rect,
+    const ImageBitmapOptions* options,
+    ExceptionState& exception_state) {
   return ImageBitmapSource::FulfillImageBitmap(
       script_state, MakeGarbageCollected<ImageBitmap>(this, crop_rect, options),
       exception_state);
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap.h b/third_party/blink/renderer/core/imagebitmap/image_bitmap.h
index d16b5b7..d40e0ab 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap.h
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap.h
@@ -13,7 +13,6 @@
 #include "third_party/blink/renderer/core/html/canvas/canvas_image_source.h"
 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/geometry/int_rect.h"
 #include "third_party/blink/renderer/platform/graphics/image.h"
 #include "third_party/blink/renderer/platform/graphics/image_orientation.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_record.h"
@@ -21,6 +20,7 @@
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
+#include "ui/gfx/geometry/rect.h"
 
 namespace blink {
 class HTMLCanvasElement;
@@ -39,32 +39,32 @@
   // Expects the ImageElementBase to return/have an SVGImage.
   static ScriptPromise CreateAsync(
       ImageElementBase*,
-      absl::optional<IntRect>,
+      absl::optional<gfx::Rect>,
       ScriptState*,
       const ImageBitmapOptions* = ImageBitmapOptions::Create());
   static sk_sp<SkImage> GetSkImageFromDecoder(std::unique_ptr<ImageDecoder>);
 
   ImageBitmap(ImageElementBase*,
-              absl::optional<IntRect>,
+              absl::optional<gfx::Rect>,
               const ImageBitmapOptions* = ImageBitmapOptions::Create());
   ImageBitmap(HTMLVideoElement*,
-              absl::optional<IntRect>,
+              absl::optional<gfx::Rect>,
               const ImageBitmapOptions* = ImageBitmapOptions::Create());
   ImageBitmap(HTMLCanvasElement*,
-              absl::optional<IntRect>,
+              absl::optional<gfx::Rect>,
               const ImageBitmapOptions* = ImageBitmapOptions::Create());
   ImageBitmap(OffscreenCanvas*,
-              absl::optional<IntRect>,
+              absl::optional<gfx::Rect>,
               const ImageBitmapOptions* = ImageBitmapOptions::Create());
   ImageBitmap(ImageData*,
-              absl::optional<IntRect>,
+              absl::optional<gfx::Rect>,
               const ImageBitmapOptions* = ImageBitmapOptions::Create());
   ImageBitmap(ImageBitmap*,
-              absl::optional<IntRect>,
+              absl::optional<gfx::Rect>,
               const ImageBitmapOptions* = ImageBitmapOptions::Create());
   ImageBitmap(scoped_refptr<StaticBitmapImage>);
   ImageBitmap(scoped_refptr<StaticBitmapImage>,
-              absl::optional<IntRect>,
+              absl::optional<gfx::Rect>,
               const ImageBitmapOptions* = ImageBitmapOptions::Create());
   // This constructor may called by structured-cloning an ImageBitmap.
   // isImageBitmapOriginClean indicates whether the original ImageBitmap is
@@ -112,7 +112,7 @@
   // ImageBitmapSource implementation
   IntSize BitmapSourceSize() const override { return Size(); }
   ScriptPromise CreateImageBitmap(ScriptState*,
-                                  absl::optional<IntRect>,
+                                  absl::optional<gfx::Rect>,
                                   const ImageBitmapOptions*,
                                   ExceptionState&) override;
 
@@ -124,7 +124,7 @@
     bool source_is_unpremul = false;
     unsigned resize_width = 0;
     unsigned resize_height = 0;
-    IntRect crop_rect;
+    gfx::Rect crop_rect;
     cc::PaintFlags::FilterQuality resize_quality =
         cc::PaintFlags::FilterQuality::kLow;
   };
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_source.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap_source.cc
index b689e98..864a95e3 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_source.cc
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_source.cc
@@ -31,7 +31,7 @@
 
 ScriptPromise ImageBitmapSource::CreateImageBitmap(
     ScriptState* script_state,
-    absl::optional<IntRect> crop_rect,
+    absl::optional<gfx::Rect> crop_rect,
     const ImageBitmapOptions* options,
     ExceptionState& exception_state) {
   return ScriptPromise();
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h b/third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h
index 4028daef..b50bdbb 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h
@@ -10,9 +10,9 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/geometry/int_rect.h"
 #include "third_party/blink/renderer/platform/geometry/int_size.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "ui/gfx/geometry/rect.h"
 
 namespace blink {
 
@@ -25,7 +25,7 @@
  public:
   virtual IntSize BitmapSourceSize() const { return IntSize(); }
   virtual ScriptPromise CreateImageBitmap(ScriptState*,
-                                          absl::optional<IntRect>,
+                                          absl::optional<gfx::Rect>,
                                           const ImageBitmapOptions*,
                                           ExceptionState&);
 
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
index b889cc7..8ca933d 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
@@ -118,23 +118,25 @@
           UnacceleratedStaticBitmapImage::Create(image).get());
   image_element->SetImageForTest(original_image_content);
 
-  absl::optional<IntRect> crop_rect =
-      IntRect(0, 0, image_element->width(), image_element->height());
+  absl::optional<gfx::Rect> crop_rect =
+      gfx::Rect(0, 0, image_element->width(), image_element->height());
   auto* image_bitmap_no_crop = MakeGarbageCollected<ImageBitmap>(
       image_element, crop_rect, default_options);
   ASSERT_TRUE(image_bitmap_no_crop);
-  crop_rect = IntRect(image_element->width() / 2, image_element->height() / 2,
-                      image_element->width() / 2, image_element->height() / 2);
+  crop_rect =
+      gfx::Rect(image_element->width() / 2, image_element->height() / 2,
+                image_element->width() / 2, image_element->height() / 2);
   auto* image_bitmap_interior_crop = MakeGarbageCollected<ImageBitmap>(
       image_element, crop_rect, default_options);
   ASSERT_TRUE(image_bitmap_interior_crop);
-  crop_rect = IntRect(-image_element->width() / 2, -image_element->height() / 2,
-                      image_element->width(), image_element->height());
+  crop_rect =
+      gfx::Rect(-image_element->width() / 2, -image_element->height() / 2,
+                image_element->width(), image_element->height());
   auto* image_bitmap_exterior_crop = MakeGarbageCollected<ImageBitmap>(
       image_element, crop_rect, default_options);
   ASSERT_TRUE(image_bitmap_exterior_crop);
-  crop_rect = IntRect(-image_element->width(), -image_element->height(),
-                      image_element->width(), image_element->height());
+  crop_rect = gfx::Rect(-image_element->width(), -image_element->height(),
+                        image_element->width(), image_element->height());
   auto* image_bitmap_outside_crop = MakeGarbageCollected<ImageBitmap>(
       image_element, crop_rect, default_options);
   ASSERT_TRUE(image_bitmap_outside_crop);
@@ -186,8 +188,8 @@
   image->SetImageForTest(original_image_content);
 
   const ImageBitmapOptions* default_options = ImageBitmapOptions::Create();
-  absl::optional<IntRect> crop_rect =
-      IntRect(0, 0, image->width(), image->height());
+  absl::optional<gfx::Rect> crop_rect =
+      gfx::Rect(0, 0, image->width(), image->height());
   auto* image_bitmap =
       MakeGarbageCollected<ImageBitmap>(image, crop_rect, default_options);
   ASSERT_TRUE(image_bitmap);
@@ -242,7 +244,7 @@
 
 static void TestImageBitmapTextureBacked(
     scoped_refptr<StaticBitmapImage> bitmap,
-    IntRect& rect,
+    gfx::Rect& rect,
     ImageBitmapOptions* options,
     bool is_texture_backed) {
   auto* image_bitmap = MakeGarbageCollected<ImageBitmap>(bitmap, rect, options);
@@ -266,7 +268,7 @@
   EXPECT_TRUE(image_bitmap);
   EXPECT_TRUE(image_bitmap->BitmapImage()->IsTextureBacked());
 
-  IntRect image_bitmap_rect(25, 25, 50, 50);
+  gfx::Rect image_bitmap_rect(25, 25, 50, 50);
   {
     ImageBitmapOptions* image_bitmap_options = ImageBitmapOptions::Create();
     TestImageBitmapTextureBacked(bitmap, image_bitmap_rect,
@@ -330,7 +332,7 @@
   ImageBitmapOptions* options = ImageBitmapOptions::Create();
   options->setColorSpaceConversion("default");
   auto* image_bitmap = MakeGarbageCollected<ImageBitmap>(
-      image_data, IntRect(gfx::Point(0, 0), image_data->Size()), options);
+      image_data, gfx::Rect(ToGfxSize(image_data->Size())), options);
   DCHECK(image_bitmap);
 }
 
diff --git a/third_party/blink/renderer/core/input/gesture_manager.cc b/third_party/blink/renderer/core/input/gesture_manager.cc
index 3ee08d5..9eae5d6 100644
--- a/third_party/blink/renderer/core/input/gesture_manager.cc
+++ b/third_party/blink/renderer/core/input/gesture_manager.cc
@@ -341,6 +341,8 @@
       current_hit_test.InnerNodeFrame()) {
     current_hit_test.InnerNodeFrame()->View()->UpdateLifecycleToPrePaintClean(
         DocumentUpdateReason::kHitTest);
+    current_hit_test = event_handling_util::HitTestResultInFrame(
+        frame_, HitTestLocation(adjusted_point), hit_type);
     if (TextFragmentHandler::IsOverTextFragment(current_hit_test) &&
         event_result == WebInputEventResult::kNotHandled) {
       return SendContextMenuEventForGesture(targeted_event);
diff --git a/third_party/blink/renderer/core/input/pointer_event_manager.h b/third_party/blink/renderer/core/input/pointer_event_manager.h
index 91825b7..13ddf98a 100644
--- a/third_party/blink/renderer/core/input/pointer_event_manager.h
+++ b/third_party/blink/renderer/core/input/pointer_event_manager.h
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/core/input/boundary_event_dispatcher.h"
 #include "third_party/blink/renderer/core/input/touch_event_manager.h"
 #include "third_party/blink/renderer/core/page/touch_adjustment.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/inspector/console_message_storage.h b/third_party/blink/renderer/core/inspector/console_message_storage.h
index e011f65..bf15d43 100644
--- a/third_party/blink/renderer/core/inspector/console_message_storage.h
+++ b/third_party/blink/renderer/core/inspector/console_message_storage.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_CONSOLE_MESSAGE_STORAGE_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
diff --git a/third_party/blink/renderer/core/inspector/dom_patch_support.cc b/third_party/blink/renderer/core/inspector/dom_patch_support.cc
index 0011fea..b4748e9 100644
--- a/third_party/blink/renderer/core/inspector/dom_patch_support.cc
+++ b/third_party/blink/renderer/core/inspector/dom_patch_support.cc
@@ -49,6 +49,7 @@
 #include "third_party/blink/renderer/core/xml/parser/xml_document_parser.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/crypto.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
 #include "third_party/blink/renderer/platform/wtf/hash_traits.h"
diff --git a/third_party/blink/renderer/core/inspector/dom_patch_support.h b/third_party/blink/renderer/core/inspector/dom_patch_support.h
index 3c5f6c7..785abae 100644
--- a/third_party/blink/renderer/core/inspector/dom_patch_support.h
+++ b/third_party/blink/renderer/core/inspector/dom_patch_support.h
@@ -31,6 +31,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_DOM_PATCH_SUPPORT_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_DOM_PATCH_SUPPORT_H_
 
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
index b036070..21c3c4e0 100644
--- a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
@@ -1889,12 +1889,8 @@
 void InspectorCSSAgent::CollectContainerQueriesFromRule(
     CSSRule* rule,
     protocol::Array<protocol::CSS::CSSContainerQuery>* container_queries) {
-  if (auto* container_rule = DynamicTo<CSSContainerRule>(rule)) {
-    if (container_rule->IsEmpty())
-      return;
-
+  if (auto* container_rule = DynamicTo<CSSContainerRule>(rule))
     container_queries->emplace_back(BuildContainerQueryObject(container_rule));
-  }
 }
 
 std::unique_ptr<protocol::Array<protocol::CSS::CSSContainerQuery>>
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_agent.h b/third_party/blink/renderer/core/inspector/inspector_dom_agent.h
index ed8f76b..0bbb5aa 100644
--- a/third_party/blink/renderer/core/inspector/inspector_dom_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_dom_agent.h
@@ -40,6 +40,8 @@
 #include "third_party/blink/renderer/core/inspector/protocol/dom.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
 #include "third_party/blink/renderer/platform/geometry/float_quad.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
diff --git a/third_party/blink/renderer/core/inspector/inspector_issue_storage.h b/third_party/blink/renderer/core/inspector/inspector_issue_storage.h
index ac3c197..d950b6e 100644
--- a/third_party/blink/renderer/core/inspector/inspector_issue_storage.h
+++ b/third_party/blink/renderer/core/inspector/inspector_issue_storage.h
@@ -8,6 +8,7 @@
 #include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
index d25b916f..f23d1db 100644
--- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -1014,8 +1014,8 @@
   }
   response_object->setProtocol(protocol);
 
-  const net::SSLInfo* ssl_info = response.GetSSLInfo();
-  if (ssl_info) {
+  const absl::optional<net::SSLInfo>& ssl_info = response.GetSSLInfo();
+  if (ssl_info.has_value()) {
     response_object->setSecurityDetails(BuildSecurityDetails(*ssl_info));
   }
 
@@ -1372,8 +1372,8 @@
   resources_data_->ResponseReceived(request_id, frame_id, response);
   resources_data_->SetResourceType(request_id, type);
 
-  const net::SSLInfo* ssl_info = response.GetSSLInfo();
-  if (ssl_info && ssl_info->cert) {
+  const absl::optional<net::SSLInfo>& ssl_info = response.GetSSLInfo();
+  if (ssl_info.has_value() && ssl_info->cert) {
     resources_data_->SetCertificate(request_id, ssl_info->cert);
   }
 
diff --git a/third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h b/third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h
index 2733008..ff47608 100644
--- a/third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h
+++ b/third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h
@@ -8,6 +8,8 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer.h b/third_party/blink/renderer/core/intersection_observer/intersection_observer.h
index 4a9d3a95..d7561bb 100644
--- a/third_party/blink/renderer/core/intersection_observer/intersection_observer.h
+++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer.h
@@ -13,6 +13,8 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/geometry/length.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/forward.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
diff --git a/third_party/blink/renderer/core/layout/custom_scrollbar.h b/third_party/blink/renderer/core/layout/custom_scrollbar.h
index 2b16773..e9a9f17 100644
--- a/third_party/blink/renderer/core/layout/custom_scrollbar.h
+++ b/third_party/blink/renderer/core/layout/custom_scrollbar.h
@@ -28,9 +28,9 @@
 
 #include "third_party/blink/renderer/core/scroll/scrollbar.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/depth_ordered_layout_object_list.h b/third_party/blink/renderer/core/layout/depth_ordered_layout_object_list.h
index 377eb689..5fa3c69 100644
--- a/third_party/blink/renderer/core/layout/depth_ordered_layout_object_list.h
+++ b/third_party/blink/renderer/core/layout/depth_ordered_layout_object_list.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_DEPTH_ORDERED_LAYOUT_OBJECT_LIST_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_DEPTH_ORDERED_LAYOUT_OBJECT_LIST_H_
 
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
diff --git a/third_party/blink/renderer/core/layout/floating_objects.h b/third_party/blink/renderer/core/layout/floating_objects.h
index c2bcc29..b34016a 100644
--- a/third_party/blink/renderer/core/layout/floating_objects.h
+++ b/third_party/blink/renderer/core/layout/floating_objects.h
@@ -29,6 +29,8 @@
 #include "base/types/pass_key.h"
 #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/clear_collection_scope.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
diff --git a/third_party/blink/renderer/core/layout/hit_test_result.h b/third_party/blink/renderer/core/layout/hit_test_result.h
index d9988a0..e6647db 100644
--- a/third_party/blink/renderer/core/layout/hit_test_result.h
+++ b/third_party/blink/renderer/core/layout/hit_test_result.h
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/platform/geometry/float_quad.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index a3a79bf..9a9de5c 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -2203,8 +2203,7 @@
 
 bool LayoutObject::IsSelectable() const {
   NOT_DESTROYED();
-  return !IsInert() && !(StyleRef().UserSelect() == EUserSelect::kNone &&
-                         StyleRef().UserModify() == EUserModify::kReadOnly);
+  return StyleRef().IsSelectable();
 }
 
 const ComputedStyle& LayoutObject::SlowEffectiveStyle(
@@ -4347,14 +4346,6 @@
          IsOutsideListMarkerForCustomContent();
 }
 
-bool LayoutObject::IsInert() const {
-  NOT_DESTROYED();
-  const LayoutObject* layout_object = this;
-  while (!layout_object->GetNode())
-    layout_object = layout_object->Parent();
-  return layout_object->GetNode()->IsInert();
-}
-
 void LayoutObject::ImageChanged(ImageResourceContent* image,
                                 CanDeferInvalidation defer) {
   NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index c02b5c7e..faf3fe0c 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -3729,8 +3729,6 @@
 
   void ClearLayoutRootIfNeeded() const;
 
-  bool IsInert() const;
-
   void ScheduleRelayout();
 
   void AddAsImageObserver(StyleImage*);
diff --git a/third_party/blink/renderer/core/layout/layout_shift_tracker.h b/third_party/blink/renderer/core/layout/layout_shift_tracker.h
index 7d392383..fce8546 100644
--- a/third_party/blink/renderer/core/layout/layout_shift_tracker.h
+++ b/third_party/blink/renderer/core/layout/layout_shift_tracker.h
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/timing/layout_shift.h"
 #include "third_party/blink/renderer/platform/geometry/region.h"
 #include "third_party/blink/renderer/platform/graphics/dom_node_id.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/timer.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h b/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h
index bb8537e..8ecb2f8 100644
--- a/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h
+++ b/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h
@@ -5,6 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_CUSTOM_PENDING_LAYOUT_REGISTRY_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_CUSTOM_PENDING_LAYOUT_REGISTRY_H_
 
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
diff --git a/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h b/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h
index 80457bf7..a10d6cf2 100644
--- a/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h
+++ b/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_rect.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
diff --git a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc
index ec880117..da7bb66 100644
--- a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc
+++ b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
+#include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
 #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
 #include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
 #include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
@@ -88,12 +89,25 @@
   LayoutNGBlockFlowMixin<LayoutSVGBlock>::InsertedIntoTree();
   for (LayoutBlock* cb = ContainingBlock(); cb; cb = cb->ContainingBlock())
     cb->AddSvgTextDescendant(*this);
+
+  for (auto* ancestor = Parent(); ancestor; ancestor = ancestor->Parent()) {
+    if (auto* root = DynamicTo<LayoutSVGRoot>(ancestor)) {
+      root->AddSvgTextDescendant(*this);
+      break;
+    }
+  }
 }
 
 void LayoutNGSVGText::WillBeRemovedFromTree() {
   NOT_DESTROYED();
   for (LayoutBlock* cb = ContainingBlock(); cb; cb = cb->ContainingBlock())
     cb->RemoveSvgTextDescendant(*this);
+  for (auto* ancestor = Parent(); ancestor; ancestor = ancestor->Parent()) {
+    if (auto* root = DynamicTo<LayoutSVGRoot>(ancestor)) {
+      root->RemoveSvgTextDescendant(*this);
+      break;
+    }
+  }
   LayoutNGBlockFlowMixin<LayoutSVGBlock>::WillBeRemovedFromTree();
 }
 
diff --git a/third_party/blink/renderer/core/layout/shapes/shape_outside_info.h b/third_party/blink/renderer/core/layout/shapes/shape_outside_info.h
index dd976387..ea98aa8 100644
--- a/third_party/blink/renderer/core/layout/shapes/shape_outside_info.h
+++ b/third_party/blink/renderer/core/layout/shapes/shape_outside_info.h
@@ -37,6 +37,7 @@
 #include "third_party/blink/renderer/core/style/shape_value.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/blink/renderer/platform/geometry/layout_size.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
index f0b67af0..c3c7eb9f 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
@@ -31,6 +31,7 @@
 #include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h"
 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
 #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
@@ -70,6 +71,7 @@
 
 void LayoutSVGRoot::Trace(Visitor* visitor) const {
   visitor->Trace(content_);
+  visitor->Trace(text_set_);
   LayoutReplaced::Trace(visitor);
 }
 
@@ -376,6 +378,15 @@
 
   SVGResources::UpdateClipPathFilterMask(To<SVGSVGElement>(*GetNode()),
                                          old_style, StyleRef());
+
+  if (diff.TransformChanged()) {
+    for (auto& svg_text : text_set_) {
+      svg_text->SetNeedsLayout(layout_invalidation_reason::kStyleChange,
+                               kMarkContainerChain);
+      svg_text->SetNeedsTextMetricsUpdate();
+    }
+  }
+
   if (!Parent())
     return;
   if (diff.HasDifference())
@@ -588,6 +599,18 @@
   SetNeedsLayout(layout_invalidation_reason::kSvgChanged);
 }
 
+void LayoutSVGRoot::AddSvgTextDescendant(LayoutNGSVGText& svg_text) {
+  NOT_DESTROYED();
+  DCHECK(!text_set_.Contains(&svg_text));
+  text_set_.insert(&svg_text);
+}
+
+void LayoutSVGRoot::RemoveSvgTextDescendant(LayoutNGSVGText& svg_text) {
+  NOT_DESTROYED();
+  DCHECK(text_set_.Contains(&svg_text));
+  text_set_.erase(&svg_text);
+}
+
 PaintLayerType LayoutSVGRoot::LayerTypeRequired() const {
   NOT_DESTROYED();
   auto layer_type_required = LayoutReplaced::LayerTypeRequired();
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.h b/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
index 17620e0..e0d941a 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
@@ -28,6 +28,7 @@
 
 namespace blink {
 
+class LayoutNGSVGText;
 class SVGElement;
 enum class SVGTransformChange;
 
@@ -106,6 +107,9 @@
   }
   void NotifyDescendantCompositingReasonsChanged();
 
+  void AddSvgTextDescendant(LayoutNGSVGText& svg_text);
+  void RemoveSvgTextDescendant(LayoutNGSVGText& svg_text);
+
   const char* GetName() const override {
     NOT_DESTROYED();
     return "LayoutSVGRoot";
@@ -208,6 +212,7 @@
   SVGContentContainer content_;
   LayoutSize container_size_;
   AffineTransform local_to_border_box_transform_;
+  HeapHashSet<Member<LayoutNGSVGText>> text_set_;
   bool is_layout_size_changed_ : 1;
   bool did_screen_scale_factor_change_ : 1;
   bool needs_boundaries_or_transform_update_ : 1;
diff --git a/third_party/blink/renderer/core/layout/text_autosizer.h b/third_party/blink/renderer/core/layout/text_autosizer.h
index 527f393e..9c762a8 100644
--- a/third_party/blink/renderer/core/layout/text_autosizer.h
+++ b/third_party/blink/renderer/core/layout/text_autosizer.h
@@ -38,6 +38,7 @@
 #include "third_party/blink/public/mojom/frame/text_autosizer_page_info.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
diff --git a/third_party/blink/renderer/core/loader/font_preload_manager.h b/third_party/blink/renderer/core/loader/font_preload_manager.h
index 0b53a89..6b83cf48 100644
--- a/third_party/blink/renderer/core/loader/font_preload_manager.h
+++ b/third_party/blink/renderer/core/loader/font_preload_manager.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FONT_PRELOAD_MANAGER_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/timer.h"
 
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index af80d6e..909a73b 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -672,9 +672,7 @@
 
   CountDeprecation(WebFeature::kRequestedSubresourceWithEmbeddedCredentials);
 
-  // TODO(mkwst): Remove the runtime check one way or the other once we're
-  // sure it's going to stick (or that it's not).
-  return RuntimeEnabledFeatures::BlockCredentialedSubresourcesEnabled();
+  return true;
 }
 
 const KURL& FrameFetchContext::Url() const {
diff --git a/third_party/blink/renderer/core/loader/long_task_detector.h b/third_party/blink/renderer/core/loader/long_task_detector.h
index 241f74b..666b9ca 100644
--- a/third_party/blink/renderer/core/loader/long_task_detector.h
+++ b/third_party/blink/renderer/core/loader/long_task_detector.h
@@ -7,6 +7,7 @@
 
 #include "base/task/sequence_manager/task_time_observer.h"
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h b/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h
index ca23d99..4ad96cb 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h
+++ b/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h
@@ -9,7 +9,7 @@
 #include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
 #include "third_party/blink/renderer/core/loader/resource/script_resource.h"
 #include "third_party/blink/renderer/core/script/modulator.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
 
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_script_loader_registry.h b/third_party/blink/renderer/core/loader/modulescript/module_script_loader_registry.h
index 16123dba..55f2ad8 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_script_loader_registry.h
+++ b/third_party/blink/renderer/core/loader/modulescript/module_script_loader_registry.h
@@ -6,8 +6,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_MODULESCRIPT_MODULE_SCRIPT_LOADER_REGISTRY_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h
index 8a6ab56..14e07ab4 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h
+++ b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/script/modulator.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl_hash.h"
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h
index 468b5f4..ab34ffc 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h
+++ b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 
diff --git a/third_party/blink/renderer/core/loader/navigation_policy_test.cc b/third_party/blink/renderer/core/loader/navigation_policy_test.cc
index 30a86e0..ae2235ac 100644
--- a/third_party/blink/renderer/core/loader/navigation_policy_test.cc
+++ b/third_party/blink/renderer/core/loader/navigation_policy_test.cc
@@ -224,6 +224,14 @@
     NavigationPolicy policy;
   } kCases[] = {
       {"", kNavigationPolicyNewForegroundTab},
+      {"location,menubar,resizable,scrollbars,status",
+       kNavigationPolicyNewForegroundTab},
+      {"popup,location,menubar,resizable,scrollbars,status",
+       kNavigationPolicyNewPopup},
+      {"PoPuP,location,menubar,resizable,scrollbars,status",
+       kNavigationPolicyNewPopup},
+      {"popupFoo,location,menubar,resizable,scrollbars,status",
+       kNavigationPolicyNewForegroundTab},
       {"something", kNavigationPolicyNewPopup},
       {"something, something", kNavigationPolicyNewPopup},
       {"notnoopener", kNavigationPolicyNewPopup},
@@ -249,10 +257,13 @@
       {"", kNavigationPolicyNewForegroundTab},
       {"noopener, noreferrer", kNavigationPolicyNewForegroundTab},
       {"noopener, notreferrer", kNavigationPolicyNewPopup},
+      {"noopener, notreferrer, popup", kNavigationPolicyNewPopup},
       {"notopener, noreferrer", kNavigationPolicyNewPopup},
-      {"something, noopener, noreferrer", kNavigationPolicyNewPopup},
-      {"noopener, noreferrer, something", kNavigationPolicyNewPopup},
-      {"noopener, something, noreferrer", kNavigationPolicyNewPopup},
+      {"notopener, noreferrer, popup", kNavigationPolicyNewPopup},
+      {"notopener, noreferrer, popup=0", kNavigationPolicyNewForegroundTab},
+      {"popup, noopener, noreferrer", kNavigationPolicyNewPopup},
+      {"noopener, noreferrer, popup", kNavigationPolicyNewPopup},
+      {"noopener, popup, noreferrer", kNavigationPolicyNewPopup},
       {"NoOpEnEr, NoReFeRrEr", kNavigationPolicyNewForegroundTab},
   };
 
@@ -270,12 +281,14 @@
     NavigationPolicy policy;
   } kCases[] = {
       {"", kNavigationPolicyNewForegroundTab},
-      {"something", kNavigationPolicyNewPopup},
-      {"something, something", kNavigationPolicyNewPopup},
+      {"popup", kNavigationPolicyNewPopup},
+      {"popup, something", kNavigationPolicyNewPopup},
       {"notreferrer", kNavigationPolicyNewPopup},
+      {"notreferrer,popup", kNavigationPolicyNewPopup},
+      {"notreferrer,popup=0", kNavigationPolicyNewForegroundTab},
       {"noreferrer", kNavigationPolicyNewForegroundTab},
-      {"something, noreferrer", kNavigationPolicyNewPopup},
-      {"noreferrer, something", kNavigationPolicyNewPopup},
+      {"popup, noreferrer", kNavigationPolicyNewPopup},
+      {"noreferrer, popup", kNavigationPolicyNewPopup},
       {"NoReFeRrEr", kNavigationPolicyNewForegroundTab},
   };
 
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_content.h b/third_party/blink/renderer/core/loader/resource/image_resource_content.h
index 57f333c4..2b28ed4 100644
--- a/third_party/blink/renderer/core/loader/resource/image_resource_content.h
+++ b/third_party/blink/renderer/core/loader/resource/image_resource_content.h
@@ -13,12 +13,12 @@
 #include "third_party/blink/renderer/platform/graphics/image.h"
 #include "third_party/blink/renderer/platform/graphics/image_observer.h"
 #include "third_party/blink/renderer/platform/graphics/image_orientation.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h"
 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_status.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/wtf/hash_counted_set.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/loader/worker_fetch_context.cc b/third_party/blink/renderer/core/loader/worker_fetch_context.cc
index 90109c3..03d589c 100644
--- a/third_party/blink/renderer/core/loader/worker_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/worker_fetch_context.cc
@@ -163,10 +163,7 @@
       CountDeprecation(
           WebFeature::kRequestedSubresourceWithEmbeddedCredentials);
 
-      // TODO(mkwst): Remove the runtime check one way or the other once we're
-      // sure it's going to stick (or that it's not).
-      if (RuntimeEnabledFeatures::BlockCredentialedSubresourcesEnabled())
-        return true;
+      return true;
     }
   }
   return false;
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
index 0a7539a..c2dd015 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -271,7 +271,7 @@
 
 ScriptPromise OffscreenCanvas::CreateImageBitmap(
     ScriptState* script_state,
-    absl::optional<IntRect> crop_rect,
+    absl::optional<gfx::Rect> crop_rect,
     const ImageBitmapOptions* options,
     ExceptionState& exception_state) {
   if (context_)
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
index 7d0e38a6..d8b54ca 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
@@ -149,7 +149,7 @@
   // ImageBitmapSource implementation
   IntSize BitmapSourceSize() const final;
   ScriptPromise CreateImageBitmap(ScriptState*,
-                                  absl::optional<IntRect>,
+                                  absl::optional<gfx::Rect>,
                                   const ImageBitmapOptions*,
                                   ExceptionState&) final;
 
diff --git a/third_party/blink/renderer/core/page/create_window.cc b/third_party/blink/renderer/core/page/create_window.cc
index 73d68eb8..5386102c 100644
--- a/third_party/blink/renderer/core/page/create_window.cc
+++ b/third_party/blink/renderer/core/page/create_window.cc
@@ -81,12 +81,8 @@
     return window_features;
 
   bool ui_features_were_disabled = false;
-
-  // See crbug.com/1192701 for details, but we're working on changing the
-  // popup-triggering conditions for window.open. This bool represents the "new"
-  // state after this change.
-  bool is_popup_with_new_behavior = false;
-
+  enum class PopupState { kUnknown, kPopup, kWindow };
+  PopupState popup_state = PopupState::kUnknown;
   unsigned key_begin, key_end;
   unsigned value_begin, value_end;
 
@@ -186,8 +182,9 @@
     } else if (key_string == "width" || key_string == "innerwidth") {
       window_features.width_set = true;
       window_features.width = value;
-      // Width will be the only trigger for a popup.
-      is_popup_with_new_behavior = true;
+    } else if (key_string == "popup") {
+      // The 'popup' property explicitly triggers a popup.
+      popup_state = value ? PopupState::kPopup : PopupState::kWindow;
     } else if (key_string == "height" || key_string == "innerheight") {
       window_features.height_set = true;
       window_features.height = value;
@@ -224,17 +221,20 @@
     }
   }
 
-  // Existing logic from NavigationPolicy::NavigationPolicyForCreateWindow():
-  if (dom_window && dom_window->document()) {
-    bool is_popup_with_current_behavior = !window_features.tool_bar_visible ||
-                                          !window_features.status_bar_visible ||
-                                          !window_features.scrollbars_visible ||
-                                          !window_features.menu_bar_visible ||
-                                          !window_features.resizable;
-    if (is_popup_with_current_behavior != is_popup_with_new_behavior) {
-      UseCounter::Count(dom_window->document(),
-                        WebFeature::kWindowOpenNewPopupBehaviorMismatch);
+  if (RuntimeEnabledFeatures::WindowOpenNewPopupBehaviorEnabled()) {
+    bool is_popup = popup_state == PopupState::kPopup;
+    if (popup_state == PopupState::kUnknown) {
+      is_popup = !window_features.tool_bar_visible ||
+                 !window_features.menu_bar_visible ||
+                 !window_features.resizable ||
+                 !window_features.scrollbars_visible ||
+                 !window_features.status_bar_visible;
     }
+    // If this is a popup, set all BarProps to false, and vice versa.
+    window_features.tool_bar_visible = !is_popup;
+    window_features.menu_bar_visible = !is_popup;
+    window_features.scrollbars_visible = !is_popup;
+    window_features.status_bar_visible = !is_popup;
   }
 
   if (window_features.noreferrer)
diff --git a/third_party/blink/renderer/core/page/focus_controller.h b/third_party/blink/renderer/core/page/focus_controller.h
index 02cc440..303e15ee 100644
--- a/third_party/blink/renderer/core/page/focus_controller.h
+++ b/third_party/blink/renderer/core/page/focus_controller.h
@@ -30,6 +30,8 @@
 #include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
diff --git a/third_party/blink/renderer/core/page/print_context.h b/third_party/blink/renderer/core/page/print_context.h
index 6922db6..c918dba 100644
--- a/third_party/blink/renderer/core/page/print_context.h
+++ b/third_party/blink/renderer/core/page/print_context.h
@@ -22,6 +22,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_PRINT_CONTEXT_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
diff --git a/third_party/blink/renderer/core/page/print_context_test.cc b/third_party/blink/renderer/core/page/print_context_test.cc
index 483b692..768c4a4 100644
--- a/third_party/blink/renderer/core/page/print_context_test.cc
+++ b/third_party/blink/renderer/core/page/print_context_test.cc
@@ -6,6 +6,11 @@
 
 #include <memory>
 
+#include "base/test/scoped_feature_list.h"
+#include "components/viz/test/test_context_provider.h"
+#include "components/viz/test/test_gles2_interface.h"
+#include "gpu/command_buffer/client/raster_implementation_gles.h"
+#include "gpu/config/gpu_finch_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/dom/document.h"
@@ -20,9 +25,11 @@
 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
+#include "third_party/blink/renderer/platform/graphics/test/gpu_test_utils.h"
 #include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
 #include "third_party/skia/include/core/SkCanvas.h"
@@ -94,6 +101,40 @@
   Vector<Operation> recorded_operations_;
 };
 
+// overrides methods of RasterImplementationGLES to suppress NOTREACHED().
+class FakeRasterInterface : public gpu::raster::RasterImplementationGLES {
+ public:
+  explicit FakeRasterInterface(gpu::gles2::GLES2Interface* gl,
+                               gpu::ContextSupport* context_support)
+      : gpu::raster::RasterImplementationGLES(gl, context_support) {}
+
+  void BeginRasterCHROMIUM(GLuint sk_color,
+                           GLboolean needs_clear,
+                           GLuint msaa_sample_count,
+                           gpu::raster::MsaaMode msaa_mode,
+                           GLboolean can_use_lcd_text,
+                           const gfx::ColorSpace& color_space,
+                           const GLbyte* mailbox) override {}
+  void RasterCHROMIUM(const cc::DisplayItemList* list,
+                      cc::ImageProvider* provider,
+                      const gfx::Size& content_size,
+                      const gfx::Rect& full_raster_rect,
+                      const gfx::Rect& playback_rect,
+                      const gfx::Vector2dF& post_translate,
+                      const gfx::Vector2dF& post_scale,
+                      bool requires_clear,
+                      size_t* max_op_size_hint,
+                      bool preserve_recording = true) override {}
+  void EndRasterCHROMIUM() override {}
+
+  void ReadbackImagePixels(const gpu::Mailbox& source_mailbox,
+                           const SkImageInfo& dst_info,
+                           GLuint dst_row_bytes,
+                           int src_x,
+                           int src_y,
+                           void* dst_pixels) override {}
+};
+
 class PrintContextTest : public PaintTestConfigurations, public RenderingTest {
  protected:
   explicit PrintContextTest(LocalFrameClient* local_frame_client = nullptr)
@@ -105,11 +146,13 @@
     print_context_ =
         MakeGarbageCollected<PrintContext>(GetDocument().GetFrame(),
                                            /*use_printing_layout=*/true);
+    CanvasResourceProvider::SetMaxPinnedImageBytesForTesting(100);
   }
 
   void TearDown() override {
     RenderingTest::TearDown();
     CanvasRenderingContext::GetCanvasPerformanceMonitor().ResetForTesting();
+    CanvasResourceProvider::ResetMaxPinnedImageBytesForTesting();
   }
 
   PrintContext& GetPrintContext() { return *print_context_.Get(); }
@@ -516,6 +559,291 @@
   PrintSinglePage(canvas);
 }
 
+TEST_P(PrintContextTest, Canvas2DAutoFlushingSuppressed) {
+  // When printing, we're supposed to make a best effore to avoid flushing
+  // a canvas's PaintOps in order to support vector printing whenever possible.
+  MockPageContextCanvas canvas;
+  SetBodyInnerHTML("<canvas id='c' width=200 height=100></canvas>");
+  GetDocument().GetSettings()->SetScriptEnabled(true);
+  Element* const script_element =
+      GetDocument().CreateRawElement(html_names::kScriptTag);
+  // Note: source_canvas is 10x10, which consumes 400 bytes for pixel data,
+  // which is larger than the 100 limit set in PrintContextTest::SetUp().
+  script_element->setTextContent(
+      "source_canvas = document.createElement('canvas');"
+      "source_canvas.width = 10;"
+      "source_canvas.height = 10;"
+      "source_ctx = source_canvas.getContext('2d');"
+      "source_ctx.fillRect(1000, 0, 1, 1);"
+      "window.addEventListener('beforeprint', (ev) => {"
+      "  ctx = document.getElementById('c').getContext('2d');"
+      "  ctx.fillStyle = 'green';"
+      "  ctx.fillRect(0, 0, 100, 100);"
+      "  ctx.drawImage(source_canvas, 101, 0);"
+      // Next op normally triggers an auto-flush due to exceeded memory limit
+      // but in this case, the auto-flush is suppressed.
+      "  ctx.fillRect(0, 0, 1, 1);"
+      "});");
+  GetDocument().body()->AppendChild(script_element);
+
+  // Verify that the auto-flush was suppressed by checking that the first
+  // fillRect call flowed through to 'canvas'.
+  testing::Sequence s;
+  // The initial clear and the first fillRect call
+  EXPECT_CALL(canvas, onDrawRect(_, _))
+      .Times(testing::Exactly(2))
+      .InSequence(s);
+  // The drawImage call
+  EXPECT_CALL(canvas, onDrawImageRect2(_, _, _, _, _, _)).InSequence(s);
+  // The secondFillRect
+  EXPECT_CALL(canvas, onDrawRect(_, _)).InSequence(s);
+
+  PrintSinglePage(canvas);
+}
+
+// For testing printing behavior when 2d canvases are gpu-accelerated.
+class PrintContextAcceleratedCanvasTest : public PrintContextTest {
+ public:
+  void SetUp() override {
+    accelerated_canvas_scope_ =
+        std::make_unique<ScopedAccelerated2dCanvasForTest>(true);
+    test_context_provider_ = viz::TestContextProvider::Create();
+    InitializeSharedGpuContext(test_context_provider_.get());
+
+    PrintContextTest::SetUp();
+
+    GetDocument().GetSettings()->SetAcceleratedCompositingEnabled(true);
+  }
+
+  void TearDown() override {
+    // Call base class TeardDown first to ensure Canvas2DLayerBridge is
+    // destroyed before the TestContextProvider.
+    PrintContextTest::TearDown();
+
+    SharedGpuContext::ResetForTesting();
+    test_context_provider_ = nullptr;
+    accelerated_canvas_scope_ = nullptr;
+  }
+
+ private:
+  scoped_refptr<viz::TestContextProvider> test_context_provider_;
+  std::unique_ptr<ScopedAccelerated2dCanvasForTest> accelerated_canvas_scope_;
+};
+
+INSTANTIATE_PAINT_TEST_SUITE_P(PrintContextAcceleratedCanvasTest);
+
+TEST_P(PrintContextAcceleratedCanvasTest, Canvas2DBeforePrint) {
+  MockPageContextCanvas canvas;
+  SetBodyInnerHTML("<canvas id='c' width=100 height=100></canvas>");
+  GetDocument().GetSettings()->SetScriptEnabled(true);
+  Element* const script_element =
+      GetDocument().CreateRawElement(html_names::kScriptTag);
+  script_element->setTextContent(
+      "window.addEventListener('beforeprint', (ev) => {"
+      "const ctx = document.getElementById('c').getContext('2d');"
+      "ctx.fillRect(0, 0, 10, 10);"
+      "ctx.fillRect(50, 50, 10, 10);"
+      "});");
+  GetDocument().body()->AppendChild(script_element);
+
+  // Initial clear + 2 fillRects.
+  EXPECT_CALL(canvas, onDrawRect(_, _)).Times(testing::Exactly(3));
+
+  PrintSinglePage(canvas);
+}
+
+// For testing printing behavior when 2d canvas contexts use oop rasterization.
+class PrintContextOOPRCanvasTest : public PrintContextTest {
+ public:
+  void SetUp() override {
+    accelerated_canvas_scope_ =
+        std::make_unique<ScopedAccelerated2dCanvasForTest>(true);
+    std::unique_ptr<viz::TestGLES2Interface> gl_context =
+        std::make_unique<viz::TestGLES2Interface>();
+    gl_context->set_supports_oop_raster(true);
+    std::unique_ptr<viz::TestContextSupport> context_support =
+        std::make_unique<viz::TestContextSupport>();
+    std::unique_ptr<FakeRasterInterface> raster_interface =
+        std::make_unique<FakeRasterInterface>(gl_context.get(),
+                                              context_support.get());
+    test_context_provider_ = base::MakeRefCounted<viz::TestContextProvider>(
+        std::move(context_support), std::move(gl_context),
+        std::move(raster_interface),
+        /*shared_image_interface=*/nullptr,
+        /*support_locking=*/false);
+
+    InitializeSharedGpuContext(test_context_provider_.get());
+
+    PrintContextTest::SetUp();
+
+    GetDocument().GetSettings()->SetAcceleratedCompositingEnabled(true);
+  }
+
+  void TearDown() override {
+    // Call base class TeardDown first to ensure Canvas2DLayerBridge is
+    // destroyed before the TestContextProvider.
+    PrintContextTest::TearDown();
+
+    SharedGpuContext::ResetForTesting();
+    test_context_provider_ = nullptr;
+    accelerated_canvas_scope_ = nullptr;
+  }
+
+ private:
+  scoped_refptr<viz::TestContextProvider> test_context_provider_;
+  std::unique_ptr<ScopedAccelerated2dCanvasForTest> accelerated_canvas_scope_;
+};
+
+INSTANTIATE_PAINT_TEST_SUITE_P(PrintContextOOPRCanvasTest);
+
+TEST_P(PrintContextOOPRCanvasTest, Canvas2DBeforePrint) {
+  MockPageContextCanvas canvas;
+  SetBodyInnerHTML("<canvas id='c' width=100 height=100></canvas>");
+  GetDocument().GetSettings()->SetScriptEnabled(true);
+  Element* const script_element =
+      GetDocument().CreateRawElement(html_names::kScriptTag);
+  script_element->setTextContent(
+      "window.addEventListener('beforeprint', (ev) => {"
+      "const ctx = document.getElementById('c').getContext('2d');"
+      "ctx.fillRect(0, 0, 10, 10);"
+      "ctx.fillRect(50, 50, 10, 10);"
+      "});");
+  GetDocument().body()->AppendChild(script_element);
+
+  // Initial clear + 2 fillRects.
+  EXPECT_CALL(canvas, onDrawRect(_, _)).Times(testing::Exactly(3));
+
+  PrintSinglePage(canvas);
+}
+
+TEST_P(PrintContextOOPRCanvasTest, Canvas2DFlushForImageListener) {
+  // Verifies that a flush triggered by a change to a source canvas results
+  // in printing falling out of vector print mode.
+
+  // This test needs to run with CanvasOopRasterization enabled in order to
+  // exercise the FlushForImageListener code path in CanvasResourceProvider.
+  MockPageContextCanvas canvas;
+  SetBodyInnerHTML("<canvas id='c' width=200 height=100></canvas>");
+  GetDocument().GetSettings()->SetScriptEnabled(true);
+  Element* const script_element =
+      GetDocument().CreateRawElement(html_names::kScriptTag);
+  script_element->setTextContent(
+      "source_canvas = document.createElement('canvas');"
+      "source_canvas.width = 5;"
+      "source_canvas.height = 5;"
+      "source_ctx = source_canvas.getContext('2d');"
+      "source_ctx.fillRect(0, 0, 1, 1);"
+      "image_data = source_ctx.getImageData(0, 0, 5, 5);"
+      "window.addEventListener('beforeprint', (ev) => {"
+      "  ctx = document.getElementById('c').getContext('2d');"
+      "  ctx.drawImage(source_canvas, 0, 0);"
+      // Touching source_ctx forces a flush of both contexts, which cancels
+      // vector printing.
+      "  source_ctx.putImageData(image_data, 0, 0);"
+      "  ctx.fillRect(0, 0, 1, 1);"
+      "});");
+  GetDocument().body()->AppendChild(script_element);
+
+  // Verify that the auto-flush caused the canvas printing to fall out of
+  // vector mode.
+  testing::Sequence s;
+  // The initial clear
+  EXPECT_CALL(canvas, onDrawRect(_, _)).InSequence(s);
+  // The bitmap blit
+  EXPECT_CALL(canvas, onDrawImageRect2(_, _, _, _, _, _)).InSequence(s);
+  // The fill rect in the event listener should leave no trace here because
+  // it is supposed to be included in the canvas blit.
+  EXPECT_CALL(canvas, onDrawRect(_, _))
+      .Times(testing::Exactly(0))
+      .InSequence(s);
+
+  PrintSinglePage(canvas);
+}
+
+TEST_P(PrintContextOOPRCanvasTest, Canvas2DNoFlushForImageListener) {
+  // Verifies that a the canvas printing stays in vector mode after a
+  // canvas to canvas drawImage, as long as the source canvas is not
+  // touched afterwards.
+  MockPageContextCanvas canvas;
+  SetBodyInnerHTML("<canvas id='c' width=200 height=100></canvas>");
+  GetDocument().GetSettings()->SetScriptEnabled(true);
+  Element* const script_element =
+      GetDocument().CreateRawElement(html_names::kScriptTag);
+  script_element->setTextContent(
+      "source_canvas = document.createElement('canvas');"
+      "source_canvas.width = 5;"
+      "source_canvas.height = 5;"
+      "source_ctx = source_canvas.getContext('2d');"
+      "source_ctx.fillRect(0, 0, 1, 1);"
+      "window.addEventListener('beforeprint', (ev) => {"
+      "  ctx = document.getElementById('c').getContext('2d');"
+      "  ctx.fillStyle = 'green';"
+      "  ctx.fillRect(0, 0, 100, 100);"
+      "  ctx.drawImage(source_canvas, 0, 0, 5, 5, 101, 0, 10, 10);"
+      "  ctx.fillRect(0, 0, 1, 1);"
+      "});");
+  GetDocument().body()->AppendChild(script_element);
+
+  // Verify that the auto-flush caused the canvas printing to fall out of
+  // vector mode.
+  testing::Sequence s;
+  // The initial clear and the fillRect call
+  EXPECT_CALL(canvas, onDrawRect(_, _))
+      .Times(testing::Exactly(2))
+      .InSequence(s);
+  // The drawImage
+  EXPECT_CALL(canvas, onDrawImageRect2(_, _, _, _, _, _)).InSequence(s);
+  // The fill rect after the drawImage
+  EXPECT_CALL(canvas, onDrawRect(_, _))
+      .Times(testing::Exactly(1))
+      .InSequence(s);
+
+  PrintSinglePage(canvas);
+}
+
+TEST_P(PrintContextTest, Canvas2DAutoFlushBeforePrinting) {
+  // This test verifies that if an autoflush is triggered before printing,
+  // and the canvas is not cleared in the beforeprint handler, then the canvas
+  // cannot be vector printed.
+  MockPageContextCanvas canvas;
+  SetBodyInnerHTML("<canvas id='c' width=200 height=100></canvas>");
+  GetDocument().GetSettings()->SetScriptEnabled(true);
+  Element* const script_element =
+      GetDocument().CreateRawElement(html_names::kScriptTag);
+  // Note: source_canvas is 10x10, which consumes 400 bytes for pixel data,
+  // which is larger than the 100 limit set in PrintContextTest::SetUp().
+  script_element->setTextContent(
+      "source_canvas = document.createElement('canvas');"
+      "source_canvas.width = 10;"
+      "source_canvas.height = 10;"
+      "source_ctx = source_canvas.getContext('2d');"
+      "source_ctx.fillRect(0, 0, 1, 1);"
+      "ctx = document.getElementById('c').getContext('2d');"
+      "ctx.fillRect(0, 0, 100, 100);"
+      "ctx.drawImage(source_canvas, 101, 0);"
+      // Next op triggers an auto-flush due to exceeded memory limit
+      "ctx.fillRect(0, 0, 1, 1);"
+      "window.addEventListener('beforeprint', (ev) => {"
+      "  ctx.fillRect(0, 0, 1, 1);"
+      "});");
+  GetDocument().body()->AppendChild(script_element);
+
+  // Verify that the auto-flush caused the canvas printing to fall out of
+  // vector mode.
+  testing::Sequence s;
+  // The initial clear
+  EXPECT_CALL(canvas, onDrawRect(_, _)).InSequence(s);
+  // The bitmap blit
+  EXPECT_CALL(canvas, onDrawImageRect2(_, _, _, _, _, _)).InSequence(s);
+  // The fill rect in the event listener should leave no trace here because
+  // it is supposed to be included in the canvas blit.
+  EXPECT_CALL(canvas, onDrawRect(_, _))
+      .Times(testing::Exactly(0))
+      .InSequence(s);
+
+  PrintSinglePage(canvas);
+}
+
 // This tests that we don't resize or re-layout subframes in printed content.
 // TODO(weili): This test fails when the iframe isn't the root scroller - e.g.
 // Adding ScopedImplicitRootScrollerForTest disabler(false);
diff --git a/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h b/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h
index ef26029b..6658870 100644
--- a/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h
+++ b/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_ROOT_SCROLLER_CONTROLLER_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/page/scrolling/scroll_customization_callbacks.h b/third_party/blink/renderer/core/page/scrolling/scroll_customization_callbacks.h
index f234b179..8eb5319 100644
--- a/third_party/blink/renderer/core/page/scrolling/scroll_customization_callbacks.h
+++ b/third_party/blink/renderer/core/page/scrolling/scroll_customization_callbacks.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_SCROLL_CUSTOMIZATION_CALLBACKS_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h
index 2e44a98..2a626485 100644
--- a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h
+++ b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h
@@ -33,6 +33,7 @@
 #include "third_party/blink/renderer/core/scroll/scroll_types.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
 #include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace cc {
diff --git a/third_party/blink/renderer/core/page/scrolling/snap_coordinator.h b/third_party/blink/renderer/core/page/scrolling/snap_coordinator.h
index 598c9f0..631a34a 100644
--- a/third_party/blink/renderer/core/page/scrolling/snap_coordinator.h
+++ b/third_party/blink/renderer/core/page/scrolling/snap_coordinator.h
@@ -9,6 +9,7 @@
 #include "cc/input/snap_selection_strategy.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h b/third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h
index 8dfd8db..f361b58 100644
--- a/third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h
+++ b/third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h
@@ -7,6 +7,7 @@
 
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
diff --git a/third_party/blink/renderer/core/paint/applied_decoration_painter.cc b/third_party/blink/renderer/core/paint/applied_decoration_painter.cc
index 47a2e7ec..2bacf0a6 100644
--- a/third_party/blink/renderer/core/paint/applied_decoration_painter.cc
+++ b/third_party/blink/renderer/core/paint/applied_decoration_painter.cc
@@ -15,7 +15,7 @@
   context_.SetStrokeColor(decoration_info_.LineColor());
 
   AutoDarkMode auto_dark_mode(PaintAutoDarkMode(
-      decoration_info_.Style(), DarkModeFilter::ElementRole::kText));
+      decoration_info_.Style(), DarkModeFilter::ElementRole::kForeground));
   switch (decoration_info_.DecorationStyle()) {
     case ETextDecorationStyle::kWavy:
       StrokeWavyTextDecoration(flags);
@@ -50,9 +50,9 @@
   // after the line in TextDecorationInfo::PrepareWavyStrokePath().
   context_.Clip(decoration_info_.BoundsForLine(line_));
 
-  absl::optional<Path> path = decoration_info_.PrepareWavyStrokePath(line_);
+  absl::optional<Path> path = decoration_info_.StrokePathForLine(line_);
   AutoDarkMode auto_dark_mode(PaintAutoDarkMode(
-      decoration_info_.Style(), DarkModeFilter::ElementRole::kText));
+      decoration_info_.Style(), DarkModeFilter::ElementRole::kForeground));
   if (flags)
     context_.DrawPath(path->GetSkPath(), *flags, auto_dark_mode);
   else
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h
index 45e52fd..c291c3a 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h
@@ -29,7 +29,7 @@
 
 #include "third_party/blink/renderer/platform/geometry/int_rect.h"
 #include "third_party/blink/renderer/platform/graphics/compositing_reasons.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
diff --git a/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.h b/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.h
index 27617ab..8fbe89e6 100644
--- a/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.h
+++ b/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.h
@@ -28,6 +28,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_COMPOSITING_GRAPHICS_LAYER_TREE_BUILDER_H_
 
 #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/paint/document_marker_painter.cc b/third_party/blink/renderer/core/paint/document_marker_painter.cc
index 1aafe1d4..f1f9ee7 100644
--- a/third_party/blink/renderer/core/paint/document_marker_painter.cc
+++ b/third_party/blink/renderer/core/paint/document_marker_painter.cc
@@ -200,7 +200,8 @@
         gfx::PointF(box_origin.left + start,
                     (box_origin.top + logical_height.ToInt() - line_thickness)
                         .ToFloat()),
-        width, PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kText));
+        width,
+        PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kForeground));
   } else {
     // For wavy underline format we use this logic that is very similar to
     // spelling/grammar squiggles format. Only applicable for composition
diff --git a/third_party/blink/renderer/core/paint/ellipsis_box_painter.cc b/third_party/blink/renderer/core/paint/ellipsis_box_painter.cc
index 1169f9d..b67e222 100644
--- a/third_party/blink/renderer/core/paint/ellipsis_box_painter.cc
+++ b/third_party/blink/renderer/core/paint/ellipsis_box_painter.cc
@@ -76,7 +76,7 @@
                            ellipsis_box_.IsHorizontal());
 
   AutoDarkMode auto_dark_mode(
-      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kText));
+      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kForeground));
 
   text_painter.Paint(0, ellipsis_box_.EllipsisStr().length(),
                      ellipsis_box_.EllipsisStr().length(), text_style,
diff --git a/third_party/blink/renderer/core/paint/file_upload_control_painter.cc b/third_party/blink/renderer/core/paint/file_upload_control_painter.cc
index e7a8675..8263933 100644
--- a/third_party/blink/renderer/core/paint/file_upload_control_painter.cc
+++ b/third_party/blink/renderer/core/paint/file_upload_control_painter.cc
@@ -81,7 +81,7 @@
         font, text_run_paint_info,
         gfx::PointF(RoundToInt(text_x), RoundToInt(text_y)),
         PaintAutoDarkMode(layout_file_upload_control_.StyleRef(),
-                          DarkModeFilter::ElementRole::kText));
+                          DarkModeFilter::ElementRole::kForeground));
     if (!font.ShouldSkipDrawing()) {
       ScopedPaintTimingDetectorBlockPaintHook
           scoped_paint_timing_detector_block_paint_hook;
diff --git a/third_party/blink/renderer/core/paint/highlight_painting_utils.cc b/third_party/blink/renderer/core/paint/highlight_painting_utils.cc
index 89779db..3f77979d 100644
--- a/third_party/blink/renderer/core/paint/highlight_painting_utils.cc
+++ b/third_party/blink/renderer/core/paint/highlight_painting_utils.cc
@@ -27,11 +27,6 @@
 
 namespace {
 
-bool NodeIsSelectable(const ComputedStyle& style, Node* node) {
-  return !node->IsInert() && !(style.UserSelect() == EUserSelect::kNone &&
-                               style.UserModify() == EUserModify::kReadOnly);
-}
-
 bool NodeIsReplaced(Node* node) {
   return node && node->GetLayoutObject() &&
          node->GetLayoutObject()->IsLayoutReplaced();
@@ -232,7 +227,7 @@
   if (pseudo == kPseudoIdSelection) {
     // If the element is unselectable, or we are only painting the selection,
     // don't override the foreground color with the selection foreground color.
-    if ((node && !NodeIsSelectable(style, node)) ||
+    if ((node && !style.IsSelectable()) ||
         (global_paint_flags & kGlobalPaintSelectionDragImageOnly)) {
       return style.VisitedDependentColor(color_property);
     }
@@ -265,7 +260,7 @@
     PseudoId pseudo,
     const AtomicString& pseudo_argument) {
   if (pseudo == kPseudoIdSelection) {
-    if (node && !NodeIsSelectable(style, node))
+    if (node && !style.IsSelectable())
       return Color::kTransparent;
   }
 
diff --git a/third_party/blink/renderer/core/paint/html_canvas_painter.cc b/third_party/blink/renderer/core/paint/html_canvas_painter.cc
index 5a1b8f51..4a9ee51 100644
--- a/third_party/blink/renderer/core/paint/html_canvas_painter.cc
+++ b/third_party/blink/renderer/core/paint/html_canvas_painter.cc
@@ -57,8 +57,10 @@
           layout_html_canvas_.ResolveColor(GetCSSPropertyBackgroundColor());
       layer->SetBackgroundColor(background_color.Rgb());
     }
+    // We do not take the CompositeAfterPaint code path when printing
+    // because it prevents painting canvas content as vector graphics.
     if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-        !flatten_composited_layers) {
+        !flatten_composited_layers && !canvas->IsPrinting()) {
       gfx::Rect pixel_snapped_rect = ToGfxRect(PixelSnappedIntRect(paint_rect));
       layer->SetBounds(pixel_snapped_rect.size());
       layer->SetIsDrawable(true);
diff --git a/third_party/blink/renderer/core/paint/image_element_timing.h b/third_party/blink/renderer/core/paint/image_element_timing.h
index 7a1e56cc..5deb044 100644
--- a/third_party/blink/renderer/core/paint/image_element_timing.h
+++ b/third_party/blink/renderer/core/paint/image_element_timing.h
@@ -9,7 +9,7 @@
 
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
diff --git a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
index 631f31a..dca1708 100644
--- a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
+++ b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
@@ -403,8 +403,8 @@
   DOMNodeId node_id = GetNodeHolder(
       LineLayoutAPIShim::LayoutObjectFrom(inline_text_box_.GetLineLayoutItem())
           ->GetNode());
-  AutoDarkMode auto_dark_mode(
-      PaintAutoDarkMode(style_to_use, DarkModeFilter::ElementRole::kText));
+  AutoDarkMode auto_dark_mode(PaintAutoDarkMode(
+      style_to_use, DarkModeFilter::ElementRole::kForeground));
 
   if (!paint_selected_text_only) {
     // Paint text decorations except line-through.
@@ -587,8 +587,7 @@
   context.DrawHighlightForText(
       font, inline_text_box_.ConstructTextRun(style), local_origin, sel_height,
       background_color,
-      PaintAutoDarkMode(style,
-                        DarkModeFilter::ElementRole::kText),
+      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kForeground),
       start_pos, end_pos);
 }
 
@@ -865,7 +864,7 @@
 
   context.FillRect(
       FloatRect(selection_rect), c,
-      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kText));
+      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kForeground));
   return selection_rect;
 }
 
@@ -942,7 +941,7 @@
                            inline_text_box_.IsHorizontal());
 
   AutoDarkMode auto_dark_mode(
-      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kText));
+      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kForeground));
 
   text_painter.Paint(paint_offsets.first, paint_offsets.second,
                      inline_text_box_.Len(), text_style, kInvalidDOMNodeId,
@@ -979,7 +978,7 @@
   context.Clip(FloatRect(box_rect));
   context.DrawHighlightForText(
       font, run, gfx::PointF(box_origin), box_rect.Height().ToInt(), color,
-      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kText),
+      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kForeground),
       paint_offsets.first, paint_offsets.second);
 }
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
index 29ace4c..6911a52 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
@@ -204,7 +204,7 @@
                                                selection_style_.fill_color);
 
   AutoDarkMode auto_dark_mode(
-      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kText));
+      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kForeground));
 
   if (!rotation) {
     PaintRect(context, RectInPhysicalSpace(), color, auto_dark_mode);
@@ -297,7 +297,7 @@
   const StringView text = cursor_.CurrentText();
 
   AutoDarkMode auto_dark_mode(
-      PaintAutoDarkMode(style_, DarkModeFilter::ElementRole::kText));
+      PaintAutoDarkMode(style_, DarkModeFilter::ElementRole::kForeground));
 
   for (const DocumentMarker* marker : markers_) {
     const unsigned marker_start_offset =
diff --git a/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc
index 0d0f0165..e4e880a 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc
@@ -27,7 +27,7 @@
       box_fragment_.Style().VisitedDependentColor(GetCSSPropertyColor()));
   gfx::Point line_end_point = {bar.width(), 0};
   AutoDarkMode auto_dark_mode(PaintAutoDarkMode(
-      box_fragment_.Style(), DarkModeFilter::ElementRole::kText));
+      box_fragment_.Style(), DarkModeFilter::ElementRole::kForeground));
   info.context.DrawLine(bar.origin(), line_end_point + bar.OffsetFromOrigin(),
                         auto_dark_mode);
 }
@@ -44,7 +44,7 @@
   GraphicsContextStateSaver state_saver(info.context);
   info.context.SetFillColor(style.VisitedDependentColor(GetCSSPropertyColor()));
   AutoDarkMode auto_dark_mode(
-      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kText));
+      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kForeground));
   info.context.DrawText(style.GetFont(), text_fragment_paint_info,
                         gfx::PointF(paint_offset), kInvalidDOMNodeId,
                         auto_dark_mode);
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_combine_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_combine_painter.cc
index daab0e72..164bb8e 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_text_combine_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_text_combine_painter.cc
@@ -126,7 +126,7 @@
                   style_.GetTextEmphasisPosition());
   PaintEmphasisMarkForCombinedText(
       text_style, emphasis_mark_font,
-      PaintAutoDarkMode(style_, DarkModeFilter::ElementRole::kText));
+      PaintAutoDarkMode(style_, DarkModeFilter::ElementRole::kForeground));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
index 4949261..1d09a6c 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
@@ -395,7 +395,7 @@
   }
 
   AutoDarkMode auto_dark_mode(
-      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kText));
+      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kForeground));
 
   const unsigned length = fragment_paint_info.to - fragment_paint_info.from;
   const unsigned start_offset = fragment_paint_info.from;
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
index 2b8b02b..d5c643d 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
@@ -331,7 +331,9 @@
   } else {
     DCHECK(step == kPaintText);
     if (svg_text_paint_state_.has_value()) {
-      PaintSvgTextFragment(node_id, auto_dark_mode);
+      AutoDarkMode svg_text_auto_dark_mode(DarkModeFilter::ElementRole::kSVG,
+                                           auto_dark_mode.enabled);
+      PaintSvgTextFragment(node_id, svg_text_auto_dark_mode);
     } else {
       graphics_context_.DrawText(font_, fragment_paint_info_,
                                  gfx::PointF(text_origin_), node_id,
diff --git a/third_party/blink/renderer/core/paint/text_decoration_info.cc b/third_party/blink/renderer/core/paint/text_decoration_info.cc
index 9e2700f0..f3ded6ba 100644
--- a/third_party/blink/renderer/core/paint/text_decoration_info.cc
+++ b/third_party/blink/renderer/core/paint/text_decoration_info.cc
@@ -167,9 +167,6 @@
 
 void TextDecorationInfo::SetPerLineData(TextDecorationLine line,
                                         float line_offset) {
-  int index = TextDecorationToLineDataIndex(line);
-  line_data_[index].line_offset = line_offset;
-
   const float double_offset_from_thickness = ResolvedThickness() + 1.0f;
   float double_offset;
   int wavy_offset_factor;
@@ -196,9 +193,22 @@
       NOTREACHED();
   }
 
+  int index = TextDecorationToLineDataIndex(line);
+  line_data_[index].line_offset = line_offset;
   line_data_[index].double_offset = double_offset;
   line_data_[index].wavy_offset_factor = wavy_offset_factor;
-  line_data_[index].stroke_path.reset();
+
+  switch (DecorationStyle()) {
+    case ETextDecorationStyle::kDotted:
+    case ETextDecorationStyle::kDashed:
+      line_data_[index].stroke_path = PrepareDottedOrDashedStrokePath(line);
+      break;
+    case ETextDecorationStyle::kWavy:
+      line_data_[index].stroke_path = PrepareWavyStrokePath(line);
+      break;
+    default:
+      line_data_[index].stroke_path.reset();
+  }
 }
 
 ETextDecorationStyle TextDecorationInfo::DecorationStyle() const {
@@ -218,12 +228,10 @@
 }
 
 gfx::PointF TextDecorationInfo::StartPoint(TextDecorationLine line) const {
-  return local_origin_ +
-         gfx::Vector2dF(
-             0, line_data_[TextDecorationToLineDataIndex(line)].line_offset);
+  return local_origin_ + gfx::Vector2dF(0, LineDataForLine(line).line_offset);
 }
 float TextDecorationInfo::DoubleOffset(TextDecorationLine line) const {
-  return line_data_[TextDecorationToLineDataIndex(line)].double_offset;
+  return LineDataForLine(line).double_offset;
 }
 
 enum StrokeStyle TextDecorationInfo::StrokeStyle() const {
@@ -285,36 +293,29 @@
 
 FloatRect TextDecorationInfo::BoundsForDottedOrDashed(
     TextDecorationLine line) const {
-  int line_data_index = TextDecorationToLineDataIndex(line);
-  if (!line_data_[line_data_index].stroke_path) {
-    // These coordinate transforms need to match what's happening in
-    // GraphicsContext's drawLineForText and drawLine.
-    gfx::PointF start_point = StartPoint(line);
-    line_data_[TextDecorationToLineDataIndex(line)].stroke_path =
-        GraphicsContext::GetPathForTextLine(
-            start_point, width_, ResolvedThickness(),
-            TextDecorationStyleToStrokeStyle(DecorationStyle()));
-  }
-
   StrokeData stroke_data;
   stroke_data.SetThickness(roundf(ResolvedThickness()));
   stroke_data.SetStyle(TextDecorationStyleToStrokeStyle(DecorationStyle()));
-  return FloatRect(
-      line_data_[line_data_index].stroke_path.value().StrokeBoundingRect(
-          stroke_data));
+  return FloatRect(LineDataForLine(line).stroke_path.value().StrokeBoundingRect(
+      stroke_data));
 }
 
 FloatRect TextDecorationInfo::BoundsForWavy(TextDecorationLine line) const {
   StrokeData stroke_data;
   stroke_data.SetThickness(ResolvedThickness());
-  auto bounding_rect =
-      FloatRect(PrepareWavyStrokePath(line)->StrokeBoundingRect(stroke_data));
+  auto bounding_rect = FloatRect(
+      LineDataForLine(line).stroke_path->StrokeBoundingRect(stroke_data));
 
   bounding_rect.set_x(StartPoint(line).x());
   bounding_rect.set_width(width_);
   return bounding_rect;
 }
 
+absl::optional<Path> TextDecorationInfo::StrokePathForLine(
+    TextDecorationLine line) const {
+  return LineDataForLine(line).stroke_path;
+}
+
 float TextDecorationInfo::WavyDecorationSizing() const {
   // Minimum unit we use to compute control point distance and step to define
   // the path of the Bezier curve.
@@ -335,6 +336,16 @@
   return 2.5 * WavyDecorationSizing();
 }
 
+Path TextDecorationInfo::PrepareDottedOrDashedStrokePath(
+    TextDecorationLine line) const {
+  // These coordinate transforms need to match what's happening in
+  // GraphicsContext's drawLineForText and drawLine.
+  gfx::PointF start_point = StartPoint(line);
+  return GraphicsContext::GetPathForTextLine(
+      start_point, width_, ResolvedThickness(),
+      TextDecorationStyleToStrokeStyle(DecorationStyle()));
+}
+
 /*
  * Prepare a path for a cubic Bezier curve and repeat the same pattern long the
  * the decoration's axis.  The start point (p1), controlPoint1, controlPoint2
@@ -362,20 +373,14 @@
  *             |-----------|
  *                 step
  */
-absl::optional<Path> TextDecorationInfo::PrepareWavyStrokePath(
-    TextDecorationLine line) const {
-  int line_data_index = TextDecorationToLineDataIndex(line);
-  if (line_data_[line_data_index].stroke_path)
-    return line_data_[line_data_index].stroke_path;
-
-  gfx::PointF start_point = StartPoint(line);
+Path TextDecorationInfo::PrepareWavyStrokePath(TextDecorationLine line) const {
   float wave_offset =
-      DoubleOffset(line) *
-      line_data_[TextDecorationToLineDataIndex(line)].wavy_offset_factor;
+      DoubleOffset(line) * LineDataForLine(line).wavy_offset_factor;
 
   float control_point_distance = ControlPointDistanceFromResolvedThickness();
   float step = StepFromResolvedThickness();
 
+  gfx::PointF start_point = StartPoint(line);
   // We paint the wave before and after the text line (to cover the whole length
   // of the line) and then we clip it at
   // AppliedDecorationPainter::StrokeWavyTextDecoration().
@@ -388,7 +393,7 @@
 
   GraphicsContext::AdjustLineToPixelBoundaries(p1, p2, ResolvedThickness());
 
-  Path& path = line_data_[line_data_index].stroke_path.emplace();
+  Path path;
   path.MoveTo(p1);
 
   bool is_vertical_line = (p1.x() == p2.x());
@@ -444,7 +449,13 @@
                             gfx::PointF(x, y_axis));
     }
   }
-  return line_data_[line_data_index].stroke_path;
+  return path;
+}
+
+TextDecorationInfo::PerLineData TextDecorationInfo::LineDataForLine(
+    TextDecorationLine line) const {
+  int line_data_index = TextDecorationToLineDataIndex(line);
+  return line_data_[line_data_index];
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/text_decoration_info.h b/third_party/blink/renderer/core/paint/text_decoration_info.h
index f18695f..022183a 100644
--- a/third_party/blink/renderer/core/paint/text_decoration_info.h
+++ b/third_party/blink/renderer/core/paint/text_decoration_info.h
@@ -96,9 +96,8 @@
   // Compute bounds for the given line and the current decoration.
   FloatRect BoundsForLine(TextDecorationLine line) const;
 
-  // Return a path for a wavy line at the given position, for the
-  // current decoration.
-  absl::optional<Path> PrepareWavyStrokePath(TextDecorationLine line) const;
+  // Return a path for current decoration.
+  absl::optional<Path> StrokePathForLine(TextDecorationLine line) const;
 
  private:
   float ComputeUnderlineThickness(
@@ -110,6 +109,21 @@
   float WavyDecorationSizing() const;
   float ControlPointDistanceFromResolvedThickness() const;
   float StepFromResolvedThickness() const;
+  Path PrepareDottedOrDashedStrokePath(TextDecorationLine line) const;
+  Path PrepareWavyStrokePath(TextDecorationLine line) const;
+
+  /* We need to store data for up to 3 lines: Underline, Overline and
+     LineThrough. Unfortunately the enum for these are bitfield indices, not
+     directly useful as indexes. So explicitly convert in place
+     when necessary.
+  */
+  struct PerLineData {
+    float line_offset;
+    float double_offset;
+    int wavy_offset_factor;
+    absl::optional<Path> stroke_path;
+  };
+  PerLineData LineDataForLine(TextDecorationLine line) const;
 
   const ComputedStyle& style_;
   const absl::optional<AppliedTextDecoration> selection_text_decoration_;
@@ -123,20 +137,7 @@
   gfx::PointF local_origin_;
   bool antialias_;
   Vector<float> applied_decorations_thickness_;
-
   int decoration_index_;
-
-  /* We need to store data for up to 3 lines: Underline, Overline and
-     LineThrough. Unfortunately the enum for these are bitfield indices, not
-     directly useful as indexes. So explicitly convert in place
-     when necessary.
-  */
-  struct PerLineData {
-    float line_offset;
-    float double_offset;
-    int wavy_offset_factor;
-    mutable absl::optional<Path> stroke_path;
-  };
   PerLineData line_data_[3];
 };
 
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector.h b/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
index fc50973..de5ba946 100644
--- a/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
+++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
@@ -13,7 +13,6 @@
 #include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
 #include "third_party/blink/renderer/core/paint/text_element_timing.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/resize_observer/resize_observer.h b/third_party/blink/renderer/core/resize_observer/resize_observer.h
index e028a79..cc3ba76 100644
--- a/third_party/blink/renderer/core/resize_observer/resize_observer.h
+++ b/third_party/blink/renderer/core/resize_observer/resize_observer.h
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
 #include "third_party/blink/renderer/core/resize_observer/resize_observer_box_options.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/resize_observer/resize_observer_controller.h b/third_party/blink/renderer/core/resize_observer/resize_observer_controller.h
index 281f0f32..9dd38ba4 100644
--- a/third_party/blink/renderer/core/resize_observer/resize_observer_controller.h
+++ b/third_party/blink/renderer/core/resize_observer/resize_observer_controller.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_RESIZE_OBSERVER_RESIZE_OBSERVER_CONTROLLER_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 
diff --git a/third_party/blink/renderer/core/script/html_parser_script_runner.h b/third_party/blink/renderer/core/script/html_parser_script_runner.h
index 785ef3e..a93a5a3 100644
--- a/third_party/blink/renderer/core/script/html_parser_script_runner.h
+++ b/third_party/blink/renderer/core/script/html_parser_script_runner.h
@@ -30,6 +30,7 @@
 #include "third_party/blink/renderer/core/html/parser/html_parser_reentry_permit.h"
 #include "third_party/blink/renderer/core/script/pending_script.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_client.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
diff --git a/third_party/blink/renderer/core/script/modulator_impl_base.h b/third_party/blink/renderer/core/script/modulator_impl_base.h
index 7173c59..a332c360 100644
--- a/third_party/blink/renderer/core/script/modulator_impl_base.h
+++ b/third_party/blink/renderer/core/script/modulator_impl_base.h
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/script/modulator.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/script/module_map.h b/third_party/blink/renderer/core/script/module_map.h
index a0cd1fb..05cea8a 100644
--- a/third_party/blink/renderer/core/script/module_map.h
+++ b/third_party/blink/renderer/core/script/module_map.h
@@ -7,6 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl_hash.h"
diff --git a/third_party/blink/renderer/core/script/module_record_resolver_impl.h b/third_party/blink/renderer/core/script/module_record_resolver_impl.h
index 896c88d8..2b8fc19 100644
--- a/third_party/blink/renderer/core/script/module_record_resolver_impl.h
+++ b/third_party/blink/renderer/core/script/module_record_resolver_impl.h
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
 #include "third_party/blink/renderer/core/script/module_record_resolver.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/core/script/script_runner.h b/third_party/blink/renderer/core/script/script_runner.h
index d6d7dce5..783b569 100644
--- a/third_party/blink/renderer/core/script/script_runner.h
+++ b/third_party/blink/renderer/core/script/script_runner.h
@@ -31,6 +31,8 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
diff --git a/third_party/blink/renderer/core/scroll/mac_scrollbar_animator_impl.mm b/third_party/blink/renderer/core/scroll/mac_scrollbar_animator_impl.mm
index bd61947..0f113707 100644
--- a/third_party/blink/renderer/core/scroll/mac_scrollbar_animator_impl.mm
+++ b/third_party/blink/renderer/core/scroll/mac_scrollbar_animator_impl.mm
@@ -14,6 +14,8 @@
 #include "third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h"
 #include "third_party/blink/renderer/platform/animation/timing_function.h"
 #include "third_party/blink/renderer/platform/geometry/cg_conversions.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/mac/block_exceptions.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 
diff --git a/third_party/blink/renderer/core/streams/queue_with_sizes.h b/third_party/blink/renderer/core/streams/queue_with_sizes.h
index 49b3dea..8429f8c81 100644
--- a/third_party/blink/renderer/core/streams/queue_with_sizes.h
+++ b/third_party/blink/renderer/core/streams/queue_with_sizes.h
@@ -6,9 +6,9 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_QUEUE_WITH_SIZES_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "v8/include/v8.h"
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
index 2644315..45ba7444 100644
--- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
+++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/streams/readable_stream_controller.h"
 #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
 #include "v8/include/v8.h"
 
diff --git a/third_party/blink/renderer/core/streams/readable_stream.cc b/third_party/blink/renderer/core/streams/readable_stream.cc
index 7bdf24dd..77abb172c 100644
--- a/third_party/blink/renderer/core/streams/readable_stream.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream.cc
@@ -40,8 +40,8 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h
index fb7ac5b..11a5b63 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h
+++ b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/streams/writable_stream.h b/third_party/blink/renderer/core/streams/writable_stream.h
index e10cdd6..83358e8 100644
--- a/third_party/blink/renderer/core/streams/writable_stream.h
+++ b/third_party/blink/renderer/core/streams/writable_stream.h
@@ -12,7 +12,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "v8/include/v8.h"
 
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index d170927..6e148bc4 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2195,6 +2195,11 @@
     return PointerEventsInternal();
   }
 
+  bool IsSelectable() const {
+    return !IsInert() && !(UserSelect() == EUserSelect::kNone &&
+                           UserModify() == EUserModify::kReadOnly);
+  }
+
   // Text decoration utility functions.
   bool TextDecorationVisualOverflowEqual(const ComputedStyle& o) const;
   void ApplyTextDecorations(const Color& parent_text_decoration_color,
diff --git a/third_party/blink/renderer/core/style/cursor_list.h b/third_party/blink/renderer/core/style/cursor_list.h
index a517fc2..dc819e7 100644
--- a/third_party/blink/renderer/core/style/cursor_list.h
+++ b/third_party/blink/renderer/core/style/cursor_list.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_CURSOR_LIST_H_
 
 #include "third_party/blink/renderer/core/style/cursor_data.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/style/data_equivalency.h b/third_party/blink/renderer/core/style/data_equivalency.h
index 6cdd579..a4d8d5f5 100644
--- a/third_party/blink/renderer/core/style/data_equivalency.h
+++ b/third_party/blink/renderer/core/style/data_equivalency.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 #include "base/memory/scoped_refptr.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/style/style_variables.h b/third_party/blink/renderer/core/style/style_variables.h
index 4640aa7f..8a566d26 100644
--- a/third_party/blink/renderer/core/style/style_variables.h
+++ b/third_party/blink/renderer/core/style/style_variables.h
@@ -8,6 +8,7 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/renderer/core/css/css_value.h"
 #include "third_party/blink/renderer/core/css/css_variable_data.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
diff --git a/third_party/blink/renderer/core/svg/animation/element_smil_animations.h b/third_party/blink/renderer/core/svg/animation/element_smil_animations.h
index b3852201b..4904759 100644
--- a/third_party/blink/renderer/core/svg/animation/element_smil_animations.h
+++ b/third_party/blink/renderer/core/svg/animation/element_smil_animations.h
@@ -6,8 +6,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_ANIMATION_ELEMENT_SMIL_ANIMATIONS_H_
 
 #include "third_party/blink/renderer/core/dom/qualified_name.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/svg/animation/priority_queue.h b/third_party/blink/renderer/core/svg/animation/priority_queue.h
index fe60c68..d7f655e9 100644
--- a/third_party/blink/renderer/core/svg/animation/priority_queue.h
+++ b/third_party/blink/renderer/core/svg/animation/priority_queue.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_ANIMATION_PRIORITY_QUEUE_H_
 
 #include "base/gtest_prod_util.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/svg/animation/smil_time_container.h b/third_party/blink/renderer/core/svg/animation/smil_time_container.h
index 9c37ebf..ef499525 100644
--- a/third_party/blink/renderer/core/svg/animation/smil_time_container.h
+++ b/third_party/blink/renderer/core/svg/animation/smil_time_container.h
@@ -32,9 +32,9 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/svg/animation/priority_queue.h"
 #include "third_party/blink/renderer/core/svg/animation/smil_time.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/timer.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h b/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h
index 552ad34..44660c0c 100644
--- a/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h
+++ b/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h
@@ -24,6 +24,8 @@
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
 #include "third_party/blink/renderer/platform/graphics/interpolation_space.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
diff --git a/third_party/blink/renderer/core/svg/svg_boolean.cc b/third_party/blink/renderer/core/svg/svg_boolean.cc
index ac389e8..c66d09a 100644
--- a/third_party/blink/renderer/core/svg/svg_boolean.cc
+++ b/third_party/blink/renderer/core/svg/svg_boolean.cc
@@ -30,6 +30,8 @@
 
 #include "third_party/blink/renderer/core/svg/svg_boolean.h"
 
+#include "base/notreached.h"
+
 namespace blink {
 
 String SVGBoolean::ValueAsString() const {
diff --git a/third_party/blink/renderer/core/svg/svg_document_extensions.h b/third_party/blink/renderer/core/svg/svg_document_extensions.h
index 3e632cc..8e37da9 100644
--- a/third_party/blink/renderer/core/svg/svg_document_extensions.h
+++ b/third_party/blink/renderer/core/svg/svg_document_extensions.h
@@ -23,6 +23,7 @@
 
 #include "base/dcheck_is_on.h"
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
diff --git a/third_party/blink/renderer/core/svg/svg_enumeration.cc b/third_party/blink/renderer/core/svg/svg_enumeration.cc
index da441d7..4487acd23 100644
--- a/third_party/blink/renderer/core/svg/svg_enumeration.cc
+++ b/third_party/blink/renderer/core/svg/svg_enumeration.cc
@@ -30,6 +30,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_enumeration.h"
 
+#include "base/notreached.h"
 #include "third_party/blink/renderer/core/svg/svg_enumeration_map.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/svg/svg_path_blender.cc b/third_party/blink/renderer/core/svg/svg_path_blender.cc
index 5471bd34..cd4a8f9 100644
--- a/third_party/blink/renderer/core/svg/svg_path_blender.cc
+++ b/third_party/blink/renderer/core/svg/svg_path_blender.cc
@@ -19,6 +19,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_path_blender.h"
 
+#include "base/notreached.h"
 #include "third_party/blink/renderer/core/svg/svg_path_byte_stream_source.h"
 #include "third_party/blink/renderer/core/svg/svg_path_consumer.h"
 #include "third_party/blink/renderer/core/svg/svg_path_data.h"
diff --git a/third_party/blink/renderer/core/svg/svg_path_byte_stream_builder.cc b/third_party/blink/renderer/core/svg/svg_path_byte_stream_builder.cc
index 50302e1..92b1a1a 100644
--- a/third_party/blink/renderer/core/svg/svg_path_byte_stream_builder.cc
+++ b/third_party/blink/renderer/core/svg/svg_path_byte_stream_builder.cc
@@ -19,6 +19,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_path_byte_stream_builder.h"
 
+#include "base/notreached.h"
 #include "third_party/blink/renderer/core/svg/svg_path_byte_stream.h"
 #include "third_party/blink/renderer/core/svg/svg_path_data.h"
 #include "ui/gfx/geometry/point_f.h"
diff --git a/third_party/blink/renderer/core/svg/svg_path_parser.cc b/third_party/blink/renderer/core/svg/svg_path_parser.cc
index 8f1e6bba..5cc45954 100644
--- a/third_party/blink/renderer/core/svg/svg_path_parser.cc
+++ b/third_party/blink/renderer/core/svg/svg_path_parser.cc
@@ -23,6 +23,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_path_parser.h"
 
+#include "base/notreached.h"
 #include "third_party/blink/renderer/core/svg/svg_path_consumer.h"
 #include "third_party/blink/renderer/platform/transforms/affine_transform.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
diff --git a/third_party/blink/renderer/core/svg/svg_path_query.cc b/third_party/blink/renderer/core/svg/svg_path_query.cc
index b987efb..32f80284 100644
--- a/third_party/blink/renderer/core/svg/svg_path_query.cc
+++ b/third_party/blink/renderer/core/svg/svg_path_query.cc
@@ -23,6 +23,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_path_query.h"
 
+#include "base/notreached.h"
 #include "third_party/blink/renderer/core/svg/svg_path_byte_stream_source.h"
 #include "third_party/blink/renderer/core/svg/svg_path_consumer.h"
 #include "third_party/blink/renderer/core/svg/svg_path_data.h"
diff --git a/third_party/blink/renderer/core/svg/svg_path_string_builder.cc b/third_party/blink/renderer/core/svg/svg_path_string_builder.cc
index 2bb160a..75d2312d 100644
--- a/third_party/blink/renderer/core/svg/svg_path_string_builder.cc
+++ b/third_party/blink/renderer/core/svg/svg_path_string_builder.cc
@@ -19,6 +19,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_path_string_builder.h"
 
+#include "base/notreached.h"
 #include "third_party/blink/renderer/core/svg/svg_path_data.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "ui/gfx/geometry/point_f.h"
diff --git a/third_party/blink/renderer/core/svg/svg_resource.h b/third_party/blink/renderer/core/svg/svg_resource.h
index 4b897df..5cf9e7e 100644
--- a/third_party/blink/renderer/core/svg/svg_resource.h
+++ b/third_party/blink/renderer/core/svg/svg_resource.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_RESOURCE_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_RESOURCE_H_
 
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_client.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
diff --git a/third_party/blink/renderer/core/svg/svg_string.cc b/third_party/blink/renderer/core/svg/svg_string.cc
index 3e90b28c..0536337 100644
--- a/third_party/blink/renderer/core/svg/svg_string.cc
+++ b/third_party/blink/renderer/core/svg/svg_string.cc
@@ -19,6 +19,8 @@
 
 #include "third_party/blink/renderer/core/svg/svg_string.h"
 
+#include "base/notreached.h"
+
 namespace blink {
 
 void SVGString::Add(const SVGPropertyBase*, const SVGElement*) {
diff --git a/third_party/blink/renderer/core/svg/svg_string_list.cc b/third_party/blink/renderer/core/svg/svg_string_list.cc
index d9c71752..f2a7032 100644
--- a/third_party/blink/renderer/core/svg/svg_string_list.cc
+++ b/third_party/blink/renderer/core/svg/svg_string_list.cc
@@ -20,6 +20,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_string_list.h"
 
+#include "base/notreached.h"
 #include "third_party/blink/renderer/core/svg/svg_parser_utilities.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_visitor.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
diff --git a/third_party/blink/renderer/core/svg/svg_string_list.h b/third_party/blink/renderer/core/svg/svg_string_list.h
index ec75426..84586e8d 100644
--- a/third_party/blink/renderer/core/svg/svg_string_list.h
+++ b/third_party/blink/renderer/core/svg/svg_string_list.h
@@ -31,6 +31,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_STRING_LIST_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_STRING_LIST_H_
 
+#include "base/notreached.h"
 #include "third_party/blink/renderer/core/svg/properties/svg_property_helper.h"
 #include "third_party/blink/renderer/core/svg/svg_parsing_error.h"
 
diff --git a/third_party/blink/renderer/core/svg/svg_tree_scope_resources.h b/third_party/blink/renderer/core/svg/svg_tree_scope_resources.h
index 568b448f..584cf9a 100644
--- a/third_party/blink/renderer/core/svg/svg_tree_scope_resources.h
+++ b/third_party/blink/renderer/core/svg/svg_tree_scope_resources.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_TREE_SCOPE_RESOURCES_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_TREE_SCOPE_RESOURCES_H_
 
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
diff --git a/third_party/blink/renderer/core/testing/death_aware_script_wrappable.h b/third_party/blink/renderer/core/testing/death_aware_script_wrappable.h
index 4666d039..0436fbf1 100644
--- a/third_party/blink/renderer/core/testing/death_aware_script_wrappable.h
+++ b/third_party/blink/renderer/core/testing/death_aware_script_wrappable.h
@@ -7,6 +7,7 @@
 
 #include <signal.h>
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/testing/mock_function_scope.cc b/third_party/blink/renderer/core/testing/mock_function_scope.cc
index 998ac45..1bae0c2 100644
--- a/third_party/blink/renderer/core/testing/mock_function_scope.cc
+++ b/third_party/blink/renderer/core/testing/mock_function_scope.cc
@@ -7,7 +7,6 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/testing/union_types_test.cc b/third_party/blink/renderer/core/testing/union_types_test.cc
index 9d76b0d..47fd5600 100644
--- a/third_party/blink/renderer/core/testing/union_types_test.cc
+++ b/third_party/blink/renderer/core/testing/union_types_test.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/testing/union_types_test.h"
 
+#include "base/notreached.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_union_double_internalenum.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_union_double_string.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_union_double_string_stringsequence.h"
diff --git a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
index 20e10f5..8be04c3 100644
--- a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
+++ b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
@@ -24,8 +24,8 @@
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h"
diff --git a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h
index 5da5bb8..37c5271c 100644
--- a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h
+++ b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h
@@ -11,7 +11,6 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "v8/include/v8.h"
 
diff --git a/third_party/blink/renderer/core/timing/performance.h b/third_party/blink/renderer/core/timing/performance.h
index 7b492738..3cedaa19 100644
--- a/third_party/blink/renderer/core/timing/performance.h
+++ b/third_party/blink/renderer/core/timing/performance.h
@@ -41,6 +41,8 @@
 #include "third_party/blink/renderer/core/timing/performance_entry.h"
 #include "third_party/blink/renderer/core/timing/performance_navigation_timing.h"
 #include "third_party/blink/renderer/core/timing/performance_paint_timing.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/timer.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
diff --git a/third_party/blink/renderer/core/timing/performance_mark.h b/third_party/blink/renderer/core/timing/performance_mark.h
index 9e75759..9d54982d 100644
--- a/third_party/blink/renderer/core/timing/performance_mark.h
+++ b/third_party/blink/renderer/core/timing/performance_mark.h
@@ -30,7 +30,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
 #include "third_party/blink/renderer/core/timing/performance_entry.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
diff --git a/third_party/blink/renderer/core/timing/performance_measure.h b/third_party/blink/renderer/core/timing/performance_measure.h
index 862b24d..708e1a1 100644
--- a/third_party/blink/renderer/core/timing/performance_measure.h
+++ b/third_party/blink/renderer/core/timing/performance_measure.h
@@ -31,7 +31,6 @@
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
 #include "third_party/blink/renderer/core/timing/performance_entry.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
diff --git a/third_party/blink/renderer/core/timing/performance_user_timing.h b/third_party/blink/renderer/core/timing/performance_user_timing.h
index 2ed451c..f46d846 100644
--- a/third_party/blink/renderer/core/timing/performance_user_timing.h
+++ b/third_party/blink/renderer/core/timing/performance_user_timing.h
@@ -29,7 +29,6 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/renderer/core/timing/performance.h"
 #include "third_party/blink/renderer/core/timing/performance_timing.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/timing/profiler_group.h b/third_party/blink/renderer/core/timing/profiler_group.h
index d673d0d..2cdbd79 100644
--- a/third_party/blink/renderer/core/timing/profiler_group.h
+++ b/third_party/blink/renderer/core/timing/profiler_group.h
@@ -9,7 +9,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/execution_context/security_context.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "v8/include/v8-profiler.h"
diff --git a/third_party/blink/renderer/core/timing/window_performance.h b/third_party/blink/renderer/core/timing/window_performance.h
index 293d8f91..f6ab29397 100644
--- a/third_party/blink/renderer/core/timing/window_performance.h
+++ b/third_party/blink/renderer/core/timing/window_performance.h
@@ -45,7 +45,6 @@
 #include "third_party/blink/renderer/core/timing/performance_navigation.h"
 #include "third_party/blink/renderer/core/timing/performance_timing.h"
 #include "third_party/blink/renderer/core/timing/responsiveness_metrics.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
index 22aa22542..e44fe58 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
@@ -9,7 +9,7 @@
 #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/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h b/third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h
index 974efc75..d34d687 100644
--- a/third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h
+++ b/third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/workers/worklet_module_responses_map.h b/third_party/blink/renderer/core/workers/worklet_module_responses_map.h
index 26dcc2ab..54120b9 100644
--- a/third_party/blink/renderer/core/workers/worklet_module_responses_map.h
+++ b/third_party/blink/renderer/core/workers/worklet_module_responses_map.h
@@ -10,7 +10,6 @@
 #include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
 #include "third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl_hash.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index 20ec745db..dad1191 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -2351,14 +2351,14 @@
   ImageBitmapOptions* options = ImageBitmapOptions::Create();
   ImageBitmap* image_bitmap = nullptr;
   if (auto* image = DynamicTo<HTMLImageElement>(node)) {
-    image_bitmap = MakeGarbageCollected<ImageBitmap>(
-        image, absl::optional<IntRect>(), options);
+    image_bitmap =
+        MakeGarbageCollected<ImageBitmap>(image, absl::nullopt, options);
   } else if (auto* canvas = DynamicTo<HTMLCanvasElement>(node)) {
-    image_bitmap = MakeGarbageCollected<ImageBitmap>(
-        canvas, absl::optional<IntRect>(), options);
+    image_bitmap =
+        MakeGarbageCollected<ImageBitmap>(canvas, absl::nullopt, options);
   } else if (auto* video = DynamicTo<HTMLVideoElement>(node)) {
-    image_bitmap = MakeGarbageCollected<ImageBitmap>(
-        video, absl::optional<IntRect>(), options);
+    image_bitmap =
+        MakeGarbageCollected<ImageBitmap>(video, absl::nullopt, options);
   }
   if (!image_bitmap)
     return String();
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.cc
index c6a06f0..3f83134e 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.cc
@@ -12,7 +12,7 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h"
 #include "third_party/blink/renderer/modules/manifest/image_resource_type_converters.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_impl.h"
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
index 34a26d4..d0b6bfd75 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
@@ -27,8 +27,8 @@
 #include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc
index 3891198..18dfb30 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc
@@ -9,7 +9,6 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_background_fetch_options.h"
 #include "third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h"
 #include "third_party/blink/renderer/modules/manifest/image_resource_type_converters.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 
 namespace mojo {
 
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
index 264fe27..86983e5 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
@@ -434,7 +434,7 @@
     return nullptr;
   CanvasRenderingContext::DidDraw(dirty_rect, draw_type);
   // Always draw everything during printing.
-  if (!layer_count_ && !canvas()->IsPrinting()) {
+  if (!layer_count_) {
     // TODO(crbug.com/1246486): Make auto-flushing layer friendly.
     canvas()
         ->GetCanvas2DLayerBridge()
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
index a46d3e1..cec48d9 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
@@ -146,6 +146,8 @@
 
   enum class ReadFrequencyMode { kWillReadFrequency, kWillNotReadFrequency };
 
+  static constexpr size_t kMaxPinnedImageBytes = 1000;
+
   void CreateContext(
       OpacityMode,
       LatencyMode = kNormalLatency,
@@ -238,6 +240,8 @@
 }
 
 void CanvasRenderingContext2DTest::SetUp() {
+  CanvasResourceProvider::SetMaxPinnedImageBytesForTesting(
+      kMaxPinnedImageBytes);
   test_context_provider_ = CreateContextProvider();
   InitializeSharedGpuContext(test_context_provider_.get());
   allow_accelerated_ =
@@ -287,6 +291,8 @@
 }
 
 void CanvasRenderingContext2DTest::TearDown() {
+  CanvasResourceProvider::ResetMaxPinnedImageBytesForTesting();
+
   ThreadState::Current()->CollectAllGarbageForTesting(
       ThreadState::StackState::kNoHeapPointers);
 
@@ -752,13 +758,13 @@
   ImageBitmap* image_bitmap_derived = nullptr;
   {
     const ImageBitmapOptions* default_options = ImageBitmapOptions::Create();
-    absl::optional<IntRect> crop_rect =
-        IntRect(0, 0, canvas->width(), canvas->height());
+    absl::optional<gfx::Rect> crop_rect =
+        gfx::Rect(0, 0, canvas->width(), canvas->height());
     auto* image_bitmap_from_canvas =
         MakeGarbageCollected<ImageBitmap>(canvas, crop_rect, default_options);
     ASSERT_TRUE(image_bitmap_from_canvas);
 
-    crop_rect = IntRect(0, 0, 20, 20);
+    crop_rect = gfx::Rect(0, 0, 20, 20);
     image_bitmap_derived = MakeGarbageCollected<ImageBitmap>(
         image_bitmap_from_canvas, crop_rect, default_options);
     ASSERT_TRUE(image_bitmap_derived);
@@ -1300,8 +1306,8 @@
 
   Context2D()->fillRect(0, 0, 1, 1);  // Ensure resource provider is created.
 
-  constexpr unsigned int kImageSize = 1024;
-  constexpr unsigned int kBytesPerImage = 4 * kImageSize * kImageSize;
+  constexpr unsigned int kImageSize = 10;
+  constexpr unsigned int kBytesPerImage = 400;
 
   const size_t initial_op_count =
       CanvasElement().ResourceProvider()->TotalOpCount();
@@ -1310,8 +1316,7 @@
   // reset by the Flush.
   for (int repeat = 0; repeat < 2; ++repeat) {
     size_t expected_op_count = initial_op_count;
-    for (size_t pinned_bytes = 0;
-         pinned_bytes <= CanvasResourceProvider::kMaxPinnedImageBytes;
+    for (size_t pinned_bytes = 0; pinned_bytes <= kMaxPinnedImageBytes;
          pinned_bytes += kBytesPerImage) {
       FakeImageSource unique_image(IntSize(kImageSize, kImageSize),
                                    kOpaqueBitmap);
@@ -1338,8 +1343,8 @@
   CanvasElement().SetResourceProviderForTesting(
       nullptr, std::move(fake_accelerate_surface), size);
 
-  constexpr unsigned int kImageSize = 1024;
-  constexpr unsigned int kBytesPerImage = 4 * kImageSize * kImageSize;
+  constexpr unsigned int kImageSize = 10;
+  constexpr unsigned int kBytesPerImage = 400;
 
   FakeImageSource unique_image(IntSize(kImageSize, kImageSize), kOpaqueBitmap);
   NonThrowableExceptionState exception_state;
@@ -1367,13 +1372,12 @@
   Context2D()->fillRect(0, 0, 1, 1);  // Ensure resource provider is created.
   size_t expected_op_count = CanvasElement().ResourceProvider()->TotalOpCount();
 
-  constexpr unsigned int kImageSize = 1024;
-  constexpr unsigned int kBytesPerImage = 4 * kImageSize * kImageSize;
+  constexpr unsigned int kImageSize = 10;
+  constexpr unsigned int kBytesPerImage = 400;
 
   FakeImageSource image(IntSize(kImageSize, kImageSize), kOpaqueBitmap);
 
-  for (size_t pinned_bytes = 0;
-       pinned_bytes <= 2 * CanvasResourceProvider::kMaxPinnedImageBytes;
+  for (size_t pinned_bytes = 0; pinned_bytes <= 2 * kMaxPinnedImageBytes;
        pinned_bytes += kBytesPerImage) {
     NonThrowableExceptionState exception_state;
     Context2D()->drawImage(GetScriptState(), &image, 0, 0, 1, 1, 0, 0, 1, 1,
diff --git a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc
index 0bbe3cc..b906842 100644
--- a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc
+++ b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc
@@ -78,6 +78,18 @@
   kMaxValue = kCreateImageBitmapSourceVideoFrame,
 };
 
+gfx::Rect NormalizedCropRect(int x, int y, int width, int height) {
+  if (width < 0) {
+    x = base::ClampAdd(x, width);
+    width = -width;
+  }
+  if (height < 0) {
+    y = base::ClampAdd(y, height);
+    height = -height;
+  }
+  return gfx::Rect(x, y, width, height);
+}
+
 }  // namespace
 
 inline ImageBitmapSource* ToImageBitmapSourceInternal(
@@ -132,7 +144,7 @@
 ScriptPromise ImageBitmapFactories::CreateImageBitmapFromBlob(
     ScriptState* script_state,
     ImageBitmapSource* bitmap_source,
-    absl::optional<IntRect> crop_rect,
+    absl::optional<gfx::Rect> crop_rect,
     const ImageBitmapOptions* options) {
   DCHECK(script_state->ContextIsValid());
   ImageBitmapFactories& factory = From(*ExecutionContext::From(script_state));
@@ -154,8 +166,8 @@
       ToImageBitmapSourceInternal(bitmap_source, options, false);
   if (!bitmap_source_internal)
     return ScriptPromise();
-  return CreateImageBitmap(script_state, bitmap_source_internal,
-                           absl::optional<IntRect>(), options, exception_state);
+  return CreateImageBitmap(script_state, bitmap_source_internal, absl::nullopt,
+                           options, exception_state);
 }
 
 ScriptPromise ImageBitmapFactories::CreateImageBitmap(
@@ -173,7 +185,7 @@
       ToImageBitmapSourceInternal(bitmap_source, options, true);
   if (!bitmap_source_internal)
     return ScriptPromise();
-  absl::optional<IntRect> crop_rect = IntRect(sx, sy, sw, sh);
+  gfx::Rect crop_rect = NormalizedCropRect(sx, sy, sw, sh);
   return CreateImageBitmap(script_state, bitmap_source_internal, crop_rect,
                            options, exception_state);
 }
@@ -181,7 +193,7 @@
 ScriptPromise ImageBitmapFactories::CreateImageBitmap(
     ScriptState* script_state,
     ImageBitmapSource* bitmap_source,
-    absl::optional<IntRect> crop_rect,
+    absl::optional<gfx::Rect> crop_rect,
     const ImageBitmapOptions* options,
     ExceptionState& exception_state) {
   if (crop_rect && (crop_rect->width() == 0 || crop_rect->height() == 0)) {
@@ -239,7 +251,7 @@
 
 ImageBitmapFactories::ImageBitmapLoader::ImageBitmapLoader(
     ImageBitmapFactories& factory,
-    absl::optional<IntRect> crop_rect,
+    absl::optional<gfx::Rect> crop_rect,
     ScriptState* script_state,
     const ImageBitmapOptions* options)
     : ExecutionContextLifecycleObserver(ExecutionContext::From(script_state)),
diff --git a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h
index 4be00bd..419b8d7 100644
--- a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h
+++ b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h
@@ -80,11 +80,6 @@
                                          int sh,
                                          const ImageBitmapOptions*,
                                          ExceptionState&);
-  static ScriptPromise CreateImageBitmap(ScriptState*,
-                                         ImageBitmapSource*,
-                                         absl::optional<IntRect> crop_rect,
-                                         const ImageBitmapOptions*,
-                                         ExceptionState&);
 
   // window.createImageBitmap()
   static ScriptPromise createImageBitmap(
@@ -142,12 +137,18 @@
   }
 
  private:
+  static ScriptPromise CreateImageBitmap(ScriptState*,
+                                         ImageBitmapSource*,
+                                         absl::optional<gfx::Rect> crop_rect,
+                                         const ImageBitmapOptions*,
+                                         ExceptionState&);
+
   class ImageBitmapLoader final : public GarbageCollected<ImageBitmapLoader>,
                                   public ExecutionContextLifecycleObserver,
                                   public FileReaderLoaderClient {
    public:
     static ImageBitmapLoader* Create(ImageBitmapFactories& factory,
-                                     absl::optional<IntRect> crop_rect,
+                                     absl::optional<gfx::Rect> crop_rect,
                                      const ImageBitmapOptions* options,
                                      ScriptState* script_state) {
       return MakeGarbageCollected<ImageBitmapLoader>(factory, crop_rect,
@@ -155,7 +156,7 @@
     }
 
     ImageBitmapLoader(ImageBitmapFactories&,
-                      absl::optional<IntRect> crop_rect,
+                      absl::optional<gfx::Rect> crop_rect,
                       ScriptState*,
                       const ImageBitmapOptions*);
 
@@ -192,7 +193,7 @@
     std::unique_ptr<FileReaderLoader> loader_;
     Member<ImageBitmapFactories> factory_;
     Member<ScriptPromiseResolver> resolver_;
-    absl::optional<IntRect> crop_rect_;
+    absl::optional<gfx::Rect> crop_rect_;
     Member<const ImageBitmapOptions> options_;
   };
 
@@ -200,7 +201,7 @@
   static ScriptPromise CreateImageBitmapFromBlob(
       ScriptState*,
       ImageBitmapSource*,
-      absl::optional<IntRect> crop_rect,
+      absl::optional<gfx::Rect> crop_rect,
       const ImageBitmapOptions*);
 
   void AddLoader(ImageBitmapLoader*);
diff --git a/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.h b/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.h
index e7ce5ed..e25dccc0 100644
--- a/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.h
+++ b/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.h
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_cookie_list_item.h"
 #include "third_party/blink/renderer/modules/event_modules.h"
 #include "third_party/blink/renderer/modules/service_worker/extendable_event.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
index e598059a..7d30e6c9 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
+++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
@@ -34,7 +34,7 @@
 #include "third_party/blink/renderer/modules/credentialmanager/password_credential.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
diff --git a/third_party/blink/renderer/modules/csspaint/paint_worklet_pending_generator_registry.h b/third_party/blink/renderer/modules/csspaint/paint_worklet_pending_generator_registry.h
index 1694013..3133913 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_worklet_pending_generator_registry.h
+++ b/third_party/blink/renderer/modules/csspaint/paint_worklet_pending_generator_registry.h
@@ -6,8 +6,9 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_PAINT_WORKLET_PENDING_GENERATOR_REGISTRY_H_
 
 #include "third_party/blink/renderer/modules/csspaint/css_paint_image_generator_impl.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/direct_sockets/navigator_socket.h b/third_party/blink/renderer/modules/direct_sockets/navigator_socket.h
index 5834045..db9f510 100644
--- a/third_party/blink/renderer/modules/direct_sockets/navigator_socket.h
+++ b/third_party/blink/renderer/modules/direct_sockets/navigator_socket.h
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/exception_code.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
diff --git a/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h b/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h
index caa619a..8f173f7c 100644
--- a/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h
+++ b/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h
@@ -39,6 +39,7 @@
 #include "third_party/blink/renderer/modules/encryptedmedia/encrypted_media_utils.h"
 #include "third_party/blink/renderer/modules/encryptedmedia/media_key_status_map.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/prefinalizer.h"
 #include "third_party/blink/renderer/platform/timer.h"
diff --git a/third_party/blink/renderer/modules/encryptedmedia/media_keys.h b/third_party/blink/renderer/modules/encryptedmedia/media_keys.h
index 82ce887..0bae98f 100644
--- a/third_party/blink/renderer/modules/encryptedmedia/media_keys.h
+++ b/third_party/blink/renderer/modules/encryptedmedia/media_keys.h
@@ -37,6 +37,8 @@
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h"
 #include "third_party/blink/renderer/modules/encryptedmedia/encrypted_media_utils.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/timer.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_access_capacity_tracker.cc b/third_party/blink/renderer/modules/file_system_access/file_system_access_capacity_tracker.cc
index f2c7fec5..630b6e4e 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_access_capacity_tracker.cc
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_access_capacity_tracker.cc
@@ -12,6 +12,7 @@
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_capacity_allocation_host.mojom-blink.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace {
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.h b/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.h
index dde33c78..6ecde8f 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.h
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.h
@@ -16,6 +16,7 @@
 #include "third_party/blink/renderer/modules/file_system_access/file_system_access_capacity_tracker.h"
 #include "third_party/blink/renderer/modules/file_system_access/file_system_access_file_delegate.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 
 #if defined(OS_MAC)
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.h b/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.h
index cddaacad..d6506d8 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.h
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.h
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.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/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 
diff --git a/third_party/blink/renderer/modules/filesystem/dragged_isolated_file_system_impl.h b/third_party/blink/renderer/modules/filesystem/dragged_isolated_file_system_impl.h
index f56254d..a6e7173 100644
--- a/third_party/blink/renderer/modules/filesystem/dragged_isolated_file_system_impl.h
+++ b/third_party/blink/renderer/modules/filesystem/dragged_isolated_file_system_impl.h
@@ -34,7 +34,6 @@
 #include "third_party/blink/renderer/core/clipboard/data_object.h"
 #include "third_party/blink/renderer/core/clipboard/dragged_isolated_file_system.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
index 3e70203..d9136b51 100644
--- a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
+++ b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
@@ -12,7 +12,6 @@
 #include "third_party/blink/renderer/modules/filesystem/file_system_callbacks.h"
 #include "third_party/blink/renderer/platform/heap/disallow_new_wrapper.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
diff --git a/third_party/blink/renderer/modules/font_access/font_manager.h b/third_party/blink/renderer/modules/font_access/font_manager.h
index 80d5011..7813acd 100644
--- a/third_party/blink/renderer/modules/font_access/font_manager.h
+++ b/third_party/blink/renderer/modules/font_access/font_manager.h
@@ -12,7 +12,6 @@
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad_button.h b/third_party/blink/renderer/modules/gamepad/gamepad_button.h
index f53621c..f0c18c2 100644
--- a/third_party/blink/renderer/modules/gamepad/gamepad_button.h
+++ b/third_party/blink/renderer/modules/gamepad/gamepad_button.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_GAMEPAD_GAMEPAD_BUTTON_H_
 
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 
 namespace device {
diff --git a/third_party/blink/renderer/modules/geolocation/geolocation_watchers.h b/third_party/blink/renderer/modules/geolocation/geolocation_watchers.h
index b1edaf5..f8337e2 100644
--- a/third_party/blink/renderer/modules/geolocation/geolocation_watchers.h
+++ b/third_party/blink/renderer/modules/geolocation/geolocation_watchers.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_GEOLOCATION_GEOLOCATION_WATCHERS_H_
 
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/hid/hid_device.h b/third_party/blink/renderer/modules/hid/hid_device.h
index e81aee6..fb3de36 100644
--- a/third_party/blink/renderer/modules/hid/hid_device.h
+++ b/third_party/blink/renderer/modules/hid/hid_device.h
@@ -16,7 +16,7 @@
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
diff --git a/third_party/blink/renderer/modules/idle/idle_detector.h b/third_party/blink/renderer/modules/idle/idle_detector.h
index 000746e5..2a23e06 100644
--- a/third_party/blink/renderer/modules/idle/idle_detector.h
+++ b/third_party/blink/renderer/modules/idle/idle_detector.h
@@ -16,7 +16,6 @@
 #include "third_party/blink/renderer/modules/event_modules.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/timer.h"
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.h b/third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.h
index a6c314b..3a83601 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.h
+++ b/third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.h
@@ -12,6 +12,7 @@
 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_transaction.h b/third_party/blink/renderer/modules/indexeddb/idb_transaction.h
index 3e3cade..f127fd4c 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_transaction.h
+++ b/third_party/blink/renderer/modules/indexeddb/idb_transaction.h
@@ -42,6 +42,8 @@
 #include "third_party/blink/renderer/modules/indexeddb/web_idb_database.h"
 #include "third_party/blink/renderer/modules/indexeddb/web_idb_transaction.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
diff --git a/third_party/blink/renderer/modules/installedapp/installed_app_controller.h b/third_party/blink/renderer/modules/installedapp/installed_app_controller.h
index a806edf..f1d62dc 100644
--- a/third_party/blink/renderer/modules/installedapp/installed_app_controller.h
+++ b/third_party/blink/renderer/modules/installedapp/installed_app_controller.h
@@ -16,7 +16,7 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
diff --git a/third_party/blink/renderer/modules/launch/dom_window_launch_queue.h b/third_party/blink/renderer/modules/launch/dom_window_launch_queue.h
index deb7bc8c..36af980 100644
--- a/third_party/blink/renderer/modules/launch/dom_window_launch_queue.h
+++ b/third_party/blink/renderer/modules/launch/dom_window_launch_queue.h
@@ -7,10 +7,10 @@
 
 #include "third_party/blink/renderer/modules/launch/launch_params.h"
 #include "third_party/blink/renderer/modules/launch/launch_queue.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
diff --git a/third_party/blink/renderer/modules/launch/file_handling_expiry_impl.cc b/third_party/blink/renderer/modules/launch/file_handling_expiry_impl.cc
index 7300959..eda0518 100644
--- a/third_party/blink/renderer/modules/launch/file_handling_expiry_impl.cc
+++ b/third_party/blink/renderer/modules/launch/file_handling_expiry_impl.cc
@@ -12,7 +12,6 @@
 #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
 #include "third_party/blink/renderer/core/script/script.h"
 #include "third_party/blink/renderer/modules/launch/dom_window_launch_queue.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/launch/launch_params.h b/third_party/blink/renderer/modules/launch/launch_params.h
index ace35e23..f2c6631 100644
--- a/third_party/blink/renderer/modules/launch/launch_params.h
+++ b/third_party/blink/renderer/modules/launch/launch_params.h
@@ -7,8 +7,8 @@
 
 #include "third_party/blink/renderer/modules/file_system_access/file_system_handle.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 
diff --git a/third_party/blink/renderer/modules/launch/launch_queue.h b/third_party/blink/renderer/modules/launch/launch_queue.h
index bd4086bf..925aaa75 100644
--- a/third_party/blink/renderer/modules/launch/launch_queue.h
+++ b/third_party/blink/renderer/modules/launch/launch_queue.h
@@ -7,8 +7,8 @@
 
 #include "third_party/blink/renderer/modules/launch/launch_params.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/locks/lock_manager.h b/third_party/blink/renderer/modules/locks/lock_manager.h
index 67a70b9..341cd7e 100644
--- a/third_party/blink/renderer/modules/locks/lock_manager.h
+++ b/third_party/blink/renderer/modules/locks/lock_manager.h
@@ -12,7 +12,6 @@
 #include "third_party/blink/renderer/modules/locks/lock.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
diff --git a/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc b/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc
index 2ab4dfa..bcf1916 100644
--- a/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc
+++ b/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc
@@ -62,8 +62,8 @@
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/to_v8.h"
 #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
diff --git a/third_party/blink/renderer/modules/mediasource/track_default_list.cc b/third_party/blink/renderer/modules/mediasource/track_default_list.cc
index a1c58cab..8676386 100644
--- a/third_party/blink/renderer/modules/mediasource/track_default_list.cc
+++ b/third_party/blink/renderer/modules/mediasource/track_default_list.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/mediasource/track_default_list.h"
 
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc b/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc
index a338881..70769555 100644
--- a/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc
@@ -368,8 +368,6 @@
     } else if (constraint.name_.Equals(kUseRtpMux)) {
       result.goog_use_rtp_mux.SetExact(ToBoolean(constraint.value_));
     } else if (constraint.name_.Equals(kEnableDtlsSrtp)) {
-      // This constraint has no effect since Chrome M97.
-      // It only prints a deprecation notice.
       bool value = ToBoolean(constraint.value_);
       if (value) {
         Deprecation::CountDeprecation(
@@ -378,6 +376,7 @@
         Deprecation::CountDeprecation(
             context, WebFeature::kRTCConstraintEnableDtlsSrtpFalse);
       }
+      result.enable_dtls_srtp.SetExact(ToBoolean(constraint.value_));
     } else if (constraint.name_.Equals(kEnableRtpDataChannels)) {
       // This constraint does not turn on RTP data channels, but we do not
       // want it to cause an error, so we parse it and ignore it.
diff --git a/third_party/blink/renderer/modules/mediastream/media_device_info.h b/third_party/blink/renderer/modules/mediastream/media_device_info.h
index 4b2b3ba..6af223a 100644
--- a/third_party/blink/renderer/modules/mediastream/media_device_info.h
+++ b/third_party/blink/renderer/modules/mediastream/media_device_info.h
@@ -29,7 +29,7 @@
 #include "third_party/blink/public/mojom/mediastream/media_devices.mojom-blink-forward.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.cc b/third_party/blink/renderer/modules/mediastream/media_devices.cc
index 7c95810..647e7f7 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/guid.h"
 #include "base/metrics/histogram_functions.h"
 #include "build/build_config.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -338,14 +339,26 @@
     ScriptState* script_state,
     V8UnionHTMLDivElementOrHTMLIFrameElement* element_union,
     ExceptionState& exception_state) {
+  DCHECK(IsMainThread());
+
+#if defined(OS_ANDROID)
+  exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
+                                    "Unsupported.");
+  return ScriptPromise();
+#else
   if (!script_state->ContextIsValid()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
                                       "Current frame is detached.");
     return ScriptPromise();
   }
 
-  auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
-  ScriptPromise promise = resolver->Promise();
+  LocalDOMWindow* const window = To<LocalDOMWindow>(GetExecutionContext());
+  if (!window) {
+    exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
+                                      "Missing execution context.");
+    return ScriptPromise();
+  }
+
   auto* element =
       element_union->IsHTMLDivElement()
           ? static_cast<Element*>(element_union->GetAsHTMLDivElement())
@@ -353,30 +366,35 @@
 
   const RegionCaptureCropId* const old_crop_id =
       element->GetRegionCaptureCropId();
-  if (old_crop_id) {  // produceCropId() previously called on this element.
+  if (old_crop_id) {
+    // The Element has a crop-ID which was previously produced.
     DCHECK(!old_crop_id->value().is_zero());
+    auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+    const ScriptPromise promise = resolver->Promise();
     resolver->Resolve(WTF::String(
         blink::TokenToGUID(old_crop_id->value()).AsLowercaseString()));
     return promise;
   }
 
-  // TODO(crbug.com/1247761): Produce the crop-ID in the browser process,
-  // where it's free from interference by potential malicious applications
-  // trying to produce collisions. Also, we need it there in order to
-  // validate IDs provided to cropTo() for (1) validity and (2) association
-  // with the current browsing context.
-  const base::GUID new_crop_id = base::GUID::GenerateRandomV4();
-  element->SetRegionCaptureCropId(
-      std::make_unique<RegionCaptureCropId>(blink::GUIDToToken(new_crop_id)));
+  const auto it = crop_id_resolvers_.find(element);
+  if (it != crop_id_resolvers_.end()) {
+    // The Element does not yet have a crop-ID, but the production of one
+    // has already been kicked off, and a response will soon arrive from
+    // the browser process. The Promise we return here will be resolved along
+    // with the original one.
+    return it->value->Promise();
+  }
 
-  // TODO(crbug.com/1247761): Delay resolution until ack from Viz received.
-  // Multiple calls to produceCropId() will be handled by returning distinct
-  // Promises which are all fulfilled (in sequence) when the first one is
-  // fulfilled.
-  const std::string& serialized_crop_id = new_crop_id.AsLowercaseString();
-  resolver->Resolve(
-      WTF::String(serialized_crop_id.c_str(), serialized_crop_id.length()));
+  // Mints a new crop-ID on the browser process. Resolve when it's produced
+  // and ready to be used.
+  auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  crop_id_resolvers_.insert(element, resolver);
+  const ScriptPromise promise = resolver->Promise();
+  GetDispatcherHost(window->GetFrame())
+      ->ProduceCropId(WTF::Bind(&MediaDevices::ResolveProduceCropIdPromise,
+                                WrapPersistent(this), WrapPersistent(element)));
   return promise;
+#endif
 }
 
 const AtomicString& MediaDevices::InterfaceName() const {
@@ -624,6 +642,9 @@
   visitor->Trace(receiver_);
   visitor->Trace(scheduled_events_);
   visitor->Trace(requests_);
+#if !defined(OS_ANDROID)
+  visitor->Trace(crop_id_resolvers_);
+#endif
   Supplement<Navigator>::Trace(visitor);
   EventTargetWithInlineData::Trace(visitor);
   ExecutionContextLifecycleObserver::Trace(visitor);
@@ -659,6 +680,29 @@
 
   GetDispatcherHost(window->GetFrame())->CloseFocusWindowOfOpportunity(id);
 }
+
+// An empty |crop_id| signals failure; anything else has to be a valid GUID
+// and signals success.
+void MediaDevices::ResolveProduceCropIdPromise(Element* element,
+                                               const WTF::String& crop_id) {
+  DCHECK(IsMainThread());
+  DCHECK(element);  // Persistent.
+
+  const auto it = crop_id_resolvers_.find(element);
+  DCHECK_NE(it, crop_id_resolvers_.end());
+  ScriptPromiseResolver* const resolver = it->value;
+  crop_id_resolvers_.erase(it);
+
+  if (crop_id.IsEmpty()) {
+    resolver->Reject();
+  } else {
+    const base::GUID guid = base::GUID::ParseLowercase(crop_id.Ascii());
+    DCHECK(guid.is_valid());
+    element->SetRegionCaptureCropId(
+        std::make_unique<RegionCaptureCropId>(blink::GUIDToToken(guid)));
+    resolver->Resolve(crop_id);
+  }
+}
 #endif
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.h b/third_party/blink/renderer/modules/mediastream/media_devices.h
index 00e06a7..62587df 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.h
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.h
@@ -12,6 +12,7 @@
 #include "third_party/blink/public/mojom/mediastream/media_devices.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_union_htmldivelement_htmliframeelement.h"
+#include "third_party/blink/renderer/core/dom/element.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/modules/event_target_modules.h"
@@ -19,7 +20,7 @@
 #include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
 #include "third_party/blink/renderer/modules/mediastream/user_media_request.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
@@ -141,6 +142,11 @@
   void EnqueueMicrotaskToCloseFocusWindowOfOpportunity(const String&,
                                                        MediaStreamTrack*);
   void CloseFocusWindowOfOpportunity(const String&, MediaStreamTrack*);
+
+  // Receives a message from the browser process with the crop-ID it has
+  // assigned to |element|.
+  void ResolveProduceCropIdPromise(Element* element,
+                                   const WTF::String& crop_id);
 #endif
 
   bool stopped_;
@@ -152,6 +158,25 @@
   HeapMojoReceiver<mojom::blink::MediaDevicesListener, MediaDevices> receiver_;
   HeapHashSet<Member<ScriptPromiseResolver>> requests_;
 
+#if !defined(OS_ANDROID)
+  // 1. When produceCropId() is first called for an Element, it has no crop-ID
+  //    associated. We produce a Resolver, map the Element to it, and fire
+  //    off a message to the browser process, asking for a new crop-ID to be
+  //    generated.
+  // 2. Subsequent calls to produceCropId(), which occur before the browser
+  //    process has had time to respond, yield a copy of the original Promise
+  //    associated with this Element.
+  // 3. When the message browser process responds with a crop-ID for the
+  //    Element, we store the new crop-ID on the Element itself, resolve all
+  //    Promises returned for this Element, and eject the resolver from this
+  //    container.
+  // 4. Later calls to produceCropId() for this given Element discover that
+  //    a crop-ID is already assigned. They immediately return a resolved
+  //    Promise with the crop-ID.
+  HeapHashMap<Member<Element>, Member<ScriptPromiseResolver>>
+      crop_id_resolvers_;
+#endif
+
   EnumerateDevicesTestCallback enumerate_devices_test_callback_;
   base::OnceClosure connection_error_test_callback_;
   base::OnceClosure device_change_test_callback_;
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices_test.cc b/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
index 2734eeb..256686b 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
@@ -204,6 +204,16 @@
 
 #if !defined(OS_ANDROID)
   void CloseFocusWindowOfOpportunity(const String& label) override {}
+
+  void ProduceCropId(ProduceCropIdCallback callback) override {
+    String next_crop_id = "";  // Empty, not null.
+    std::swap(next_crop_id_, next_crop_id);
+    std::move(callback).Run(std::move(next_crop_id));
+  }
+
+  void SetNextCropId(String next_crop_id) {
+    next_crop_id_ = std::move(next_crop_id);
+  }
 #endif
 
   void ExpectSetCaptureHandleConfig(
@@ -234,6 +244,9 @@
   mojo::Remote<mojom::blink::MediaDevicesListener> listener_;
   mojo::Receiver<mojom::blink::MediaDevicesDispatcherHost> receiver_{this};
   mojom::blink::CaptureHandleConfigPtr expected_capture_handle_config_;
+#if !defined(OS_ANDROID)
+  String next_crop_id_ = "";  // Empty, not null.
+#endif
 };
 
 class MediaDevicesTest : public PageTestBase {
@@ -706,6 +719,33 @@
             ToExceptionCode(DOMExceptionCode::kNotSupportedError));
 }
 
+// Note: This test runs on non-Android too in order to prove that the test
+// itself is sane. (Rather than, for example, an exception always being thrown.)
+TEST_F(MediaDevicesTest, ProduceCropIdUnsupportedOnAndroid) {
+  V8TestingScope scope;
+  auto* media_devices = GetMediaDevices(scope.GetWindow());
+  ASSERT_TRUE(media_devices);
+
+  SetBodyContent(R"HTML(
+    <div id='test-div'></div>
+    <iframe id='test-iframe' src="about:blank" />
+  )HTML");
+
+  Document& document = GetDocument();
+  auto div = V8UnionHTMLDivElementOrHTMLIFrameElement(
+      reinterpret_cast<HTMLDivElement*>(document.getElementById("test-div")));
+  const ScriptPromise div_promise = media_devices->produceCropId(
+      scope.GetScriptState(), &div, scope.GetExceptionState());
+  platform()->RunUntilIdle();
+#if defined(OS_ANDROID)
+  EXPECT_TRUE(scope.GetExceptionState().HadException());
+#else  // Non-Android shown to work, proving the test is sane.
+  EXPECT_FALSE(div_promise.IsEmpty());
+  EXPECT_FALSE(scope.GetExceptionState().HadException());
+#endif
+}
+
+#if !defined(OS_ANDROID)
 TEST_F(MediaDevicesTest, ProduceCropIdWithValidElement) {
   V8TestingScope scope;
   auto* media_devices = GetMediaDevices(scope.GetWindow());
@@ -739,6 +779,8 @@
   V8TestingScope scope;
   auto* media_devices = GetMediaDevices(scope.GetWindow());
   ASSERT_TRUE(media_devices);
+  dispatcher_host().SetNextCropId(
+      String(base::GUID::GenerateRandomV4().AsLowercaseString()));
 
   SetBodyContent(R"HTML(
     <div id='test-div'></div>
@@ -780,6 +822,8 @@
   Document& document = GetDocument();
   auto div = V8UnionHTMLDivElementOrHTMLIFrameElement(
       reinterpret_cast<HTMLDivElement*>(document.getElementById("test-div")));
+  dispatcher_host().SetNextCropId(
+      String(base::GUID::GenerateRandomV4().AsLowercaseString()));
   const ScriptPromise promise = media_devices->produceCropId(
       scope.GetScriptState(), &div, scope.GetExceptionState());
   ScriptPromiseTester tester(scope.GetScriptState(), promise);
@@ -792,5 +836,6 @@
   EXPECT_TRUE(result.ContainsOnlyASCIIOrEmpty());
   EXPECT_TRUE(base::GUID::ParseLowercase(result.Ascii()).is_valid());
 }
+#endif
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_track.cc b/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
index fa802bb..be9ca45 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
@@ -60,8 +60,8 @@
 #include "third_party/blink/renderer/modules/mediastream/processed_local_audio_source.h"
 #include "third_party/blink/renderer/modules/mediastream/user_media_controller.h"
 #include "third_party/blink/renderer/modules/mediastream/webaudio_media_stream_audio_sink.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_web_audio_source.h"
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc
index 7fba0313..2fb181be 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc
@@ -115,7 +115,7 @@
     VideoCaptureDeliverFrameCB frame_callback,
     EncodedVideoFrameCB encoded_frame_callback) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  state_ = STARTING;
+  state_ = kStarting;
   frame_callback_ = std::move(frame_callback);
   source_->StartCapture(
       capture_params_, frame_callback_,
@@ -135,11 +135,11 @@
 
 void MediaStreamVideoCapturerSource::StopSourceForRestartImpl() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (state_ != STARTED) {
+  if (state_ != kStarted) {
     OnStopForRestartDone(false);
     return;
   }
-  state_ = STOPPING_FOR_RESTART;
+  state_ = kStoppingForRestart;
   source_->StopCapture();
 
   // Force state update for nondevice sources, since they do not
@@ -153,7 +153,7 @@
   DCHECK(new_format.IsValid());
   media::VideoCaptureParams new_capture_params = capture_params_;
   new_capture_params.requested_format = new_format;
-  state_ = RESTARTING;
+  state_ = kRestarting;
   source_->StartCapture(
       new_capture_params, frame_callback_,
       WTF::BindRepeating(&MediaStreamVideoCapturerSource::OnRunStateChanged,
@@ -177,11 +177,11 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(device_capturer_factory_callback_);
 
-  if (state_ != STARTED) {
+  if (state_ != kStarted) {
     return;
   }
 
-  state_ = STOPPING_FOR_CHANGE_SOURCE;
+  state_ = kStoppingForChangeSource;
   source_->StopCapture();
   SetDevice(new_device);
   source_ = device_capturer_factory_callback_.Run(new_device.session_id());
@@ -208,44 +208,44 @@
     bool is_running) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   switch (state_) {
-    case STARTING:
+    case kStarting:
       source_->OnLog("MediaStreamVideoCapturerSource sending OnStartDone");
       if (is_running) {
-        state_ = STARTED;
+        state_ = kStarted;
         DCHECK(capture_params_ == new_capture_params);
         OnStartDone(mojom::blink::MediaStreamRequestResult::OK);
       } else {
-        state_ = STOPPED;
+        state_ = kStopped;
         OnStartDone(
             mojom::blink::MediaStreamRequestResult::TRACK_START_FAILURE_VIDEO);
       }
       break;
-    case STARTED:
+    case kStarted:
       if (!is_running) {
-        state_ = STOPPED;
+        state_ = kStopped;
         StopSource();
       }
       break;
-    case STOPPING_FOR_RESTART:
+    case kStoppingForRestart:
       source_->OnLog(
           "MediaStreamVideoCapturerSource sending OnStopForRestartDone");
-      state_ = is_running ? STARTED : STOPPED;
+      state_ = is_running ? kStarted : kStopped;
       OnStopForRestartDone(!is_running);
       break;
-    case STOPPING_FOR_CHANGE_SOURCE:
-      state_ = is_running ? STARTED : STOPPED;
+    case kStoppingForChangeSource:
+      state_ = is_running ? kStarted : kStopped;
       break;
-    case RESTARTING:
+    case kRestarting:
       if (is_running) {
-        state_ = STARTED;
+        state_ = kStarted;
         capture_params_ = new_capture_params;
       } else {
-        state_ = STOPPED;
+        state_ = kStopped;
       }
       source_->OnLog("MediaStreamVideoCapturerSource sending OnRestartDone");
       OnRestartDone(is_running);
       break;
-    case STOPPED:
+    case kStopped:
       break;
   }
 }
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h
index e1182b4b..60e28d2 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h
@@ -104,14 +104,14 @@
   std::unique_ptr<VideoCapturerSource> source_;
 
   enum State {
-    STARTING,
-    STARTED,
-    STOPPING_FOR_RESTART,
-    STOPPING_FOR_CHANGE_SOURCE,
-    RESTARTING,
-    STOPPED
+    kStarting,
+    kStarted,
+    kStoppingForRestart,
+    kStoppingForChangeSource,
+    kRestarting,
+    kStopped
   };
-  State state_ = STOPPED;
+  State state_ = kStopped;
 
   media::VideoCaptureParams capture_params_;
   VideoCaptureDeliverFrameCB frame_callback_;
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.cc
index 8d6c890..0ee0568 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.cc
@@ -38,7 +38,7 @@
       : main_render_task_runner_(std::move(main_render_task_runner)),
         repaint_cb_(repaint_cb),
         media_stream_video_renderer_sink_(media_stream_video_renderer_sink),
-        state_(STOPPED),
+        state_(kStopped),
         frame_size_(kMinFrameSize, kMinFrameSize),
         emit_frame_drop_events_(true) {
     DETACH_FROM_THREAD(io_thread_checker_);
@@ -49,7 +49,7 @@
 
   ~FrameDeliverer() {
     DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
-    DCHECK(state_ == STARTED || state_ == PAUSED) << state_;
+    DCHECK(state_ == kStarted || state_ == kPaused) << state_;
   }
 
   void OnVideoFrame(scoped_refptr<media::VideoFrame> frame,
@@ -63,7 +63,7 @@
                          TRACE_EVENT_SCOPE_THREAD, "timestamp",
                          frame->timestamp().InMilliseconds());
 
-    if (state_ != STARTED) {
+    if (state_ != kStarted) {
       if (emit_frame_drop_events_) {
         emit_frame_drop_events_ = false;
         PostCrossThreadTask(
@@ -90,8 +90,8 @@
     // of available buffers. E.g, video that originates from a video camera.
     scoped_refptr<media::VideoFrame> video_frame =
         media::VideoFrame::CreateBlackFrame(
-            state_ == STOPPED ? gfx::Size(kMinFrameSize, kMinFrameSize)
-                              : frame_size_);
+            state_ == kStopped ? gfx::Size(kMinFrameSize, kMinFrameSize)
+                               : frame_size_);
     if (!video_frame)
       return;
 
@@ -102,20 +102,20 @@
 
   void Start() {
     DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
-    DCHECK_EQ(state_, STOPPED);
-    SetState(STARTED);
+    DCHECK_EQ(state_, kStopped);
+    SetState(kStarted);
   }
 
   void Resume() {
     DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
-    if (state_ == PAUSED)
-      SetState(STARTED);
+    if (state_ == kPaused)
+      SetState(kStarted);
   }
 
   void Pause() {
     DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
-    if (state_ == STARTED)
-      SetState(PAUSED);
+    if (state_ == kStarted)
+      SetState(kPaused);
   }
 
  private:
@@ -234,7 +234,7 @@
 MediaStreamVideoRendererSink::GetStateForTesting() {
   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
   if (!frame_deliverer_)
-    return STOPPED;
+    return kStopped;
   return frame_deliverer_->state_;
 }
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.h b/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.h
index e1867f7..1cd1f97 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.h
@@ -60,9 +60,9 @@
  private:
   friend class MediaStreamVideoRendererSinkTest;
   enum State {
-    STARTED,
-    PAUSED,
-    STOPPED,
+    kStarted,
+    kPaused,
+    kStopped,
   };
 
   // MediaStreamVideoSink implementation. Called on the main thread.
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink_test.cc
index 25709acf..da332d10 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink_test.cc
@@ -79,17 +79,17 @@
   bool IsInStartedState() const {
     RunIOUntilIdle();
     return media_stream_video_renderer_sink_->GetStateForTesting() ==
-           MediaStreamVideoRendererSink::STARTED;
+           MediaStreamVideoRendererSink::kStarted;
   }
   bool IsInStoppedState() const {
     RunIOUntilIdle();
     return media_stream_video_renderer_sink_->GetStateForTesting() ==
-           MediaStreamVideoRendererSink::STOPPED;
+           MediaStreamVideoRendererSink::kStopped;
   }
   bool IsInPausedState() const {
     RunIOUntilIdle();
     return media_stream_video_renderer_sink_->GetStateForTesting() ==
-           MediaStreamVideoRendererSink::PAUSED;
+           MediaStreamVideoRendererSink::kPaused;
   }
 
   void OnVideoFrame(scoped_refptr<media::VideoFrame> frame) {
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_client.h b/third_party/blink/renderer/modules/mediastream/user_media_client.h
index e6d89a1..ef016698 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_client.h
+++ b/third_party/blink/renderer/modules/mediastream/user_media_client.h
@@ -18,6 +18,7 @@
 #include "third_party/blink/renderer/modules/mediastream/user_media_processor.h"
 #include "third_party/blink/renderer/modules/mediastream/user_media_request.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc b/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc
index a689774..6daedfc 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc
@@ -268,6 +268,10 @@
   void CloseFocusWindowOfOpportunity(const String& label) override {
     NOTREACHED();
   }
+
+  void ProduceCropId(ProduceCropIdCallback callback) override {
+    std::move(callback).Run("");
+  }
 #endif
 
   void GetAllVideoInputDeviceFormats(
@@ -308,10 +312,10 @@
 };
 
 enum RequestState {
-  REQUEST_NOT_STARTED,
-  REQUEST_NOT_COMPLETE,
-  REQUEST_SUCCEEDED,
-  REQUEST_FAILED,
+  kRequestNotStarted,
+  kRequestNotComplete,
+  kRequestSucceeded,
+  kRequestFailed,
 };
 
 class UserMediaProcessorUnderTest : public UserMediaProcessor {
@@ -420,14 +424,14 @@
   void GetUserMediaRequestSucceeded(MediaStreamDescriptor* descriptor,
                                     UserMediaRequest* request_info) override {
     last_generated_descriptor_ = descriptor;
-    *state_ = REQUEST_SUCCEEDED;
+    *state_ = kRequestSucceeded;
   }
 
   void GetUserMediaRequestFailed(
       blink::mojom::blink::MediaStreamRequestResult result,
       const String& constraint_name) override {
     last_generated_descriptor_ = nullptr;
-    *state_ = REQUEST_FAILED;
+    *state_ = kRequestFailed;
     result_ = result;
     constraint_name_ = constraint_name;
   }
@@ -470,7 +474,7 @@
         state_(state) {}
 
   void RequestUserMediaForTest(UserMediaRequest* user_media_request) {
-    *state_ = REQUEST_NOT_COMPLETE;
+    *state_ = kRequestNotComplete;
     RequestUserMedia(user_media_request);
     base::RunLoop().RunUntilIdle();
   }
@@ -544,7 +548,7 @@
     user_media_client_impl_->RequestUserMediaForTest();
     StartMockedVideoSource();
 
-    EXPECT_EQ(REQUEST_SUCCEEDED, request_state());
+    EXPECT_EQ(kRequestSucceeded, request_state());
 
     MediaStreamDescriptor* desc =
         user_media_processor_->last_generated_descriptor();
@@ -562,7 +566,7 @@
         MediaConstraints(), CreateDefaultConstraints());
     user_media_client_impl_->RequestUserMediaForTest(user_media_request);
     StartMockedVideoSource();
-    EXPECT_EQ(REQUEST_SUCCEEDED, request_state());
+    EXPECT_EQ(kRequestSucceeded, request_state());
 
     MediaStreamDescriptor* descriptor =
         user_media_processor_->last_generated_descriptor();
@@ -584,7 +588,7 @@
         constraint_factory.CreateMediaConstraints(), MediaConstraints());
     user_media_client_impl_->RequestUserMediaForTest(user_media_request);
 
-    EXPECT_EQ(REQUEST_SUCCEEDED, request_state());
+    EXPECT_EQ(kRequestSucceeded, request_state());
 
     MediaStreamDescriptor* desc =
         user_media_processor_->last_generated_descriptor();
@@ -624,7 +628,7 @@
     user_media_client_impl_->RequestUserMediaForTest(request);
     StartMockedVideoSource();
 
-    EXPECT_EQ(REQUEST_SUCCEEDED, request_state());
+    EXPECT_EQ(kRequestSucceeded, request_state());
     EXPECT_EQ(1U, mock_dispatcher_host_.audio_devices().size());
     EXPECT_EQ(1U, mock_dispatcher_host_.video_devices().size());
     // MockMojoMediaStreamDispatcherHost appends its internal session ID to its
@@ -670,7 +674,7 @@
   std::unique_ptr<DummyPageHolder> dummy_page_holder_;
   WeakPersistent<UserMediaProcessorUnderTest> user_media_processor_;
   Persistent<UserMediaClientUnderTest> user_media_client_impl_;
-  RequestState state_ = REQUEST_NOT_STARTED;
+  RequestState state_ = kRequestNotStarted;
 };
 
 TEST_F(UserMediaClientTest, GenerateMediaStream) {
@@ -818,7 +822,7 @@
   user_media_client_impl_->RequestUserMediaForTest();
   FailToStartMockedVideoSource();
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(REQUEST_FAILED, request_state());
+  EXPECT_EQ(kRequestFailed, request_state());
   EXPECT_EQ(
       blink::mojom::blink::MediaStreamRequestResult::TRACK_START_FAILURE_VIDEO,
       user_media_processor_->error_reason());
@@ -834,7 +838,7 @@
   user_media_client_impl_->RequestUserMediaForTest();
   StartMockedVideoSource();
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(REQUEST_FAILED, request_state());
+  EXPECT_EQ(kRequestFailed, request_state());
   EXPECT_EQ(
       blink::mojom::blink::MediaStreamRequestResult::TRACK_START_FAILURE_AUDIO,
       user_media_processor_->error_reason());
@@ -849,7 +853,7 @@
 TEST_F(UserMediaClientTest, MediaStreamImplShutDown) {
   user_media_client_impl_->RequestUserMediaForTest();
   EXPECT_EQ(1, mock_dispatcher_host_.request_stream_counter());
-  EXPECT_EQ(REQUEST_NOT_COMPLETE, request_state());
+  EXPECT_EQ(kRequestNotComplete, request_state());
   // TearDown() nulls out |user_media_client_impl_| and forces GC to garbage
   // collect it.
 }
@@ -864,7 +868,7 @@
   EXPECT_EQ(1, mock_dispatcher_host_.request_stream_counter());
   EXPECT_EQ(0, mock_dispatcher_host_.stop_audio_device_counter());
   EXPECT_EQ(0, mock_dispatcher_host_.stop_video_device_counter());
-  EXPECT_EQ(REQUEST_NOT_COMPLETE, request_state());
+  EXPECT_EQ(kRequestNotComplete, request_state());
 }
 
 // This test what happens if a newdocument is loaded in the frame while the
@@ -875,7 +879,7 @@
   LoadNewDocumentInFrame();
   EXPECT_EQ(1, mock_dispatcher_host_.stop_audio_device_counter());
   EXPECT_EQ(1, mock_dispatcher_host_.stop_video_device_counter());
-  EXPECT_EQ(REQUEST_NOT_COMPLETE, request_state());
+  EXPECT_EQ(kRequestNotComplete, request_state());
 }
 
 // This test what happens if stop is called on a track after the frame has
@@ -1116,7 +1120,7 @@
   UserMediaRequest* request =
       UserMediaRequest::CreateForTesting(audio_constraints, MediaConstraints());
   user_media_client_impl_->RequestUserMediaForTest(request);
-  EXPECT_EQ(REQUEST_FAILED, request_state());
+  EXPECT_EQ(kRequestFailed, request_state());
 }
 
 TEST_F(UserMediaClientTest, CreateWithMandatoryInvalidVideoDeviceId) {
@@ -1125,7 +1129,7 @@
   UserMediaRequest* request =
       UserMediaRequest::CreateForTesting(MediaConstraints(), video_constraints);
   user_media_client_impl_->RequestUserMediaForTest(request);
-  EXPECT_EQ(REQUEST_FAILED, request_state());
+  EXPECT_EQ(kRequestFailed, request_state());
 }
 
 TEST_F(UserMediaClientTest, CreateWithMandatoryValidDeviceIds) {
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
index 972364b..c807b277 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -319,9 +319,9 @@
                               MediaStreamRequestResult result,
                               const String& result_name)>;
   enum class State {
-    NOT_SENT_FOR_GENERATION,
-    SENT_FOR_GENERATION,
-    GENERATED,
+    kNotSentForGeneration,
+    kSentForGeneration,
+    kGenerated,
   };
 
   explicit RequestInfo(UserMediaRequest* request);
@@ -439,7 +439,7 @@
   void CheckAllTracksStarted();
 
   Member<UserMediaRequest> request_;
-  State state_ = State::NOT_SENT_FOR_GENERATION;
+  State state_ = State::kNotSentForGeneration;
   blink::AudioCaptureSettings audio_capture_settings_;
   bool is_audio_content_capture_ = false;
   blink::VideoCaptureSettings video_capture_settings_;
@@ -928,7 +928,7 @@
       current_request_info_->request_id(),
       current_request_info_->stream_controls()->audio.device_id.c_str(),
       current_request_info_->stream_controls()->video.device_id.c_str()));
-  current_request_info_->set_state(RequestInfo::State::SENT_FOR_GENERATION);
+  current_request_info_->set_state(RequestInfo::State::kSentForGeneration);
 
   // The browser replies to this request by invoking OnStreamGenerated().
   GetMediaStreamDispatcherHost()->GenerateStream(
@@ -985,7 +985,7 @@
     return;
   }
 
-  current_request_info_->set_state(RequestInfo::State::GENERATED);
+  current_request_info_->set_state(RequestInfo::State::kGenerated);
   current_request_info_->set_pan_tilt_zoom_allowed(pan_tilt_zoom_allowed);
 
   for (const auto* devices : {&audio_devices, &video_devices}) {
@@ -1837,19 +1837,19 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (current_request_info_) {
     switch (current_request_info_->state()) {
-      case RequestInfo::State::SENT_FOR_GENERATION:
+      case RequestInfo::State::kSentForGeneration:
         // Let the browser process know that the previously sent request must be
         // canceled.
         GetMediaStreamDispatcherHost()->CancelRequest(
             current_request_info_->request_id());
         FALLTHROUGH;
 
-      case RequestInfo::State::NOT_SENT_FOR_GENERATION:
+      case RequestInfo::State::kNotSentForGeneration:
         LogUserMediaRequestWithNoResult(
             blink::MEDIA_STREAM_REQUEST_NOT_GENERATED);
         break;
 
-      case RequestInfo::State::GENERATED:
+      case RequestInfo::State::kGenerated:
         LogUserMediaRequestWithNoResult(
             blink::MEDIA_STREAM_REQUEST_PENDING_MEDIA_TRACKS);
         break;
diff --git a/third_party/blink/renderer/modules/mediastream/video_renderer_algorithm_wrapper.cc b/third_party/blink/renderer/modules/mediastream/video_renderer_algorithm_wrapper.cc
index d51e4e8..102a420 100644
--- a/third_party/blink/renderer/modules/mediastream/video_renderer_algorithm_wrapper.cc
+++ b/third_party/blink/renderer/modules/mediastream/video_renderer_algorithm_wrapper.cc
@@ -10,7 +10,7 @@
     media::MediaLog* media_log)
     : wall_clock_time_cb_(wall_clock_time_cb),
       media_log_(media_log),
-      renderer_algorithm_(RendererAlgorithm::Default) {
+      renderer_algorithm_(RendererAlgorithm::kDefault) {
   default_rendering_frame_buffer_ =
       std::make_unique<media::VideoRendererAlgorithm>(wall_clock_time_cb_,
                                                       media_log_);
@@ -20,7 +20,7 @@
     base::TimeTicks deadline_min,
     base::TimeTicks deadline_max,
     size_t* frames_dropped) {
-  return renderer_algorithm_ == RendererAlgorithm::Default
+  return renderer_algorithm_ == RendererAlgorithm::kDefault
              ? default_rendering_frame_buffer_->Render(
                    deadline_min, deadline_max, frames_dropped)
              : low_latency_rendering_frame_buffer_->Render(
@@ -30,27 +30,27 @@
 void VideoRendererAlgorithmWrapper::EnqueueFrame(
     scoped_refptr<media::VideoFrame> frame) {
   DCHECK(frame);
-  if (renderer_algorithm_ == RendererAlgorithm::Default &&
+  if (renderer_algorithm_ == RendererAlgorithm::kDefault &&
       frame->metadata().maximum_composition_delay_in_frames) {
     default_rendering_frame_buffer_.release();
     low_latency_rendering_frame_buffer_ =
         std::make_unique<LowLatencyVideoRendererAlgorithm>(media_log_);
-    renderer_algorithm_ = RendererAlgorithm::LowLatency;
+    renderer_algorithm_ = RendererAlgorithm::kLowLatency;
   }
-  return renderer_algorithm_ == RendererAlgorithm::Default
+  return renderer_algorithm_ == RendererAlgorithm::kDefault
              ? default_rendering_frame_buffer_->EnqueueFrame(frame)
              : low_latency_rendering_frame_buffer_->EnqueueFrame(frame);
 }
 
 void VideoRendererAlgorithmWrapper::Reset(
     media::VideoRendererAlgorithm::ResetFlag reset_flag) {
-  return renderer_algorithm_ == RendererAlgorithm::Default
+  return renderer_algorithm_ == RendererAlgorithm::kDefault
              ? default_rendering_frame_buffer_->Reset(reset_flag)
              : low_latency_rendering_frame_buffer_->Reset();
 }
 
 bool VideoRendererAlgorithmWrapper::NeedsReferenceTime() const {
-  return renderer_algorithm_ == RendererAlgorithm::Default;
+  return renderer_algorithm_ == RendererAlgorithm::kDefault;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediastream/video_renderer_algorithm_wrapper.h b/third_party/blink/renderer/modules/mediastream/video_renderer_algorithm_wrapper.h
index ba3ef4d5..0eeccfa 100644
--- a/third_party/blink/renderer/modules/mediastream/video_renderer_algorithm_wrapper.h
+++ b/third_party/blink/renderer/modules/mediastream/video_renderer_algorithm_wrapper.h
@@ -32,13 +32,13 @@
                  media::VideoRendererAlgorithm::ResetFlag::kEverything);
 
   size_t frames_queued() const {
-    return renderer_algorithm_ == RendererAlgorithm::Default
+    return renderer_algorithm_ == RendererAlgorithm::kDefault
                ? default_rendering_frame_buffer_->frames_queued()
                : low_latency_rendering_frame_buffer_->frames_queued();
   }
 
   base::TimeDelta average_frame_duration() const {
-    return renderer_algorithm_ == RendererAlgorithm::Default
+    return renderer_algorithm_ == RendererAlgorithm::kDefault
                ? default_rendering_frame_buffer_->average_frame_duration()
                : low_latency_rendering_frame_buffer_->average_frame_duration();
   }
@@ -46,7 +46,7 @@
   bool NeedsReferenceTime() const;
 
  private:
-  enum RendererAlgorithm { Default, LowLatency };
+  enum RendererAlgorithm { kDefault, kLowLatency };
 
   const media::TimeSource::WallClockTimeCB wall_clock_time_cb_;
   media::MediaLog* media_log_;
diff --git a/third_party/blink/renderer/modules/nfc/ndef_message.h b/third_party/blink/renderer/modules/nfc/ndef_message.h
index 15bfdd8..cd573f1 100644
--- a/third_party/blink/renderer/modules/nfc/ndef_message.h
+++ b/third_party/blink/renderer/modules/nfc/ndef_message.h
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_typedefs.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/notifications/notification_manager.cc b/third_party/blink/renderer/modules/notifications/notification_manager.cc
index 52dd8d6..cc07a6e8 100644
--- a/third_party/blink/renderer/modules/notifications/notification_manager.cc
+++ b/third_party/blink/renderer/modules/notifications/notification_manager.cc
@@ -23,7 +23,7 @@
 #include "third_party/blink/renderer/modules/notifications/notification_metrics.h"
 #include "third_party/blink/renderer/modules/permissions/permission_utils.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
diff --git a/third_party/blink/renderer/modules/notifications/notification_resources_loader.h b/third_party/blink/renderer/modules/notifications/notification_resources_loader.h
index 8466dbcb..812ddec 100644
--- a/third_party/blink/renderer/modules/notifications/notification_resources_loader.h
+++ b/third_party/blink/renderer/modules/notifications/notification_resources_loader.h
@@ -8,9 +8,9 @@
 #include "third_party/blink/public/mojom/notifications/notification.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/loader/threaded_icon_loader.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/prefinalizer.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
diff --git a/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h b/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h
index e8d91941..250b6724 100644
--- a/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h
+++ b/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h
@@ -9,6 +9,7 @@
 #include "third_party/blink/public/mojom/notifications/notification.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
diff --git a/third_party/blink/renderer/modules/payments/payment_request_for_invalid_origin_or_ssl_test.cc b/third_party/blink/renderer/modules/payments/payment_request_for_invalid_origin_or_ssl_test.cc
index 3a519a1..f531ab6 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_for_invalid_origin_or_ssl_test.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request_for_invalid_origin_or_ssl_test.cc
@@ -10,7 +10,6 @@
 #include "third_party/blink/renderer/modules/payments/payment_test_helper.h"
 #include "third_party/blink/renderer/platform/bindings/exception_code.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
 
diff --git a/third_party/blink/renderer/modules/payments/payment_request_optional_total_test.cc b/third_party/blink/renderer/modules/payments/payment_request_optional_total_test.cc
index 3a083942..55fc27c7 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_optional_total_test.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request_optional_total_test.cc
@@ -11,7 +11,7 @@
 #include "third_party/blink/renderer/core/event_type_names.h"
 #include "third_party/blink/renderer/modules/payments/payment_test_helper.h"
 #include "third_party/blink/renderer/platform/bindings/exception_code.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
 
diff --git a/third_party/blink/renderer/modules/payments/payment_request_test.cc b/third_party/blink/renderer/modules/payments/payment_request_test.cc
index e3bd3db..0c69487 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_test.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request_test.cc
@@ -18,7 +18,7 @@
 #include "third_party/blink/renderer/core/testing/mock_function_scope.h"
 #include "third_party/blink/renderer/modules/payments/payment_test_helper.h"
 #include "third_party/blink/renderer/platform/bindings/exception_code.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/payments/payment_test_helper.h b/third_party/blink/renderer/modules/payments/payment_test_helper.h
index ad09593..64c3fbb1 100644
--- a/third_party/blink/renderer/modules/payments/payment_test_helper.h
+++ b/third_party/blink/renderer/modules/payments/payment_test_helper.h
@@ -14,7 +14,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_payment_details_update.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_payment_item.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_payment_shipping_option.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_error.cc b/third_party/blink/renderer/modules/peerconnection/rtc_error.cc
index 055f582..f25ba3dc 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_error.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_error.cc
@@ -6,6 +6,8 @@
 
 #include <utility>
 
+#include "base/notreached.h"
+
 namespace blink {
 
 namespace {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h
index c2e65e6..6e81ab9 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
 #include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_ice_transport_adapter.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
index b960a1d5..34e0ce4 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
@@ -49,7 +49,7 @@
 #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_session_description_enums.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/prefinalizer.h"
 #include "third_party/blink/renderer/platform/mediastream/media_constraints.h"
 #include "third_party/blink/renderer/platform/peerconnection/rtc_peer_connection_handler_client.h"
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
index ce8e09b..a018f1ac 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
@@ -216,6 +216,8 @@
   configuration->combined_audio_video_bwe = ConstraintToOptional(
       constraints,
       &MediaTrackConstraintSetPlatform::goog_combined_audio_video_bwe);
+  configuration->enable_dtls_srtp = ConstraintToOptional(
+      constraints, &MediaTrackConstraintSetPlatform::enable_dtls_srtp);
 }
 
 // Class mapping responses from calls to libjingle CreateOffer/Answer and
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
index 370b43b..77aa406 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
@@ -30,8 +30,8 @@
 #include "third_party/blink/renderer/modules/mediastream/media_stream.h"
 #include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
 #include "third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/peerconnection/rtc_rtp_receiver_platform.h"
 #include "third_party/blink/renderer/platform/peerconnection/rtc_rtp_sender_platform.h"
 #include "third_party/blink/renderer/platform/peerconnection/rtc_session_description_platform.h"
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
index 1ce08c4b..bf840a7 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/frame/picture_in_picture_controller.h"
 #include "third_party/blink/renderer/core/page/page_visibility_observer.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 
diff --git a/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config_impl.cc b/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config_impl.cc
index e7f568b..21f5df3 100644
--- a/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config_impl.cc
+++ b/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config_impl.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/sanitizer_api/sanitizer_config_impl.h"
 
 #include "third_party/blink/renderer/bindings/modules/v8/v8_sanitizer_config.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
 
diff --git a/third_party/blink/renderer/modules/screen_enumeration/screen_details.cc b/third_party/blink/renderer/modules/screen_enumeration/screen_details.cc
index a50bb1a..e98a523 100644
--- a/third_party/blink/renderer/modules/screen_enumeration/screen_details.cc
+++ b/third_party/blink/renderer/modules/screen_enumeration/screen_details.cc
@@ -94,6 +94,13 @@
     }
   }
 
+  // screens is sorted by dimensions, x first and then y.
+  base::ranges::stable_sort(screens_, [](ScreenDetailed* a, ScreenDetailed* b) {
+    if (a->left() != b->left())
+      return a->left() < b->left();
+    return a->top() < b->top();
+  });
+
   // Update current_display_id_ so that currentScreen() is up to date
   // before we send out any events.
   current_display_id_ = new_infos.current_display_id;
diff --git a/third_party/blink/renderer/modules/sensor/sensor_proxy.h b/third_party/blink/renderer/modules/sensor/sensor_proxy.h
index 2bfa8a0..debee5b 100644
--- a/third_party/blink/renderer/modules/sensor/sensor_proxy.h
+++ b/third_party/blink/renderer/modules/sensor/sensor_proxy.h
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/page/page_visibility_observer.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/exception_code.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/serial/serial_port.h b/third_party/blink/renderer/modules/serial/serial_port.h
index 22ea6177..ae87086 100644
--- a/third_party/blink/renderer/modules/serial/serial_port.h
+++ b/third_party/blink/renderer/modules/serial/serial_port.h
@@ -13,8 +13,8 @@
 #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/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
index 00fca0b..67f3ed0a 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -50,7 +50,6 @@
 #include "third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.h"
 #include "third_party/blink/renderer/platform/heap/disallow_new_wrapper.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set.h"
diff --git a/third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.h b/third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.h
index c15462d..8cb68f8 100644
--- a/third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.h
+++ b/third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.h
@@ -7,8 +7,8 @@
 
 #include "services/shape_detection/public/mojom/barcodedetection_provider.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis.h b/third_party/blink/renderer/modules/speech/speech_synthesis.h
index eac7f3c..18684d58 100644
--- a/third_party/blink/renderer/modules/speech/speech_synthesis.h
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis.h
@@ -31,6 +31,8 @@
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/modules/speech/speech_synthesis_utterance.h"
 #include "third_party/blink/renderer/modules/speech/speech_synthesis_voice.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
diff --git a/third_party/blink/renderer/modules/storage/cached_storage_area.h b/third_party/blink/renderer/modules/storage/cached_storage_area.h
index 0ae86e42..f589a4d 100644
--- a/third_party/blink/renderer/modules/storage/cached_storage_area.h
+++ b/third_party/blink/renderer/modules/storage/cached_storage_area.h
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/modules/storage/storage_area_map.h"
 #include "third_party/blink/renderer/modules/storage/storage_namespace.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/storage/blink_storage_key.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
diff --git a/third_party/blink/renderer/modules/storage/storage_controller.h b/third_party/blink/renderer/modules/storage/storage_controller.h
index 7614209..b761cfa 100644
--- a/third_party/blink/renderer/modules/storage/storage_controller.h
+++ b/third_party/blink/renderer/modules/storage/storage_controller.h
@@ -14,7 +14,6 @@
 #include "third_party/blink/public/mojom/dom_storage/dom_storage.mojom-blink.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/modules/storage/storage_area.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
diff --git a/third_party/blink/renderer/modules/storage/storage_namespace.h b/third_party/blink/renderer/modules/storage/storage_namespace.h
index 9d33cc27..32af59c24 100644
--- a/third_party/blink/renderer/modules/storage/storage_namespace.h
+++ b/third_party/blink/renderer/modules/storage/storage_namespace.h
@@ -34,7 +34,6 @@
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 #include "third_party/blink/renderer/platform/storage/blink_storage_key.h"
diff --git a/third_party/blink/renderer/modules/webaudio/audio_node.h b/third_party/blink/renderer/modules/webaudio/audio_node.h
index 45d5f02..07ed699 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_node.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_node.h
@@ -33,6 +33,8 @@
 #include "third_party/blink/renderer/modules/webaudio/inspector_helper_mixin.h"
 #include "third_party/blink/renderer/platform/audio/audio_bus.h"
 #include "third_party/blink/renderer/platform/audio/audio_utilities.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/heap/prefinalizer.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder.h b/third_party/blink/renderer/modules/webcodecs/audio_decoder.h
index 0fab19e..c31c078d 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_decoder.h
+++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder.h
@@ -19,7 +19,6 @@
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 
 namespace media {
diff --git a/third_party/blink/renderer/modules/webcodecs/decoder_template.h b/third_party/blink/renderer/modules/webcodecs/decoder_template.h
index c16dbee..6398421 100644
--- a/third_party/blink/renderer/modules/webcodecs/decoder_template.h
+++ b/third_party/blink/renderer/modules/webcodecs/decoder_template.h
@@ -24,9 +24,9 @@
 #include "third_party/blink/renderer/modules/webcodecs/hardware_preference.h"
 #include "third_party/blink/renderer/modules/webcodecs/reclaimable_codec.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 
 namespace base {
diff --git a/third_party/blink/renderer/modules/webcodecs/encoder_base.h b/third_party/blink/renderer/modules/webcodecs/encoder_base.h
index f01b3f3..6744328c 100644
--- a/third_party/blink/renderer/modules/webcodecs/encoder_base.h
+++ b/third_party/blink/renderer/modules/webcodecs/encoder_base.h
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/modules/webcodecs/reclaimable_codec.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 
 namespace base {
diff --git a/third_party/blink/renderer/modules/webcodecs/video_decoder.h b/third_party/blink/renderer/modules/webcodecs/video_decoder.h
index 2a78268..45c0853 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_decoder.h
+++ b/third_party/blink/renderer/modules/webcodecs/video_decoder.h
@@ -22,7 +22,6 @@
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 
 namespace media {
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
index 9048b0b..05f619b7 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -879,8 +879,12 @@
     first_output_after_configure_ = false;
 
     if (output_color_space != last_output_color_space_) {
+// TODO(crbug.com/1241448): Make Android obey the contract below. For now
+// Android VEA only _eventually_ gives a key frame when color space changes.
+#if !defined(OS_ANDROID)
       DCHECK(output.key_frame) << "Encoders should generate a keyframe when "
                                << "changing color space";
+#endif
       last_output_color_space_ = output_color_space;
     }
 
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
index 5f64024..8b204f7c 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -1068,7 +1068,7 @@
 }
 
 ScriptPromise VideoFrame::CreateImageBitmap(ScriptState* script_state,
-                                            absl::optional<IntRect> crop_rect,
+                                            absl::optional<gfx::Rect> crop_rect,
                                             const ImageBitmapOptions* options,
                                             ExceptionState& exception_state) {
   const auto local_handle = handle_->CloneForInternalUse();
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.h b/third_party/blink/renderer/modules/webcodecs/video_frame.h
index 67ec46b..c8cec399c 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_frame.h
+++ b/third_party/blink/renderer/modules/webcodecs/video_frame.h
@@ -18,7 +18,6 @@
 #include "third_party/blink/renderer/modules/webcodecs/allow_shared_buffer_source_util.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame_handle.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
@@ -107,6 +106,8 @@
   scoped_refptr<VideoFrameHandle> handle() const { return handle_; }
   scoped_refptr<media::VideoFrame> frame() const { return handle_->frame(); }
 
+  bool WouldTaintOrigin() const override;
+
   // GarbageCollected override
   void Trace(Visitor*) const override;
 
@@ -116,7 +117,7 @@
       SourceImageStatus*,
       const FloatSize&,
       const AlphaDisposition alpha_disposition = kPremultiplyAlpha) override;
-  bool WouldTaintOrigin() const override;
+
   FloatSize ElementSize(const FloatSize&,
                         const RespectImageOrientationEnum) const override;
   bool IsVideoFrame() const override;
@@ -127,7 +128,7 @@
   static constexpr uint64_t kCpuEfficientFrameSize = 320u * 240u;
   IntSize BitmapSourceSize() const override;
   ScriptPromise CreateImageBitmap(ScriptState*,
-                                  absl::optional<IntRect> crop_rect,
+                                  absl::optional<gfx::Rect> crop_rect,
                                   const ImageBitmapOptions*,
                                   ExceptionState&) override;
 
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame_transfer_list.h b/third_party/blink/renderer/modules/webcodecs/video_frame_transfer_list.h
index 8f44138e..c49f32b 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_frame_transfer_list.h
+++ b/third_party/blink/renderer/modules/webcodecs/video_frame_transfer_list.h
@@ -7,8 +7,8 @@
 
 #include "third_party/blink/renderer/bindings/core/v8/serialization/transferables.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/webdatabase/database_manager.h b/third_party/blink/renderer/modules/webdatabase/database_manager.h
index 2199033..22431e5 100644
--- a/third_party/blink/renderer/modules/webdatabase/database_manager.h
+++ b/third_party/blink/renderer/modules/webdatabase/database_manager.h
@@ -29,6 +29,7 @@
 #include "base/dcheck_is_on.h"
 #include "third_party/blink/renderer/modules/webdatabase/database_context.h"
 #include "third_party/blink/renderer/modules/webdatabase/database_error.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
diff --git a/third_party/blink/renderer/modules/webdatabase/inspector_database_agent.h b/third_party/blink/renderer/modules/webdatabase/inspector_database_agent.h
index e5137596..4bbdcbd2 100644
--- a/third_party/blink/renderer/modules/webdatabase/inspector_database_agent.h
+++ b/third_party/blink/renderer/modules/webdatabase/inspector_database_agent.h
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/core/inspector/inspector_base_agent.h"
 #include "third_party/blink/renderer/core/inspector/protocol/database.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.h b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.h
index 444bd02..ab3b8b5 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.h
@@ -29,6 +29,7 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_context_object.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_shared_object.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 
 namespace gpu {
 namespace gles2 {
diff --git a/third_party/blink/renderer/modules/webgpu/BUILD.gn b/third_party/blink/renderer/modules/webgpu/BUILD.gn
index dd904a9..5bc070f 100644
--- a/third_party/blink/renderer/modules/webgpu/BUILD.gn
+++ b/third_party/blink/renderer/modules/webgpu/BUILD.gn
@@ -87,6 +87,7 @@
   deps = [
     "//gpu/command_buffer/client:webgpu_interface",
     "//services/metrics/public/cpp:ukm_builders",
+    "//third_party/blink/renderer/modules/webcodecs:webcodecs",
     "//third_party/dawn/src/dawn:dawn_headers",
   ]
 }
diff --git a/third_party/blink/renderer/modules/webgpu/DEPS b/third_party/blink/renderer/modules/webgpu/DEPS
index 55b27bec..ded05aa6 100644
--- a/third_party/blink/renderer/modules/webgpu/DEPS
+++ b/third_party/blink/renderer/modules/webgpu/DEPS
@@ -10,5 +10,6 @@
     "+gpu/command_buffer/client/shared_image_interface.h",
     "+gpu/command_buffer/client/webgpu_interface.h",
     "+media/base/video_frame.h",
+    "+media/renderers/paint_canvas_video_renderer.h",
     "+services/metrics/public/cpp/ukm_builders.h",
 ]
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_conversions.h b/third_party/blink/renderer/modules/webgpu/dawn_conversions.h
index b27c3bd..d18c1ee 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_conversions.h
+++ b/third_party/blink/renderer/modules/webgpu/dawn_conversions.h
@@ -13,7 +13,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_typedefs.h"
 #include "third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.h"
 #include "third_party/blink/renderer/modules/webgpu/dawn_object.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 
 // This file provides helpers for converting WebGPU objects, descriptors,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_compilation_message.cc b/third_party/blink/renderer/modules/webgpu/gpu_compilation_message.cc
index fb1fec2..ccff69f 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_compilation_message.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_compilation_message.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/modules/webgpu/gpu_compilation_message.h"
 
+#include "base/notreached.h"
+
 namespace blink {
 
 GPUCompilationMessage::GPUCompilationMessage(String message,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.cc b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
index ff6ab16..b59b176 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -297,7 +297,7 @@
     const GPUExternalTextureDescriptor* descriptor,
     ExceptionState& exception_state) {
   GPUExternalTexture* externalTexture =
-      GPUExternalTexture::FromVideo(this, descriptor, exception_state);
+      GPUExternalTexture::Create(this, descriptor, exception_state);
   if (externalTexture)
     EnsureExternalTextureDestroyed(externalTexture);
   return externalTexture;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
index 92890f6..9a6c1cd 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
@@ -7,7 +7,9 @@
 #include "media/base/video_frame.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_external_texture_descriptor.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_view_descriptor.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_union_htmlvideoelement_videoframe.h"
 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
+#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
 #include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_texture.h"
@@ -19,32 +21,58 @@
 namespace blink {
 
 // static
-GPUExternalTexture* GPUExternalTexture::FromVideo(
+GPUExternalTexture* GPUExternalTexture::Create(
     GPUDevice* device,
     const GPUExternalTextureDescriptor* webgpu_desc,
     ExceptionState& exception_state) {
-  HTMLVideoElement* video = webgpu_desc->source();
-
-  if (!video || !video->videoWidth() || !video->videoHeight()) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
-                                      "Missing video source");
-    return nullptr;
-  }
-
-  if (video->WouldTaintOrigin()) {
-    exception_state.ThrowSecurityError(
-        "Video element is tainted by cross-origin data and may not be loaded.");
-    return nullptr;
-  }
-
-  media::PaintCanvasVideoRenderer* video_renderer = nullptr;
   scoped_refptr<media::VideoFrame> media_video_frame;
-  if (auto* wmp = video->GetWebMediaPlayer()) {
-    media_video_frame = wmp->GetCurrentFrame();
-    video_renderer = wmp->GetPaintCanvasVideoRenderer();
+  media::PaintCanvasVideoRenderer* video_renderer = nullptr;
+  switch (webgpu_desc->source()->GetContentType()) {
+    case V8UnionHTMLVideoElementOrVideoFrame::ContentType::kHTMLVideoElement: {
+      HTMLVideoElement* video = webgpu_desc->source()->GetAsHTMLVideoElement();
+
+      if (!video || !video->videoWidth() || !video->videoHeight()) {
+        exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+                                          "Missing video source");
+        return nullptr;
+      }
+
+      if (video->WouldTaintOrigin()) {
+        exception_state.ThrowSecurityError(
+            "Video element is tainted by cross-origin data and may not be "
+            "loaded.");
+        return nullptr;
+      }
+
+      if (auto* wmp = video->GetWebMediaPlayer()) {
+        media_video_frame = wmp->GetCurrentFrame();
+        video_renderer = wmp->GetPaintCanvasVideoRenderer();
+      }
+      break;
+    }
+
+    case V8UnionHTMLVideoElementOrVideoFrame::ContentType::kVideoFrame: {
+      VideoFrame* frame = webgpu_desc->source()->GetAsVideoFrame();
+
+      if (!frame || !frame->codedWidth() || !frame->codedHeight()) {
+        exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+                                          "Missing video source");
+        return nullptr;
+      }
+
+      if (frame->WouldTaintOrigin()) {
+        exception_state.ThrowSecurityError(
+            "VideoFrame is tainted by cross-origin data and may not be "
+            "loaded.");
+        return nullptr;
+      }
+
+      media_video_frame = frame->frame();
+      break;
+    }
   }
 
-  if (!media_video_frame || !video_renderer) {
+  if (!media_video_frame) {
     exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
                                       "Failed to import texture from video");
     if (!media_video_frame) {
@@ -87,6 +115,10 @@
   // TODO(crbug.com/1174809): This isn't efficient for VideoFrames which are
   // already available as a shared image. A WebGPUMailboxTexture should be
   // created directly from the VideoFrame instead.
+  // TODO(crbug.com/1174809): VideoFrame cannot extract video_renderer.
+  // DrawVideoFrameIntoResourceProvider() creates local_video_renderer always.
+  // This might affect performance, maybe a cache local_video_renderer could
+  // help.
   const auto dest_rect = gfx::Rect(media_video_frame->natural_size());
   if (!DrawVideoFrameIntoResourceProvider(
           std::move(media_video_frame), resource_provider,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.h b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.h
index af59477..aecde69 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.h
@@ -18,7 +18,7 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static GPUExternalTexture* FromVideo(
+  static GPUExternalTexture* Create(
       GPUDevice* device,
       const GPUExternalTextureDescriptor* webgpu_desc,
       ExceptionState& exception_state);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_external_texture_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_external_texture_descriptor.idl
index f50b768..a54804c 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_external_texture_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_external_texture_descriptor.idl
@@ -5,6 +5,6 @@
 // https://gpuweb.github.io/gpuweb/
 
 dictionary GPUExternalTextureDescriptor : GPUObjectDescriptorBase {
-    required HTMLVideoElement source;
+    required (HTMLVideoElement or VideoFrame) source;
     GPUPredefinedColorSpace colorSpace = "srgb";
-};
\ No newline at end of file
+};
diff --git a/third_party/blink/renderer/modules/webid/web_id.h b/third_party/blink/renderer/modules/webid/web_id.h
index e574f5f..4fd241b 100644
--- a/third_party/blink/renderer/modules/webid/web_id.h
+++ b/third_party/blink/renderer/modules/webid/web_id.h
@@ -9,7 +9,7 @@
 #include "third_party/blink/public/mojom/webid/federated_auth_response.mojom-blink.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/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/webmidi/midi_output.h b/third_party/blink/renderer/modules/webmidi/midi_output.h
index 72872b7..43501dd 100644
--- a/third_party/blink/renderer/modules/webmidi/midi_output.h
+++ b/third_party/blink/renderer/modules/webmidi/midi_output.h
@@ -36,7 +36,7 @@
 #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
 #include "third_party/blink/renderer/modules/webmidi/midi_port.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/webtransport/web_transport.h b/third_party/blink/renderer/modules/webtransport/web_transport.h
index 48ce945..3dca3cf 100644
--- a/third_party/blink/renderer/modules/webtransport/web_transport.h
+++ b/third_party/blink/renderer/modules/webtransport/web_transport.h
@@ -20,7 +20,6 @@
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/prefinalizer.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_provider.h b/third_party/blink/renderer/modules/xr/xr_frame_provider.h
index afdff5d0..428239af 100644
--- a/third_party/blink/renderer/modules/xr/xr_frame_provider.h
+++ b/third_party/blink/renderer/modules/xr/xr_frame_provider.h
@@ -11,7 +11,6 @@
 #include "third_party/blink/renderer/platform/geometry/int_size.h"
 #include "third_party/blink/renderer/platform/heap/disallow_new_wrapper.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h b/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h
index a0c0fe2..aaaf78d 100644
--- a/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h
+++ b/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_FRAME_REQUEST_CALLBACK_COLLECTION_H_
 
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source_array.cc b/third_party/blink/renderer/modules/xr/xr_input_source_array.cc
index a9d3b1a..0311a702 100644
--- a/third_party/blink/renderer/modules/xr/xr_input_source_array.cc
+++ b/third_party/blink/renderer/modules/xr/xr_input_source_array.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "third_party/blink/renderer/modules/xr/xr_input_source_array.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source_array.h b/third_party/blink/renderer/modules/xr/xr_input_source_array.h
index 60dbe3e..1f7503a 100644
--- a/third_party/blink/renderer/modules/xr/xr_input_source_array.h
+++ b/third_party/blink/renderer/modules/xr/xr_input_source_array.h
@@ -7,6 +7,7 @@
 
 #include "third_party/blink/renderer/modules/xr/xr_input_source.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h b/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h
index bfbbe90..6a797e30 100644
--- a/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h
+++ b/third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h
@@ -5,9 +5,9 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_TRANSIENT_INPUT_HIT_TEST_SOURCE_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_TRANSIENT_INPUT_HIT_TEST_SOURCE_H_
 
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-
 #include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/bindings/active_script_wrappable_manager.h b/third_party/blink/renderer/platform/bindings/active_script_wrappable_manager.h
index 375d48b..efedaa0c 100644
--- a/third_party/blink/renderer/platform/bindings/active_script_wrappable_manager.h
+++ b/third_party/blink/renderer/platform/bindings/active_script_wrappable_manager.h
@@ -7,6 +7,7 @@
 
 #include "third_party/blink/renderer/platform/bindings/active_script_wrappable_base.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 
diff --git a/third_party/blink/renderer/platform/bindings/dom_data_store.h b/third_party/blink/renderer/platform/bindings/dom_data_store.h
index bffa2b0..cd6a950 100644
--- a/third_party/blink/renderer/platform/bindings/dom_data_store.h
+++ b/third_party/blink/renderer/platform/bindings/dom_data_store.h
@@ -35,6 +35,7 @@
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
 #include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/stack_util.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
diff --git a/third_party/blink/renderer/platform/bindings/multi_worlds_v8_reference.h b/third_party/blink/renderer/platform/bindings/multi_worlds_v8_reference.h
index 1fb0611..7d794b3 100644
--- a/third_party/blink/renderer/platform/bindings/multi_worlds_v8_reference.h
+++ b/third_party/blink/renderer/platform/bindings/multi_worlds_v8_reference.h
@@ -7,6 +7,7 @@
 
 #include "base/notreached.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/bindings/v8_per_context_data.h b/third_party/blink/renderer/platform/bindings/v8_per_context_data.h
index 6b52b1b8..5a455b8 100644
--- a/third_party/blink/renderer/platform/bindings/v8_per_context_data.h
+++ b/third_party/blink/renderer/platform/bindings/v8_per_context_data.h
@@ -37,6 +37,7 @@
 #include "gin/public/gin_embedders.h"
 #include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
diff --git a/third_party/blink/renderer/platform/bindings/v8_private_property.h b/third_party/blink/renderer/platform/bindings/v8_private_property.h
index ced2875..6e2d8ee 100644
--- a/third_party/blink/renderer/platform/bindings/v8_private_property.h
+++ b/third_party/blink/renderer/platform/bindings/v8_private_property.h
@@ -94,7 +94,6 @@
    public:
     SymbolKey() = default;
 
-   private:
     SymbolKey(const SymbolKey&) = delete;
     SymbolKey& operator=(const SymbolKey&) = delete;
   };
diff --git a/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc b/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc
index ae61e2d1..27c938f 100644
--- a/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc
+++ b/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc
@@ -8,6 +8,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/timer/elapsed_timer.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/font_unique_name_lookup/icu_fold_case_util.h"
 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
 #include "third_party/blink/public/platform/platform.h"
@@ -94,6 +95,20 @@
   }
 }
 
+void FontUniqueNameLookupAndroid::Init() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!base::FeatureList::IsEnabled(features::kPrefetchAndroidFonts))
+    return;
+
+  EnsureServiceConnected();
+  if (android_font_lookup_service_) {
+    // WTF::Unretained is safe here because |this| owns
+    // |android_font_lookup_service_|.
+    android_font_lookup_service_->FetchAllFontFiles(WTF::Bind(
+        &FontUniqueNameLookupAndroid::FontsPrefetched, WTF::Unretained(this)));
+  }
+}
+
 void FontUniqueNameLookupAndroid::EnsureServiceConnected() {
   if (firmware_font_lookup_service_ &&
       (!RuntimeEnabledFeatures::AndroidDownloadableFontsMatchingEnabled() ||
@@ -147,6 +162,7 @@
 sk_sp<SkTypeface>
 FontUniqueNameLookupAndroid::MatchUniqueNameFromDownloadableFonts(
     const String& font_unique_name) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!android_font_lookup_service_.is_bound()) {
     LOG(ERROR) << "Service not connected.";
     return nullptr;
@@ -170,8 +186,11 @@
 
   base::ElapsedTimer elapsed_timer;
 
-  if (!android_font_lookup_service_->MatchLocalFontByUniqueName(
-          case_folded_unique_font_name, &font_file)) {
+  auto it = prefetched_font_map_.find(case_folded_unique_font_name);
+  if (it != prefetched_font_map_.end()) {
+    font_file = it->value.Duplicate();
+  } else if (!android_font_lookup_service_->MatchLocalFontByUniqueName(
+                 case_folded_unique_font_name, &font_file)) {
     LOG(ERROR)
         << "Mojo method returned false for case-folded unique font name: "
         << case_folded_unique_font_name;
@@ -205,4 +224,10 @@
   return return_typeface;
 }
 
+void FontUniqueNameLookupAndroid::FontsPrefetched(
+    HashMap<String, base::File> font_files) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  prefetched_font_map_ = std::move(font_files);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h b/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h
index fbc5d72..c4dc522d 100644
--- a/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h
+++ b/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_ANDROID_FONT_UNIQUE_NAME_LOOKUP_ANDROID_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_ANDROID_FONT_UNIQUE_NAME_LOOKUP_ANDROID_H_
 
+#include "base/sequence_checker.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h"
 #include "third_party/blink/public/mojom/android_font_lookup/android_font_lookup.mojom-blink.h"
@@ -35,6 +36,8 @@
 
   sk_sp<SkTypeface> MatchUniqueName(const String& font_unique_name) override;
 
+  void Init() override;
+
  private:
   void EnsureServiceConnected();
 
@@ -48,12 +51,17 @@
   sk_sp<SkTypeface> MatchUniqueNameFromDownloadableFonts(
       const String& font_unique_name);
 
+  void FontsPrefetched(HashMap<String, base::File> font_files);
+
   mojo::Remote<mojom::blink::FontUniqueNameLookup>
       firmware_font_lookup_service_;
   mojo::Remote<mojom::blink::AndroidFontLookup> android_font_lookup_service_;
   WTF::Deque<NotifyFontUniqueNameLookupReady> pending_callbacks_;
   absl::optional<bool> sync_available_;
   absl::optional<Vector<String>> queryable_fonts_;
+  HashMap<String, base::File> prefetched_font_map_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/font_cache.h b/third_party/blink/renderer/platform/fonts/font_cache.h
index 4d39e43..c19534b 100644
--- a/third_party/blink/renderer/platform/fonts/font_cache.h
+++ b/third_party/blink/renderer/platform/fonts/font_cache.h
@@ -47,7 +47,7 @@
 #include "third_party/blink/renderer/platform/fonts/font_fallback_priority.h"
 #include "third_party/blink/renderer/platform/fonts/font_platform_data.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_cache.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
diff --git a/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h b/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h
index 91a5c83..8b265ad 100644
--- a/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h
+++ b/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h
@@ -55,6 +55,11 @@
     NOTREACHED();
   }
 
+  // Performs any global initialization needed for this renderer. This is called
+  // early in renderer startup, as opposed to PrepareFontUniqueNameLookup()
+  // which is called when sync lookup is first needed.
+  virtual void Init() {}
+
  protected:
   FontUniqueNameLookup();
 
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
index 13ba3aa..df3fe3f 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -498,13 +498,7 @@
     timer.emplace();
   }
 
-  if (!clear_frame_ || !resource_host_ || !resource_host_->IsPrinting()) {
-    ResourceProvider()->FlushCanvas();
-    last_recording_ = nullptr;
-    clear_frame_ = false;
-  } else {
-    last_recording_ = ResourceProvider()->FlushCanvasAndPreserveRecording();
-  }
+  last_recording_ = ResourceProvider()->FlushCanvasAndMaybePreserveRecording();
 
   last_record_tainted_by_write_pixels_ = false;
 
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
index 0de6234..3b3a882 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
@@ -159,10 +159,6 @@
     return last_record_tainted_by_write_pixels_ ? nullptr : last_recording_;
   }
 
-  // This is called when the Canvas element has cleared the frame, so the 2D
-  // bridge knows that there's no previous content on the resource.
-  void ClearFrame() { clear_frame_ = true; }
-
   bool HasRateLimiterForTesting();
 
  private:
@@ -190,7 +186,6 @@
   bool hibernation_scheduled_ = false;
   bool dont_use_idle_scheduling_for_testing_ = false;
   bool context_lost_ = false;
-  bool clear_frame_ = true;
 
   // WritePixels content is not saved in recording. If a call was made to
   // WritePixels, the recording is now missing that information.
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_host.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_host.cc
index fc56ede..ad9d54f 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_host.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_host.cc
@@ -20,6 +20,7 @@
   resource_provider_ = std::move(new_resource_provider);
   UpdateMemoryUsage();
   if (resource_provider_) {
+    resource_provider_->SetCanvasResourceHost(this);
     resource_provider_->Canvas()->restoreToCount(1);
     InitializeForRecording(resource_provider_->Canvas());
     // Using unretained here since CanvasResourceHost owns |resource_provider_|
@@ -28,6 +29,7 @@
         &CanvasResourceHost::InitializeForRecording, base::Unretained(this)));
   }
   if (old_resource_provider) {
+    old_resource_provider->SetCanvasResourceHost(nullptr);
     old_resource_provider->SetRestoreClipStackCallback(
         CanvasResourceProvider::RestoreMatrixClipStackCb());
   }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index 8fa9898..507d7b9 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -81,6 +81,9 @@
 
 }  // namespace
 
+size_t CanvasResourceProvider::max_pinned_image_bytes_ =
+    kDefaultMaxPinnedImageBytes;
+
 class CanvasResourceProvider::CanvasImageProvider : public cc::ImageProvider {
  public:
   CanvasImageProvider(cc::ImageDecodeCache* cache_n32,
@@ -1351,8 +1354,8 @@
 }
 
 sk_sp<cc::PaintRecord>
-CanvasResourceProvider::FlushCanvasAndPreserveRecording() {
-  return FlushCanvasInternal(true);
+CanvasResourceProvider::FlushCanvasAndMaybePreserveRecording() {
+  return FlushCanvasInternal(IsPrinting() && clear_frame_);
 }
 
 IntSize CanvasResourceProvider::Size() const {
@@ -1375,6 +1378,7 @@
     bool preserve_recording) {
   if (!HasRecordedDrawOps())
     return nullptr;
+  clear_frame_ = false;
   sk_sp<cc::PaintRecord> last_recording = recorder_->finishRecordingAsPicture();
   RasterRecord(last_recording, preserve_recording);
   total_pinned_image_bytes_ = 0;
@@ -1476,6 +1480,7 @@
     Canvas()->clear(SK_ColorTRANSPARENT);
 
   FlushCanvas();
+  ClearFrame();
 }
 
 uint32_t CanvasResourceProvider::ContentUniqueID() const {
@@ -1582,7 +1587,7 @@
   // Note that this function only gets called when canvas needs a full repaint,
   // so always update the |mode_| to discard the old copy of canvas content.
   mode_ = SkSurface::kDiscard_ContentChangeMode;
-
+  ClearFrame();
   if (!HasRecordedDrawOps())
     return;
   recorder_->finishRecordingAsPicture();
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
index 52314ad..dc23c2d 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
@@ -9,6 +9,7 @@
 #include "cc/raster/playback_image_provider.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_resource.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_resource_host.h"
 #include "third_party/blink/renderer/platform/graphics/image_orientation.h"
 #include "third_party/blink/renderer/platform/graphics/memory_managed_paint_recorder.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_recorder.h"
@@ -91,7 +92,7 @@
   // of canvas contents to be interleaved with other compositing and UI work.
   static constexpr size_t kMaxRecordedOpBytes = 4 * 1024 * 1024;
   // The same value as is used in content::WebGraphicsConext3DProviderImpl.
-  static constexpr uint64_t kMaxPinnedImageBytes = 64 * 1024 * 1024;
+  static constexpr uint64_t kDefaultMaxPinnedImageBytes = 64 * 1024 * 1024;
 
   using RestoreMatrixClipStackCb =
       base::RepeatingCallback<void(cc::PaintCanvas*)>;
@@ -151,6 +152,17 @@
   virtual scoped_refptr<StaticBitmapImage> Snapshot(
       const ImageOrientation& = ImageOrientationEnum::kDefault) = 0;
 
+  void SetCanvasResourceHost(CanvasResourceHost* resource_host) {
+    resource_host_ = resource_host;
+  }
+
+  static void SetMaxPinnedImageBytesForTesting(size_t value) {
+    max_pinned_image_bytes_ = value;
+  }
+  static void ResetMaxPinnedImageBytesForTesting() {
+    max_pinned_image_bytes_ = kDefaultMaxPinnedImageBytes;
+  }
+
   // WebGraphicsContext3DProvider::DestructionObserver implementation.
   void OnContextDestroyed() override;
 
@@ -159,7 +171,7 @@
   // FlushCanvas and do not preserve recordings.
   void FlushCanvas();
   // FlushCanvas and preserve recordings.
-  sk_sp<cc::PaintRecord> FlushCanvasAndPreserveRecording();
+  sk_sp<cc::PaintRecord> FlushCanvasAndMaybePreserveRecording();
   const SkImageInfo& GetSkImageInfo() const { return info_; }
   SkSurfaceProps GetSkSurfaceProps() const;
   gfx::ColorSpace GetColorSpace() const;
@@ -264,6 +276,10 @@
 
   void DidPinImage(size_t bytes) override;
 
+  bool IsPrinting() { return resource_host_ && resource_host_->IsPrinting(); }
+
+  void ClearFrame() { clear_frame_ = true; }
+
  protected:
   class CanvasImageProvider;
 
@@ -377,12 +393,21 @@
 
   RestoreMatrixClipStackCb restore_clip_stack_callback_;
 
+  CanvasResourceHost* resource_host_;
+
+  bool clear_frame_ = true;
+  static size_t max_pinned_image_bytes_;
+
   base::WeakPtrFactory<CanvasResourceProvider> weak_ptr_factory_{this};
 };
 
 ALWAYS_INLINE void CanvasResourceProvider::FlushIfRecordingLimitExceeded() {
+  // When printing we avoid flushing if it is still possible to print in
+  // vector mode.
+  if (IsPrinting() && clear_frame_)
+    return;
   if (recorder_ && ((recorder_->BytesUsed() > kMaxRecordedOpBytes) ||
-                    total_pinned_image_bytes_ > kMaxPinnedImageBytes)) {
+                    total_pinned_image_bytes_ > max_pinned_image_bytes_)) {
     FlushCanvas();
   }
 }
diff --git a/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc b/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc
index d0b2e90..a7c78a6 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc
@@ -9,6 +9,7 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/renderer/platform/graphics/paint/display_item.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_chunk.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/testing/fake_display_item_client.h"
 #include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h"
 
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
index 97b5112..d675928 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
@@ -20,6 +20,7 @@
 #include "third_party/blink/renderer/platform/graphics/paint/paint_chunk.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_chunk_subset.h"
 #include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/testing/fake_display_item_client.h"
 #include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
diff --git a/third_party/blink/renderer/platform/graphics/compositing/pending_layer.h b/third_party/blink/renderer/platform/graphics/compositing/pending_layer.h
index a11bae3e..4628261 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/pending_layer.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/pending_layer.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/platform/graphics/paint/paint_chunk_subset.h"
 #include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/vector2d_f.h"
 
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
index de55f97..23545cc 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
@@ -142,7 +142,7 @@
 bool DarkModeFilter::ShouldApplyToColor(SkColor color, ElementRole role) {
   switch (role) {
     case ElementRole::kSVG:
-    case ElementRole::kText:
+    case ElementRole::kForeground:
     case ElementRole::kListSymbol:
       DCHECK(immutable_.foreground_classifier);
       return immutable_.foreground_classifier->ShouldInvertColor(color) ==
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.h b/third_party/blink/renderer/platform/graphics/dark_mode_filter.h
index 2149173..0e3cfcc6 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.h
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.h
@@ -33,7 +33,7 @@
   // TODO(gilmanmh): Add a role for shadows. In general, we don't want to
   // invert shadows, but we may need to do some other kind of processing for
   // them.
-  enum class ElementRole { kText, kListSymbol, kBackground, kSVG };
+  enum class ElementRole { kForeground, kListSymbol, kBackground, kSVG };
 
   DarkModeImagePolicy GetDarkModeImagePolicy() const;
 
diff --git a/third_party/blink/renderer/platform/graphics/filters/filter_effect.h b/third_party/blink/renderer/platform/graphics/filters/filter_effect.h
index 3b8294a..d11bddbc 100644
--- a/third_party/blink/renderer/platform/graphics/filters/filter_effect.h
+++ b/third_party/blink/renderer/platform/graphics/filters/filter_effect.h
@@ -29,6 +29,7 @@
 #include "third_party/blink/renderer/platform/graphics/color.h"
 #include "third_party/blink/renderer/platform/graphics/interpolation_space.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_filter.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h
index c47bc37..dcf727c7 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h
@@ -12,6 +12,8 @@
 #include "third_party/blink/renderer/platform/graphics/paint/paint_artifact.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_chunk.h"
 #include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller.h b/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
index 1d2561e..f00055d 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
@@ -22,6 +22,7 @@
 #include "third_party/blink/renderer/platform/graphics/paint/paint_chunk.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_chunker.h"
 #include "third_party/blink/renderer/platform/graphics/paint/region_capture_data.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_under_invalidation_checker.h b/third_party/blink/renderer/platform/graphics/paint/paint_under_invalidation_checker.h
index cbe8b89..1cae282 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_under_invalidation_checker.h
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_under_invalidation_checker.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_PAINT_UNDER_INVALIDATION_CHECKER_H_
 
 #include "third_party/blink/renderer/platform/graphics/graphics_types.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h b/third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h
index bab23053..a4594f96 100644
--- a/third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h
+++ b/third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h
@@ -37,10 +37,13 @@
       gr_context_ = GrDirectContext::MakeMock(&mockOptions);
     }
 
-    // TODO(nazabris, crbug.com/1017508) Use RasterImplementation after
-    // all references to GLES2Interface have been removed.
-    raster_interface_ =
-        std::make_unique<gpu::raster::RasterImplementationGLES>(gl_, nullptr);
+    if (!raster_context_provider_) {
+      // If there is no raster context provider, fall back to using a locally
+      // created raster interface. Unit tests that want to use something other
+      // than RasterImplementationGLES should pas a raster_context_provider.
+      raster_interface_ =
+          std::make_unique<gpu::raster::RasterImplementationGLES>(gl_, nullptr);
+    }
 
     webgpu_interface_ = std::make_unique<gpu::webgpu::WebGPUInterfaceStub>();
 
@@ -72,10 +75,9 @@
   gpu::InterfaceBase* InterfaceBase() override { return gl_; }
   gpu::gles2::GLES2Interface* ContextGL() override { return gl_; }
   gpu::raster::RasterInterface* RasterInterface() override {
-    if (!raster_interface_)
-      return nullptr;
-
-    return raster_interface_.get();
+    return raster_context_provider_
+               ? raster_context_provider_->RasterInterface()
+               : raster_interface_.get();
   }
   bool IsContextLost() override {
     return RasterInterface() &&
diff --git a/third_party/blink/renderer/platform/heap/BUILD.gn b/third_party/blink/renderer/platform/heap/BUILD.gn
index 2f486ef..b31e4c5 100644
--- a/third_party/blink/renderer/platform/heap/BUILD.gn
+++ b/third_party/blink/renderer/platform/heap/BUILD.gn
@@ -41,7 +41,6 @@
     "gc_task_runner.h",
     "handle.h",
     "heap.h",
-    "heap_allocator.h",
     "heap_allocator_impl.h",
     "heap_traits.h",
     "member.h",
diff --git a/third_party/blink/renderer/platform/heap/handle.h b/third_party/blink/renderer/platform/heap/handle.h
index cf69b70..4c0e24dd 100644
--- a/third_party/blink/renderer/platform/heap/handle.h
+++ b/third_party/blink/renderer/platform/heap/handle.h
@@ -31,13 +31,13 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HANDLE_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HANDLE_H_
 
+// TODO(chromium:1269227): Clean up the following catch-all includes and require
+// IWYU for users of platform/heap.
+
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
-#include "third_party/blink/renderer/platform/heap/heap_traits.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
-#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HANDLE_H_
diff --git a/third_party/blink/renderer/platform/heap/heap_allocator.h b/third_party/blink/renderer/platform/heap/heap_allocator.h
deleted file mode 100644
index 989490e..0000000
--- a/third_party/blink/renderer/platform/heap/heap_allocator.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_
-
-// Legacy: Users including `heap_allocator.h` actually expect it to pull in the
-// containers.
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_
diff --git a/third_party/blink/renderer/platform/heap/heap_traits.h b/third_party/blink/renderer/platform/heap/heap_traits.h
index cb1f430..ce4eca3 100644
--- a/third_party/blink/renderer/platform/heap/heap_traits.h
+++ b/third_party/blink/renderer/platform/heap/heap_traits.h
@@ -7,7 +7,7 @@
 
 #include <type_traits>
 
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/type_traits.h"
 
diff --git a/third_party/blink/renderer/platform/heap/test/concurrent_marking_test.cc b/third_party/blink/renderer/platform/heap/test/concurrent_marking_test.cc
index f72f01c..e21da88 100644
--- a/third_party/blink/renderer/platform/heap/test/concurrent_marking_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/concurrent_marking_test.cc
@@ -6,8 +6,13 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_objects.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
diff --git a/third_party/blink/renderer/platform/heap/test/heap_compact_test.cc b/third_party/blink/renderer/platform/heap/test/heap_compact_test.cc
index a6cca2a..b1eecd4 100644
--- a/third_party/blink/renderer/platform/heap/test/heap_compact_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/heap_compact_test.cc
@@ -3,6 +3,10 @@
 // found in the LICENSE file.
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
diff --git a/third_party/blink/renderer/platform/heap/test/heap_test.cc b/third_party/blink/renderer/platform/heap/test/heap_test.cc
index 36b1e517..505b8ae1 100644
--- a/third_party/blink/renderer/platform/heap/test/heap_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/heap_test.cc
@@ -35,6 +35,11 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_objects.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_platform.h"
diff --git a/third_party/blink/renderer/platform/heap/test/incremental_marking_test.cc b/third_party/blink/renderer/platform/heap/test/incremental_marking_test.cc
index e8c0e32..0119a9e0 100644
--- a/third_party/blink/renderer/platform/heap/test/incremental_marking_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/incremental_marking_test.cc
@@ -9,9 +9,14 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_objects.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
diff --git a/third_party/blink/renderer/platform/heap/test/weakness_marking_test.cc b/third_party/blink/renderer/platform/heap/test/weakness_marking_test.cc
index a0ca722..dcc539d 100644
--- a/third_party/blink/renderer/platform/heap/test/weakness_marking_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/weakness_marking_test.cc
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_objects.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
diff --git a/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h b/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h
index f0bf6492..842d153 100644
--- a/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h
+++ b/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h
@@ -6,8 +6,10 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_INSTRUMENTATION_MEMORY_PRESSURE_LISTENER_H_
 
 #include "base/memory/memory_pressure_listener.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/loader/fetch/memory_cache.h b/third_party/blink/renderer/platform/loader/fetch/memory_cache.h
index 5c44bc0..d741e55 100644
--- a/third_party/blink/renderer/platform/loader/fetch/memory_cache.h
+++ b/third_party/blink/renderer/platform/loader/fetch/memory_cache.h
@@ -26,6 +26,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_MEMORY_CACHE_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_MEMORY_CACHE_H_
 
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/forward.h"
 #include "third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/memory_cache_dump_provider.h"
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.h b/third_party/blink/renderer/platform/loader/fetch/resource.h
index e9cda39..30d6405 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource.h
@@ -34,6 +34,8 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/mojom/loader/code_cache.mojom-blink-forward.h"
 #include "third_party/blink/public/platform/scheduler/web_scoped_virtual_time_pauser.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/web_process_memory_dump.h"
 #include "third_party/blink/renderer/platform/loader/fetch/integrity_metadata.h"
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
index 5524d64..87a8994 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
@@ -35,6 +35,7 @@
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink-forward.h"
 #include "third_party/blink/public/mojom/service_worker/controller_service_worker_mode.mojom-blink-forward.h"
 #include "third_party/blink/public/platform/web_url_loader.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/heap/prefinalizer.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
index 34d02891..a03ef2a 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -47,7 +47,6 @@
 #include "third_party/blink/public/platform/web_url_response.h"
 #include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_info.h"
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h
index 09cd45a..a68a78e 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h
@@ -11,8 +11,8 @@
 #include "base/time/time.h"
 #include "base/types/strong_alias.h"
 #include "net/http/http_response_info.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_response.cc b/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
index 3b8272d..946a69d 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
@@ -231,7 +231,7 @@
 void ResourceResponse::SetSSLInfo(const net::SSLInfo& ssl_info) {
   DCHECK_NE(security_style_, SecurityStyle::kUnknown);
   DCHECK_NE(security_style_, SecurityStyle::kNeutral);
-  ssl_info_.ssl_info = std::make_unique<net::SSLInfo>(ssl_info);
+  ssl_info_ = ssl_info;
 }
 
 bool ResourceResponse::IsCorsSameOrigin() const {
@@ -503,28 +503,6 @@
   }
 }
 
-ResourceResponse::OptionalSSLInfo::OptionalSSLInfo() = default;
-ResourceResponse::OptionalSSLInfo::OptionalSSLInfo(
-    ResourceResponse::OptionalSSLInfo&&) = default;
-ResourceResponse::OptionalSSLInfo::OptionalSSLInfo(
-    const ResourceResponse::OptionalSSLInfo& other) {
-  *this = other;
-}
-
-ResourceResponse::OptionalSSLInfo::~OptionalSSLInfo() = default;
-
-ResourceResponse::OptionalSSLInfo& ResourceResponse::OptionalSSLInfo::operator=(
-    ResourceResponse::OptionalSSLInfo&&) = default;
-ResourceResponse::OptionalSSLInfo& ResourceResponse::OptionalSSLInfo::operator=(
-    const ResourceResponse::OptionalSSLInfo& other) {
-  if (other.ssl_info) {
-    ssl_info = std::make_unique<net::SSLInfo>(*other.ssl_info);
-  } else {
-    ssl_info = nullptr;
-  }
-  return *this;
-}
-
 STATIC_ASSERT_ENUM(WebURLResponse::kHTTPVersionUnknown,
                    ResourceResponse::kHTTPVersionUnknown);
 STATIC_ASSERT_ENUM(WebURLResponse::kHTTPVersion_0_9,
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_response.h b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
index a380c99..71b055b 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_response.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
@@ -215,7 +215,7 @@
     security_style_ = security_style;
   }
 
-  const net::SSLInfo* GetSSLInfo() const { return ssl_info_.ssl_info.get(); }
+  const absl::optional<net::SSLInfo>& GetSSLInfo() const { return ssl_info_; }
   void SetSSLInfo(const net::SSLInfo& ssl_info);
 
   const KURL& WebBundleURL() const { return web_bundle_url_; }
@@ -429,21 +429,6 @@
   }
 
  private:
-  // Behaves like an `absl::optional<net::SSLInfo>`, except it is stored in
-  // `std::unique_ptr` to reduce memory in the common case when it is omitted.
-  // (`ResourceResponse` primarily only has `net::SSLInfo` when DevTools is
-  // open.) This wrapper is needed to provide a copy constructor.
-  struct OptionalSSLInfo {
-    OptionalSSLInfo();
-    OptionalSSLInfo(OptionalSSLInfo&&);
-    OptionalSSLInfo(const OptionalSSLInfo&);
-    ~OptionalSSLInfo();
-    OptionalSSLInfo& operator=(OptionalSSLInfo&&);
-    OptionalSSLInfo& operator=(const OptionalSSLInfo&);
-
-    std::unique_ptr<net::SSLInfo> ssl_info;
-  };
-
   void UpdateHeaderParsedState(const AtomicString& name);
 
   KURL current_request_url_;
@@ -570,7 +555,7 @@
   SecurityStyle security_style_ = SecurityStyle::kUnknown;
 
   // Security details of this request's connection.
-  OptionalSSLInfo ssl_info_;
+  absl::optional<net::SSLInfo> ssl_info_;
 
   scoped_refptr<ResourceLoadTiming> resource_load_timing_;
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc b/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc
index bcd44fd..1b69351 100644
--- a/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/platform/loader/fetch/resource.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_loader.h"
 #include "third_party/blink/renderer/platform/loader/fetch/url_loader/navigation_body_loader.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/navigation_body_loader_unittest.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/navigation_body_loader_unittest.cc
index 95a62f5e..5d80914 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/navigation_body_loader_unittest.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/navigation_body_loader_unittest.cc
@@ -351,7 +351,8 @@
       std::make_unique<ResourceLoadInfoNotifierWrapper>(
           /*resource_load_info_notifier=*/nullptr),
       /*is_main_frame=*/true, &navigation_params);
-  EXPECT_TRUE(navigation_params.response.ToResourceResponse().GetSSLInfo());
+  EXPECT_TRUE(
+      navigation_params.response.ToResourceResponse().GetSSLInfo().has_value());
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc
index 50ba3a6..d176e7d 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc
@@ -601,9 +601,9 @@
   WebURLResponse web_url_response;
   WebURLLoader::PopulateURLResponse(url, head, &web_url_response, true, -1);
 
-  const net::SSLInfo* got_ssl_info =
+  const absl::optional<net::SSLInfo>& got_ssl_info =
       web_url_response.ToResourceResponse().GetSSLInfo();
-  ASSERT_TRUE(got_ssl_info);
+  ASSERT_TRUE(got_ssl_info.has_value());
   EXPECT_EQ(ssl_info.connection_status, got_ssl_info->connection_status);
   EXPECT_TRUE(ssl_info.cert->EqualsIncludingChain(got_ssl_info->cert.get()));
 }
diff --git a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
index 7a58095f..a6b4dcc 100644
--- a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
+++ b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
@@ -327,6 +327,8 @@
       // probably accurate enough for metrics.
       destination_url_data->set_has_access_control();
     }
+
+    destination_url_data->set_mime_type(response.MimeType().Utf8());
   }
 
   if (destination_url_data != url_data_) {
diff --git a/third_party/blink/renderer/platform/media/url_index.cc b/third_party/blink/renderer/platform/media/url_index.cc
index 353cc6ac..8038f473 100644
--- a/third_party/blink/renderer/platform/media/url_index.cc
+++ b/third_party/blink/renderer/platform/media/url_index.cc
@@ -117,6 +117,10 @@
   has_access_control_ = true;
 }
 
+void UrlData::set_mime_type(std::string mime_type) {
+  mime_type_ = std::move(mime_type);
+}
+
 void UrlData::RedirectTo(const scoped_refptr<UrlData>& url_data) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   // Copy any cached data over to the new location.
diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl.cc b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
index cfe965c..3ffdb0b1 100644
--- a/third_party/blink/renderer/platform/media/web_media_player_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
@@ -327,6 +327,60 @@
   return renderer_type != media::RendererType::kMediaFoundation;
 }
 
+#if defined(OS_ANDROID)
+
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class MimeType {
+  kOtherMimeType = 0,
+  kApplicationDashXml = 1,
+  kApplicationOgg = 2,
+  kApplicationMpegUrl = 3,
+  kApplicationVndAppleMpegUrl = 4,
+  kApplicationXMpegUrl = 5,
+  kAudioMpegUrl = 6,
+  kAudioXMpegUrl = 7,
+  kNonspecificAudio = 8,
+  kNonspecificImage = 9,
+  kNonspecificVideo = 10,
+  kTextVtt = 11,
+  kMaxValue = kTextVtt,  // For UMA histograms.
+};
+MimeType TranslateMimeTypeToHistogramEnum(const std::string& mime_type) {
+  constexpr auto kCaseInsensitive = base::CompareCase::INSENSITIVE_ASCII;
+  if (base::StartsWith(mime_type, "application/dash+xml", kCaseInsensitive))
+    return MimeType::kApplicationDashXml;
+  if (base::StartsWith(mime_type, "application/ogg", kCaseInsensitive))
+    return MimeType::kApplicationOgg;
+  if (base::StartsWith(mime_type, "application/mpegurl", kCaseInsensitive))
+    return MimeType::kApplicationMpegUrl;
+  if (base::StartsWith(mime_type, "application/vnd.apple.mpegurl",
+                       kCaseInsensitive)) {
+    return MimeType::kApplicationVndAppleMpegUrl;
+  }
+  if (base::StartsWith(mime_type, "application/x-mpegurl", kCaseInsensitive))
+    return MimeType::kApplicationXMpegUrl;
+
+  if (base::StartsWith(mime_type, "audio/mpegurl", kCaseInsensitive))
+    return MimeType::kAudioMpegUrl;
+  if (base::StartsWith(mime_type, "audio/x-mpegurl", kCaseInsensitive))
+    return MimeType::kAudioXMpegUrl;
+
+  if (base::StartsWith(mime_type, "audio/", kCaseInsensitive))
+    return MimeType::kNonspecificAudio;
+  if (base::StartsWith(mime_type, "image/", kCaseInsensitive))
+    return MimeType::kNonspecificImage;
+  if (base::StartsWith(mime_type, "video/", kCaseInsensitive))
+    return MimeType::kNonspecificVideo;
+
+  if (base::StartsWith(mime_type, "text/vtt", kCaseInsensitive))
+    return MimeType::kTextVtt;
+
+  return MimeType::kOtherMimeType;
+}
+
+#endif
+
 }  // namespace
 
 class BufferedDataSourceHostImpl;
@@ -1810,6 +1864,15 @@
                             mb_data_source_->HasAccessControl());
     }
 
+    MimeType mime_type =
+        TranslateMimeTypeToHistogramEnum(mb_data_source_->mime_type());
+    base::UmaHistogramEnumeration("Media.WebMediaPlayerImpl.HLS.MimeType",
+                                  mime_type);
+    if (mb_data_source_->IsCorsCrossOrigin()) {
+      base::UmaHistogramEnumeration(
+          "Media.WebMediaPlayerImpl.HLS.CorsCrossOrigin.MimeType", mime_type);
+    }
+
     // Note: Does not consider the full redirect chain, which could contain
     // undetected mixed content.
     bool frame_url_is_cryptographic = url::Origin(frame_->GetSecurityOrigin())
diff --git a/third_party/blink/renderer/platform/mediastream/media_constraints.cc b/third_party/blink/renderer/platform/mediastream/media_constraints.cc
index e0a773b..e9642a5 100644
--- a/third_party/blink/renderer/platform/mediastream/media_constraints.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_constraints.cc
@@ -372,6 +372,7 @@
       voice_activity_detection("voiceActivityDetection"),
       ice_restart("iceRestart"),
       goog_use_rtp_mux("googUseRtpMux"),
+      enable_dtls_srtp("enableDtlsSrtp"),
       enable_rtp_data_channels("enableRtpDataChannels"),
       enable_dscp("enableDscp"),
       enable_i_pv6("enableIPv6"),
@@ -424,6 +425,7 @@
           &voice_activity_detection,
           &ice_restart,
           &goog_use_rtp_mux,
+          &enable_dtls_srtp,
           &enable_rtp_data_channels,
           &enable_dscp,
           &enable_i_pv6,
diff --git a/third_party/blink/renderer/platform/mediastream/media_constraints.h b/third_party/blink/renderer/platform/mediastream/media_constraints.h
index bef2fa4f..34f3d0f8 100644
--- a/third_party/blink/renderer/platform/mediastream/media_constraints.h
+++ b/third_party/blink/renderer/platform/mediastream/media_constraints.h
@@ -269,6 +269,7 @@
   BooleanConstraint voice_activity_detection;
   BooleanConstraint ice_restart;
   BooleanConstraint goog_use_rtp_mux;
+  BooleanConstraint enable_dtls_srtp;
   BooleanConstraint enable_rtp_data_channels;
   BooleanConstraint enable_dscp;
   BooleanConstraint enable_i_pv6;
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_component.h b/third_party/blink/renderer/platform/mediastream/media_stream_component.h
index 24abe5af..0d05fb024 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_component.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_component.h
@@ -37,6 +37,7 @@
 #include "third_party/blink/public/platform/modules/mediastream/web_media_stream_track.h"
 #include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/renderer/platform/audio/audio_source_provider.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/prefinalizer.h"
 #include "third_party/blink/renderer/platform/mediastream/media_constraints.h"
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_source.h b/third_party/blink/renderer/platform/mediastream/media_stream_source.h
index 27ed131..a886643 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_source.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_source.h
@@ -40,6 +40,7 @@
 #include "third_party/blink/public/platform/modules/mediastream/web_media_stream_track.h"
 #include "third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_source.h"
 #include "third_party/blink/renderer/platform/audio/audio_destination_consumer.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/prefinalizer.h"
 #include "third_party/blink/renderer/platform/mediastream/media_constraints.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_track_platform.h"
diff --git a/third_party/blink/renderer/platform/mhtml/mhtml_archive.h b/third_party/blink/renderer/platform/mhtml/mhtml_archive.h
index e1462c0..31e74a7 100644
--- a/third_party/blink/renderer/platform/mhtml/mhtml_archive.h
+++ b/third_party/blink/renderer/platform/mhtml/mhtml_archive.h
@@ -32,6 +32,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_MHTML_MHTML_ARCHIVE_H_
 
 #include "third_party/blink/public/mojom/loader/mhtml_load_result.mojom-blink-forward.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
diff --git a/third_party/blink/renderer/platform/mojo/drag_mojom_traits.cc b/third_party/blink/renderer/platform/mojo/drag_mojom_traits.cc
index d200855..d838396 100644
--- a/third_party/blink/renderer/platform/mojo/drag_mojom_traits.cc
+++ b/third_party/blink/renderer/platform/mojo/drag_mojom_traits.cc
@@ -132,8 +132,8 @@
 // static
 bool StructTraits<blink::mojom::DragItemBinaryDataView,
                   blink::WebDragData::Item>::
-    is_accessible_from_start_frame(const blink::WebDragData::Item& item) {
-  return item.binary_data_accessible_from_start_frame;
+    is_image_accessible(const blink::WebDragData::Item& item) {
+  return item.binary_data_image_accessible;
 }
 
 // static
@@ -176,8 +176,7 @@
   item.binary_data =
       blink::WebData(reinterpret_cast<const char*>(file_contents.data().data()),
                      file_contents.data().size());
-  item.binary_data_accessible_from_start_frame =
-      data.is_accessible_from_start_frame();
+  item.binary_data_image_accessible = data.is_image_accessible();
   item.binary_data_source_url = source_url;
   item.binary_data_filename_extension =
       blink::FilePathToWebString(filename_extension);
diff --git a/third_party/blink/renderer/platform/mojo/drag_mojom_traits.h b/third_party/blink/renderer/platform/mojo/drag_mojom_traits.h
index 47886f5..58153f6 100644
--- a/third_party/blink/renderer/platform/mojo/drag_mojom_traits.h
+++ b/third_party/blink/renderer/platform/mojo/drag_mojom_traits.h
@@ -60,8 +60,7 @@
 struct PLATFORM_EXPORT StructTraits<blink::mojom::DragItemBinaryDataView,
                                     blink::WebDragData::Item> {
   static mojo_base::BigBuffer data(const blink::WebDragData::Item& item);
-  static bool is_accessible_from_start_frame(
-      const blink::WebDragData::Item& item);
+  static bool is_image_accessible(const blink::WebDragData::Item& item);
   static blink::KURL source_url(const blink::WebDragData::Item& item);
   static base::FilePath filename_extension(
       const blink::WebDragData::Item& item);
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index c06e188..a370bf0b 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -309,10 +309,6 @@
       name: "BlinkRuntimeCallStats",
     },
     {
-      name: "BlockCredentialedSubresources",
-      status: "stable",
-    },
-    {
       name: "BlockingFocusWithoutUserActivation",
       status: "experimental",
     },
@@ -2689,6 +2685,11 @@
       depends_on: ["WebXRARModule"],
       status: "stable",
     },
+    // New behavior for window.open's interpretation of the windowFeatures parameter.
+    {
+      name: "WindowOpenNewPopupBehavior",
+      status: "stable",
+    },
     // Extends window placement functionality for multi-screen devices. Also
     // exposes requisite information about displays connected to the device.
     {
diff --git a/third_party/blink/renderer/platform/supplementable.h b/third_party/blink/renderer/platform/supplementable.h
index 35800b2..e5967a26 100644
--- a/third_party/blink/renderer/platform/supplementable.h
+++ b/third_party/blink/renderer/platform/supplementable.h
@@ -29,8 +29,8 @@
 #include <cstddef>
 
 #include "base/dcheck_is_on.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
 #if DCHECK_IS_ON()
 #include "third_party/blink/renderer/platform/wtf/threading.h"
diff --git a/third_party/blink/renderer/platform/text/date_time_format.cc b/third_party/blink/renderer/platform/text/date_time_format.cc
index 54a2ca0..3e4a0ea 100644
--- a/third_party/blink/renderer/platform/text/date_time_format.cc
+++ b/third_party/blink/renderer/platform/text/date_time_format.cc
@@ -25,6 +25,7 @@
 
 #include "third_party/blink/renderer/platform/text/date_time_format.h"
 
+#include "base/notreached.h"
 #include "third_party/blink/renderer/platform/wtf/text/ascii_ctype.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
diff --git a/third_party/blink/renderer/platform/wtf/functional.h b/third_party/blink/renderer/platform/wtf/functional.h
index 63a115e..34db10c 100644
--- a/third_party/blink/renderer/platform/wtf/functional.h
+++ b/third_party/blink/renderer/platform/wtf/functional.h
@@ -31,6 +31,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/dcheck_is_on.h"
+#include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/threading/thread_checker.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -144,12 +145,26 @@
 }
 
 template <typename T>
+UnretainedWrapper<T> Unretained(const raw_ptr<T>& value) {
+  static_assert(!WTF::IsGarbageCollectedType<T>::value,
+                "WTF::Unretained() + GCed type is forbidden");
+  return UnretainedWrapper<T>(value.get());
+}
+
+template <typename T>
 CrossThreadUnretainedWrapper<T> CrossThreadUnretained(T* value) {
   static_assert(!WTF::IsGarbageCollectedType<T>::value,
                 "CrossThreadUnretained() + GCed type is forbidden");
   return CrossThreadUnretainedWrapper<T>(value);
 }
 
+template <typename T>
+CrossThreadUnretainedWrapper<T> CrossThreadUnretained(const raw_ptr<T>& value) {
+  static_assert(!WTF::IsGarbageCollectedType<T>::value,
+                "CrossThreadUnretained() + GCed type is forbidden");
+  return CrossThreadUnretainedWrapper<T>(value.get());
+}
+
 namespace internal {
 
 template <size_t, typename T>
diff --git a/third_party/blink/renderer/platform/wtf/functional_test.cc b/third_party/blink/renderer/platform/wtf/functional_test.cc
index d74ee9c5..0869300 100644
--- a/third_party/blink/renderer/platform/wtf/functional_test.cc
+++ b/third_party/blink/renderer/platform/wtf/functional_test.cc
@@ -29,6 +29,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/test/gtest_util.h"
 #include "base/threading/thread.h"
@@ -156,6 +157,19 @@
   EXPECT_EQ(1, counter);
 }
 
+int PingPong(int* i_ptr) {
+  return *i_ptr;
+}
+
+TEST(FunctionalTest, RawPtr) {
+  int i = 123;
+  raw_ptr<int> p = &i;
+
+  auto callback = WTF::BindRepeating(PingPong, WTF::Unretained(p));
+  int res = callback.Run();
+  EXPECT_EQ(123, res);
+}
+
 void MakeClosure(base::OnceClosure** closure_out) {
   *closure_out = new base::OnceClosure(WTF::Bind([] {}));
   LEAK_SANITIZER_IGNORE_OBJECT(*closure_out);
diff --git a/third_party/blink/renderer/platform/wtf/sequence_bound.h b/third_party/blink/renderer/platform/wtf/sequence_bound.h
index b6fdf11..daa32310 100644
--- a/third_party/blink/renderer/platform/wtf/sequence_bound.h
+++ b/third_party/blink/renderer/platform/wtf/sequence_bound.h
@@ -35,7 +35,7 @@
   }
 
   template <typename T>
-  static inline auto Unretained(T* ptr) {
+  static inline auto Unretained(T ptr) {
     return CrossThreadUnretained(ptr);
   }
 
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
index 632c921..6563c3b 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
@@ -338,32 +338,6 @@
         return self.git_cl.latest_try_jobs(builder_names=builder_names,
                                            patchset=self.patchset)
 
-    def get_test_ids_with_unexpected_results(self, builds, test_suite):
-        """Returns a set of test ids for which to create baselines and expectations.
-
-        Only tests that always run unexpected from the initial step are included.
-        These tests either failed all three retries, or is an unexpected pass. We do not
-        create test expectations for passed tests even if they have flaky results, so
-        that we do not create excessive test expectations, thus negatively impact the
-        test coverage.
-        Once we decided the list of tests to work on, results from both the initial step
-        and retry-with-patch step are used to create test expecations.
-        """
-        rv = set()
-        predicate = {"expectancy": "VARIANTS_WITH_ONLY_UNEXPECTED_RESULTS"}
-        test_results_list = self.host.results_fetcher.fetch_results_from_resultdb(self.host, builds, predicate)
-        for result in test_results_list:
-            test_id = result["testId"]
-            test_name = test_id[len(self.testid_prefix):]
-            if not self._is_wpt_test(test_name):
-                continue
-            if result["variant"]["def"]["test_suite"] != test_suite:
-                continue
-            if result["status"] == "PASS" and not self.options.include_unexpected_pass:
-                continue
-            rv.add(test_id)
-        return rv
-
     def get_failing_results_dicts(self, build, test_suite):
         """Returns a list of nested dicts of failing test results.
 
@@ -391,7 +365,11 @@
         test_results_list = []
         predicate = {"expectancy": "VARIANTS_WITH_ONLY_UNEXPECTED_RESULTS"}
         rv = self.host.results_fetcher.fetch_results_from_resultdb(self.host, [build], predicate)
-        rv = filter(func, rv)
+        rv = list(filter(func, rv))
+        if not self.options.include_unexpected_pass:
+            # if a test first fail then passed unexpectedly
+            passed_test_ids = set([r["testId"] for r in rv if r["status"] == "PASS"])
+            rv = [r for r in rv if r["testId"] not in passed_test_ids]
         test_results_list.extend(rv)
 
         has_webdriver_tests = self.host.builders.has_webdriver_tests_for_builder(
@@ -826,8 +804,8 @@
             line_parts.append(test_name.replace('*', '\\*'))
             line_parts.append(expectations)
 
-            # Only add the bug link if the expectations do not include WontFix.
-            if 'WontFix' not in expectations and result.bug:
+            # Only add the bug link if the expectations do not include SKIP.
+            if 'Skip' not in expectations and result.bug:
                 line_parts.insert(0, result.bug)
 
             lines.append(' '.join(line_parts))
@@ -1018,7 +996,8 @@
             self.host.filesystem.write_text_file(expectations_file_path,
                                                  file_contents)
 
-        if wont_fix_list:
+        # only write to NeverFixTests for the generic round
+        if wont_fix_list and flag_specific is None:
             _log.info('Lines to write to NeverFixTests:\n %s',
                       '\n'.join(wont_fix_list))
             # Writes to NeverFixTests file.
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
index 6ae4bb08..91ae856 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
@@ -613,8 +613,8 @@
         self.assertEqual(
             line_dict, {
                 'virtual/foo/external/wpt/test/aa-manual.html': [
-                    'crbug.com/test [ Trusty ] virtual/foo/external/wpt/test/aa-manual.html [ Skip ]',
-                    'crbug.com/test [ Mac10.11 ] virtual/foo/external/wpt/test/aa-manual.html [ Skip ]',
+                    '[ Trusty ] virtual/foo/external/wpt/test/aa-manual.html [ Skip ]',
+                    '[ Mac10.11 ] virtual/foo/external/wpt/test/aa-manual.html [ Skip ]',
                 ],
             })
 
@@ -1363,7 +1363,7 @@
         self.assertEqual(
             line_dict, {
                 'external/wpt/x-manual.html':
-                ['crbug.com/test external/wpt/x-manual.html [ Skip ]']
+                ['external/wpt/x-manual.html [ Skip ]']
             })
 
     def test_same_platform_one_without_results(self):
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations
index ee94cf4c..2690625 100644
--- a/third_party/blink/web_tests/MSANExpectations
+++ b/third_party/blink/web_tests/MSANExpectations
@@ -70,8 +70,6 @@
 crbug.com/760543 [ Linux ] http/tests/devtools/tracing/timeline-time/timeline-usertiming.js [ Pass Timeout ]
 crbug.com/760543 [ Linux ] http/tests/devtools/tracing/timeline-paint/timeline-paint.js [ Pass Timeout ]
 crbug.com/760543 [ Linux ] http/tests/devtools/oopif/oopif-performance-cpu-profiles.js [ Pass Timeout ]
-crbug.com/902685 [ Linux ] http/tests/devtools/isolated-code-cache/same-origin-test.js [ Pass Timeout ]
-crbug.com/902685 [ Linux ] http/tests/devtools/isolated-code-cache/cross-origin-test.js [ Pass Timeout ]
 
 # Memory allocation hooks are disabled on ASAN/MSAN
 crbug.com/803276 inspector-protocol/memory/sampling-native-profile.js [ Skip ]
@@ -168,7 +166,6 @@
 crbug.com/1179829 [ Linux ] http/tests/devtools/console/console-format.js [ Pass Timeout ]
 crbug.com/1179829 [ Linux ] http/tests/devtools/tracing/console-timeline.js [ Pass Timeout ]
 crbug.com/1179829 [ Linux ] http/tests/devtools/console/console-viewport-stick-to-bottom-onload.js [ Pass Timeout ]
-crbug.com/1179829 [ Linux ] http/tests/devtools/isolated-code-cache/stale-revalidation-test.js [ Pass Timeout ]
 
 # Sheriff 2021-04-22
 crbug.com/1201807 [ Linux ] virtual/feature-policy-permissions/external/wpt/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index f9fdbad..98b7e1d 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -1295,6 +1295,11 @@
 external/wpt/html-media-capture/capture_video_missing-manual.html [ Skip ]
 external/wpt/html-media-capture/capture_video_user-manual.html [ Skip ]
 external/wpt/html/browsers/browsing-the-web/unloading-documents/unload/pagehide-manual.html [ Skip ]
+external/wpt/html/browsers/offline/application-cache-api/api_status_checking-manual.html [ Skip ]
+external/wpt/html/browsers/offline/application-cache-api/api_status_downloading-manual.html [ Skip ]
+external/wpt/html/browsers/offline/application-cache-api/api_status_obsolete-manual.html [ Skip ]
+external/wpt/html/browsers/offline/application-cache-api/api_status_updateready-manual.html [ Skip ]
+external/wpt/html/browsers/offline/application-cache-api/api_swapcache-manual.html [ Skip ]
 external/wpt/html/browsers/offline/browser-state/navigator_online_event-manual.https.html [ Skip ]
 external/wpt/html/browsers/offline/manifest_main_empty-manual.https.html [ Skip ]
 external/wpt/html/browsers/offline/manifest_notchanged_online-manual.https.html [ Skip ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 89158de..4d197777 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -98,11 +98,7 @@
 #   --enable-features=ForceSynchronousHTMLParsing,LoaderDataPipeTuning:allocation_size_bytes/2097152/loader_chunk_size/1048576
 
 # app-history tests - fail:
-crbug.com/1254926 external/wpt/app-history/navigate-event/navigate-history-back-after-fragment.html [ Failure ]
 crbug.com/1254926 external/wpt/app-history/navigate/navigate-same-document-event-order.html [ Failure ]
-crbug.com/1254926 external/wpt/app-history/currentchange-event/currentchange-app-history-back-forward-same-doc.html [ Failure ]
-crbug.com/1254926 external/wpt/app-history/currentchange-event/currentchange-app-history-navigate-same-doc.html [ Failure ]
-crbug.com/1254926 external/wpt/app-history/currentchange-event/currentchange-history-back-same-doc.html [ Failure ]
 
 # Extra line info appears in the output in some cases.
 crbug.com/1254932 http/tests/preload/meta-csp.html [ Failure ]
@@ -2057,6 +2053,7 @@
 crbug.com/846656 external/wpt/css/selectors/focus-visible-002.html [ Pass Skip Timeout ]
 crbug.com/1135405 http/tests/devtools/sources/debugger-pause/debugger-pause-infinite-loop.js [ Pass Skip Timeout ]
 crbug.com/1034789 [ Mac ] http/tests/security/frameNavigation/xss-ALLOWED-parent-navigation-change-async.html [ Pass Timeout ]
+crbug.com/1034789 [ Linux ] http/tests/security/frameNavigation/xss-ALLOWED-parent-navigation-change-async.html [ Pass Timeout ]
 crbug.com/1105957 [ Debug Linux ] fast/dom/cssTarget-crash.html [ Pass Timeout ]
 crbug.com/915903 http/tests/security/inactive-document-with-empty-security-origin.html [ Pass Timeout ]
 crbug.com/987138 [ Linux ] media/controls/doubletap-to-jump-forwards.html [ Pass Timeout ]
@@ -2539,6 +2536,8 @@
 # requestIdleCallback requires threaded compositing
 crbug.com/1259718 external/wpt/requestidlecallback/* [ Skip ]
 crbug.com/1259718 virtual/threaded/external/wpt/requestidlecallback/* [ Pass ]
+crbug.com/1259718 http/tests/devtools/isolated-code-cache/* [ Skip ]
+crbug.com/1259718 virtual/threaded/http/tests/devtools/isolated-code-cache/* [ Pass ]
 
 # WebVTT is off because additional padding
 crbug.com/1012242 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_completely_move_up.html [ Failure ]
@@ -3003,7 +3002,7 @@
 
 # ====== New tests from wpt-importer added here ======
 crbug.com/626703 [ Linux ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-mouseup.html [ Timeout ]
-crbug.com/626703 [ Mac10.15 ] external/wpt/media-capabilities/encodingInfo.any.worker.html [ Crash ]
+crbug.com/1270841 [ Mac ] external/wpt/media-capabilities/encodingInfo.any.worker.html [ Crash ]
 crbug.com/626703 [ Mac11 ] virtual/plz-dedicated-worker/external/wpt/workers/constructors/SharedWorker/setting-port-members.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.15 ] virtual/without-coep-for-shared-worker/external/wpt/html/cross-origin-embedder-policy/reporting-subresource-corp.https.html [ Skip Timeout ]
 crbug.com/626703 [ Mac11 ] virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-transforms/crashtests/w-negative-002.html [ Timeout ]
@@ -3039,7 +3038,7 @@
 crbug.com/626703 [ Mac10.15 ] virtual/shared_array_buffer_on_desktop/external/wpt/compression/decompression-constructor-error.tentative.any.serviceworker.html [ Timeout ]
 crbug.com/626703 [ Win10.20h2 ] external/wpt/web-locks/bfcache/abort.tentative.https.html [ Failure Skip Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/custom-elements/form-associated/ElementInternals-validation.html [ Crash Failure ]
-crbug.com/626703 [ Mac10.15 ] external/wpt/custom-elements/form-associated/ElementInternals-validation.html [ Crash Failure ]
+crbug.com/626703 [ Mac ] external/wpt/custom-elements/form-associated/ElementInternals-validation.html [ Crash Failure ]
 crbug.com/626703 [ Win10.20h2 ] external/wpt/custom-elements/form-associated/ElementInternals-validation.html [ Crash Failure ]
 crbug.com/626703 [ Mac11 ] virtual/fenced-frame-mparch/wpt_internal/fenced_frame/create-credential.https.html [ Crash ]
 crbug.com/626703 [ Mac10.13 ] external/wpt/html/semantics/forms/the-input-element/show-picker.tentative.html [ Timeout ]
@@ -3222,8 +3221,7 @@
 crbug.com/626703 [ Mac10.15 ] wpt_internal/bluetooth/requestDevice/filter-does-not-match.https.html [ Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/resize-observer/iframe-same-origin.html [ Crash ]
 crbug.com/626703 [ Win7 ] external/wpt/resize-observer/iframe-same-origin.html [ Crash ]
-crbug.com/626703 [ Mac10.15 ] external/wpt/resize-observer/iframe-same-origin.html [ Crash ]
-crbug.com/626703 [ Mac11-arm64 ] external/wpt/resize-observer/iframe-same-origin.html [ Crash ]
+crbug.com/1270820 [ Mac ] external/wpt/resize-observer/iframe-same-origin.html [ Crash ]
 crbug.com/626703 [ Win10.20h2 ] external/wpt/resize-observer/iframe-same-origin.html [ Crash ]
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/scheduler/post-task-without-signals.any.serviceworker.html [ Crash ]
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/scheduler/post-task-without-signals.any.worker.html [ Crash ]
@@ -3238,21 +3236,13 @@
 crbug.com/626703 [ Mac11 ] external/wpt/selection/textcontrols/selectionchange-bubble.html [ Timeout ]
 crbug.com/626703 [ Win ] external/wpt/selection/textcontrols/selectionchange-bubble.html [ Timeout ]
 crbug.com/626703 external/wpt/density-size-correction/density-corrected-image-svg-aspect-ratio-cross-origin.sub.html [ Failure ]
-crbug.com/626703 [ Mac10.12 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-click.html [ Timeout ]
-crbug.com/626703 [ Mac10.13 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-click.html [ Timeout ]
-crbug.com/626703 [ Mac10.14 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-click.html [ Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-click.html [ Timeout ]
+crbug.com/1270865 [ Mac ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-click.html [ Failure Timeout ]
 crbug.com/626703 [ Win7 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-click.html [ Failure Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-click.html [ Failure Timeout ]
-crbug.com/626703 [ Mac10.15 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-click.html [ Failure Timeout ]
 crbug.com/626703 [ Win10.20h2 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-click.html [ Failure Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-assign-user-click.html [ Failure Timeout ]
-crbug.com/626703 [ Mac10.12 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-mouseup.html [ Timeout ]
-crbug.com/626703 [ Mac10.13 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-mouseup.html [ Timeout ]
-crbug.com/626703 [ Mac10.14 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-mouseup.html [ Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-mouseup.html [ Timeout ]
+crbug.com/1270842 [ Mac ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-mouseup.html [ Failure Timeout ]
 crbug.com/626703 [ Win7 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-mouseup.html [ Failure Timeout ]
-crbug.com/626703 [ Mac10.15 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-mouseup.html [ Failure Timeout ]
 crbug.com/626703 [ Win10.20h2 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-mouseup.html [ Failure Timeout ]
 crbug.com/626703 external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/a-user-click-during-pageshow.html [ Timeout ]
 crbug.com/626703 external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/a-user-click-during-load.html [ Timeout ]
@@ -3286,7 +3276,6 @@
 crbug.com/626703 [ Mac11 ] external/wpt/density-size-correction/image-set-003.html [ Failure ]
 crbug.com/626703 [ Win ] external/wpt/density-size-correction/image-set-003.html [ Failure ]
 crbug.com/626703 external/wpt/infrastructure/assumptions/non-local-ports.sub.window.html [ Timeout ]
-crbug.com/626703 [ Mac10.15 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-simulcast.https.html [ Timeout ]
 crbug.com/626703 [ Mac10.15 ] external/wpt/mediacapture-insertable-streams/MediaStreamTrackGenerator-audio.https.html [ Crash ]
 crbug.com/626703 [ Mac11 ] wpt_internal/bluetooth/requestDevice/filter-does-not-match.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-screenx-screeny.html [ Skip Timeout ]
@@ -3416,8 +3405,6 @@
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/webrtc/RTCDataChannel-iceRestart.html [ Skip Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/RTCPeerConnection-createDataChannel.html [ Skip Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/RTCPeerConnection-createDataChannel.html [ Skip Timeout ]
-crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-legacy.https.html [ Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-legacy.https.html [ Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/RTCPeerConnection-videoDetectorTest.html [ Skip Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/RTCPeerConnection-videoDetectorTest.html [ Skip Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/RTCPeerConnection-iceConnectionState-disconnected.https.html [ Skip Timeout ]
@@ -3427,8 +3414,6 @@
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/protocol/dtls-fingerprint-validation.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/protocol/dtls-fingerprint-validation.html [ Timeout ]
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/webrtc/protocol/dtls-fingerprint-validation.html [ Timeout ]
-crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc-encoded-transform/RTCEncodedAudioFrame-serviceworker-failure.https.html [ Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/RTCEncodedAudioFrame-serviceworker-failure.https.html [ Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/RTCPeerConnection-track-stats.https.html [ Skip Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/RTCPeerConnection-track-stats.https.html [ Skip Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/RTCDataChannel-send-blob-order.html [ Timeout ]
@@ -3450,8 +3435,6 @@
 crbug.com/626703 [ Mac11 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCDataChannel-iceRestart.html [ Skip Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/RTCDtlsTransport-state.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/RTCDtlsTransport-state.html [ Timeout ]
-crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-simulcast.https.html [ Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-simulcast.https.html [ Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/RTCIceTransport.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/RTCIceTransport.html [ Timeout ]
 crbug.com/626703 [ Mac10.14 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/protocol/ice-state.https.html [ Skip Timeout ]
@@ -3464,28 +3447,20 @@
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/simplecall.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/simplecall.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/protocol/split.https.html [ Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-video.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCDTMFSender-insertDTMF.https.html [ Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/RTCEncodedVideoFrame-serviceworker-failure.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/RTCPeerConnection-connectionState.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/RTCDataChannel-close.html [ Skip Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-worker.https.html [ Timeout ]
-crbug.com/626703 [ Mac11-arm64 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-worker.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-connectionState.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/simulcast/vp8.https.html [ Skip Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/protocol/handover-datachannel.html [ Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-errors.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/RTCPeerConnection-helper-test.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/protocol/candidate-exchange.https.html [ Skip Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/protocol/bundle.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/RTCPeerConnection-getStats.https.html [ Skip Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-video-frames.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/protocol/crypto-suite.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCDataChannel-bufferedAmount.html [ Skip Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/RTCDtlsTransport-getRemoteCertificates.html [ Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-audio.https.html [ Timeout ]
-crbug.com/626703 [ Mac11-arm64 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-audio.https.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/no-media-call.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-ondatachannel.html [ Skip Timeout ]
 crbug.com/626703 [ Mac11-arm64 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-ondatachannel.html [ Skip Timeout ]
@@ -3508,11 +3483,8 @@
 crbug.com/626703 [ Mac11 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/protocol/dtls-fingerprint-validation.html [ Timeout ]
 crbug.com/1209223 external/wpt/html/syntax/xmldecl/xmldecl-2.html [ Failure ]
 crbug.com/626703 [ Mac ] editing/pasteboard/drag-selected-image-to-contenteditable.html [ Failure ]
-crbug.com/626703 [ Mac10.15 ] external/wpt/webrtc-encoded-transform/idlharness.https.window.html [ Crash Failure ]
-crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/idlharness.https.window.html [ Crash Failure ]
 crbug.com/626703 [ Mac11 ] external/wpt/webxr/xrSession_requestReferenceSpace_features.https.html [ Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/focus/focus-already-focused-iframe-different-site.html [ Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/sframe-keys.https.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/focus/focus-already-focused-iframe-same-site.html [ Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/focus/focus-already-focused-iframe-deep-same-site.html [ Timeout ]
 crbug.com/626703 [ Mac10.12 ] external/wpt/focus/focus-already-focused-iframe-deep-same-site.html [ Timeout ]
@@ -3541,8 +3513,6 @@
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/Create-protocols-repeated-case-insensitive.any.html?wss [ Failure Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/websockets/basic-auth.any.worker.html?wpt_flags=h2 [ Failure Timeout ]
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/basic-auth.any.worker.html?wpt_flags=h2 [ Failure Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/websockets/stream/tentative/backpressure-send.any.serviceworker.html?wpt_flags=h2 [ Failure Skip Timeout ]
-crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/stream/tentative/backpressure-send.any.serviceworker.html?wpt_flags=h2 [ Failure Skip Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/worklets/paint-worklet-credentials.https.html [ Failure Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/css/css-images/image-set/image-set-parsing.html [ Failure Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/dom/xslt/transformToFragment.tentative.window.html [ Failure Timeout ]
@@ -3550,9 +3520,6 @@
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/editing/other/editing-around-select-element.tentative.html?insertText [ Failure Skip Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/fetch/api/basic/request-upload.any.serviceworker.html [ Failure Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/shadow-dom/accesskey.tentative.html [ Failure Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/script-metadata-transform.https.html [ Failure Timeout ]
-crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/script-write-twice-transform.https.html [ Failure Timeout ]
-# crbug.com/626703 [ Mac11 ] external/wpt/webrtc-encoded-transform/sframe-transform-buffer-source.html [ Failure Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/websockets/basic-auth.any.sharedworker.html?wpt_flags=h2 [ Failure Timeout ]
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/basic-auth.any.sharedworker.html?wpt_flags=h2 [ Failure Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webvtt/api/VTTCue/constructor.html [ Failure Timeout ]
@@ -3560,14 +3527,12 @@
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/stream/tentative/backpressure-send.any.worker.html?wpt_flags=h2 [ Crash Failure ]
 crbug.com/626703 [ Mac11 ] external/wpt/websockets/stream/tentative/backpressure-send.any.html?wpt_flags=h2 [ Failure Skip Timeout ]
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/stream/tentative/backpressure-send.any.html?wpt_flags=h2 [ Failure Skip Timeout ]
-crbug.com/626703 [ Mac10.15 ] external/wpt/websockets/stream/tentative/backpressure-receive.any.html?wpt_flags=h2 [ Failure Pass ]
 crbug.com/626703 [ Mac ] external/wpt/websockets/bufferedAmount-unchanged-by-sync-xhr.any.worker.html?wpt_flags=h2 [ Failure Pass ]
 crbug.com/626703 [ Mac ] external/wpt/websockets/basic-auth.any.html?wpt_flags=h2 [ Failure Pass ]
 crbug.com/626703 [ Mac10.15 ] external/wpt/worklets/audio-worklet-credentials.https.html [ Crash Failure ]
 crbug.com/626703 [ Mac10.15 ] external/wpt/websockets/stream/tentative/constructor.any.html?wpt_flags=h2 [ Failure Timeout ]
 crbug.com/626703 [ Win ] external/wpt/websockets/stream/tentative/constructor.any.html?wpt_flags=h2 [ Failure Timeout ]
 crbug.com/626703 [ Win ] external/wpt/websockets/stream/tentative/backpressure-send.any.html?wpt_flags=h2 [ Failure Skip Timeout ]
-crbug.com/626703 [ Mac10.15 ] external/wpt/webrtc-encoded-transform/script-metadata-transform.https.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.15 ] external/wpt/fetch/api/basic/request-upload.any.serviceworker.html [ Crash Failure Timeout ]
 crbug.com/626703 [ Mac10.15 ] external/wpt/editing/other/editing-around-select-element.tentative.html?insertText [ Crash Failure Skip Timeout ]
 crbug.com/626703 [ Mac ] external/wpt/custom-elements/form-associated/ElementInternals-setFormValue.html [ Crash Pass Timeout ]
@@ -3576,14 +3541,11 @@
 crbug.com/626703 [ Mac10.15 ] external/wpt/fetch/api/basic/request-upload.any.sharedworker.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.15 ] external/wpt/mediacapture-image/MediaStreamTrack-getConstraints.https.html [ Crash Failure Timeout ]
 crbug.com/626703 [ Mac10.15 ] external/wpt/webvtt/api/VTTCue/constructor.html [ Crash Failure ]
-crbug.com/626703 [ Mac10.15 ] external/wpt/webrtc-encoded-transform/sframe-keys.https.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.15 ] external/wpt/dom/xslt/transformToFragment.tentative.window.html [ Crash Failure ]
-crbug.com/626703 external/wpt/webrtc-encoded-transform/script-transform.https.html [ Crash Failure Pass Timeout ]
 crbug.com/626703 [ Mac10.15 ] external/wpt/shadow-dom/accesskey.tentative.html [ Failure Timeout ]
 crbug.com/626703 [ Win10.20h2 ] external/wpt/websockets/stream/tentative/backpressure-send.any.sharedworker.html?wpt_flags=h2 [ Failure Skip Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/websockets/stream/tentative/backpressure-send.any.html?wpt_flags=h2 [ Failure Skip Timeout ]
 crbug.com/626703 [ Mac10.15 ] virtual/plz-dedicated-worker/external/wpt/html/cross-origin-embedder-policy/shared-workers.html [ Failure Timeout ]
-crbug.com/626703 [ Mac10.15 ] external/wpt/webrtc-encoded-transform/sframe-transform-buffer-source.html [ Crash Failure Timeout ]
 crbug.com/626703 external/wpt/websockets/stream/tentative/close.any.worker.html?wpt_flags=h2 [ Failure Timeout ]
 crbug.com/626703 virtual/plz-dedicated-worker/external/wpt/html/cross-origin-embedder-policy/multi-globals/workers-coep-report.https.html [ Failure Pass ]
 crbug.com/626703 [ Mac10.15 ] virtual/plz-dedicated-worker/external/wpt/fetch/api/basic/http-response-code.any.html [ Crash Failure ]
@@ -3799,8 +3761,6 @@
 crbug.com/626703 [ Linux ] external/wpt/websockets/Create-protocols-repeated-case-insensitive.any.worker.html?wpt_flags=h2 [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/websockets/Create-url-with-space.any.html [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/websockets/stream/tentative/abort.any.sharedworker.html?wpt_flags=h2 [ Failure ]
-crbug.com/626703 [ Linux ] external/wpt/websockets/stream/tentative/backpressure-receive.any.serviceworker.html?wpt_flags=h2 [ Failure ]
-crbug.com/626703 [ Linux ] external/wpt/websockets/stream/tentative/backpressure-receive.any.sharedworker.html?wpt_flags=h2 [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/websockets/stream/tentative/constructor.any.html?wpt_flags=h2 [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/websockets/stream/tentative/constructor.any.sharedworker.html?wpt_flags=h2 [ Failure ]
 crbug.com/626703 [ Linux ] virtual/plz-dedicated-worker/external/wpt/resource-timing/cross-origin-start-end-time-with-redirects.html [ Failure ]
@@ -3822,7 +3782,6 @@
 crbug.com/626703 [ Mac10.12 ] external/wpt/streams/idlharness.any.html [ Failure ]
 crbug.com/626703 [ Mac10.12 ] external/wpt/streams/idlharness.any.sharedworker.html [ Failure ]
 crbug.com/626703 [ Mac10.12 ] external/wpt/webhid/idlharness.https.window.html [ Failure ]
-crbug.com/626703 [ Mac10.12 ] external/wpt/webrtc-encoded-transform/idlharness.https.window.html [ Failure ]
 crbug.com/626703 [ Mac10.12 ] virtual/plz-dedicated-worker/external/wpt/service-workers/idlharness.https.any.sharedworker.html [ Failure ]
 crbug.com/626703 [ Mac10.12 ] virtual/plz-dedicated-worker/external/wpt/service-workers/idlharness.https.any.worker.html [ Failure ]
 crbug.com/626703 [ Mac10.12 ] virtual/portals/external/wpt/portals/idlharness.window.html [ Failure ]
@@ -5412,7 +5371,6 @@
 crbug.com/834302 external/wpt/permissions-policy/permissions-policy-opaque-origin.https.html [ Failure ]
 
 # Temporary suppression to allow devtools-frontend changes
-crbug.com/1029489 http/tests/devtools/elements/elements-linkify-attributes.js [ Failure Pass Skip Timeout ]
 crbug.com/1041830 http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile.js [ Failure Pass ]
 
 # Sheriff 2019-12-13
@@ -5791,9 +5749,6 @@
 # Sheriff 2020-06-03
 crbug.com/1007228 [ Mac ] external/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual.html [ Failure Pass ]
 
-# Disabled for landing DevTools change
-crbug.com/1011811 http/tests/devtools/persistence/automapping-sourcemap.js [ Failure Pass ]
-
 # Sheriff 2020-06-06
 crbug.com/1091843 fast/canvas/color-space/canvas-createImageBitmap-p3.html [ Failure Pass ]
 
@@ -6213,8 +6168,6 @@
 
 # Sheriff 2021-02-24
 crbug.com/1181667 [ Linux ] external/wpt/css/selectors/focus-visible-011.html [ Failure Pass ]
-crbug.com/1045052 [ Linux ] virtual/split-http-cache-not-site-per-process/http/tests/devtools/isolated-code-cache/stale-revalidation-test.js [ Failure Pass Skip Timeout ]
-crbug.com/1045052 [ Linux ] virtual/not-split-http-cache-not-site-per-process/http/tests/devtools/isolated-code-cache/stale-revalidation-test.js [ Failure Pass Skip Timeout ]
 crbug.com/1181857 external/wpt/webaudio/the-audio-api/the-analysernode-interface/test-analyser-output.html [ Failure Pass ]
 
 # Sheriff 2021-02-25
@@ -6496,12 +6449,10 @@
 css3/flexbox/perpendicular-writing-modes-inside-flex-item.html [ Failure ]
 
 # Sheriff 2021-05-18
-crbug.com/1210658 [ Mac10.14 ] virtual/jxl-enabled/images/jxl/jxl-images.html [ Failure ]
-crbug.com/1210658 [ Mac10.15 ] virtual/jxl-enabled/images/jxl/jxl-images.html [ Failure ]
-crbug.com/1210658 [ Win ] virtual/jxl-enabled/images/jxl/jxl-images.html [ Failure ]
-
-# Temporarily disabled to unblock https://crrev.com/c/3099011
-crbug.com/1199701 http/tests/devtools/console/console-big-array.js [ Skip ]
+crbug.com/1210658 [ Mac10.12 ] virtual/jxl-enabled/images/jxl/jxl-images.html [ Failure Pass ]
+crbug.com/1210658 [ Mac10.14 ] virtual/jxl-enabled/images/jxl/jxl-images.html [ Failure Pass ]
+crbug.com/1210658 [ Mac10.15 ] virtual/jxl-enabled/images/jxl/jxl-images.html [ Failure Pass ]
+crbug.com/1210658 [ Win ] virtual/jxl-enabled/images/jxl/jxl-images.html [ Failure Pass ]
 
 # Sheriff 2021-5-19
 # Flaky on Webkit Linux Leak
@@ -6624,7 +6575,6 @@
 crbug.com/1210687 [ Mac ] http/tests/permissions/chromium/test-request-worker.html [ Pass Skip Timeout ]
 crbug.com/1210687 [ Mac10.15 ] storage/websql/sql-error-codes.html [ Pass Skip Timeout ]
 crbug.com/1210687 [ Mac10.15 ] external/wpt/html/user-activation/propagation-crossorigin.sub.tentative.html [ Pass Skip Timeout ]
-crbug.com/1210687 [ Win ] virtual/split-http-cache-not-site-per-process/http/tests/devtools/isolated-code-cache/stale-revalidation-test.js [ Pass Skip Timeout ]
 crbug.com/1210687 [ Win ] virtual/shared_array_buffer_on_desktop/http/tests/devtools/a11y-axe-core/sources/scope-pane-a11y-test.js [ Pass Skip Timeout ]
 
 # Sheriff 2021-06-02
@@ -6742,7 +6692,7 @@
 
 
 # Sheriff 2021-07-13
-crbug.com/1220114 [ Linux ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-simulcast.https.html [ Failure Pass Timeout ]
+crbug.com/1220114 external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-simulcast.https.html [ Failure Pass Timeout ]
 crbug.com/1228959 [ Linux ] virtual/scroll-unification/fast/scroll-snap/snaps-after-wheel-scrolling-single-tick.html [ Failure Pass ]
 
 # A number of http/tests/inspector-protocol/network tests are flaky.
@@ -6918,12 +6868,6 @@
 crbug.com/1233766 [ Mac ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-local-time-before-start.https.html [ Crash Failure Pass ]
 crbug.com/1233766 [ Mac ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-get-timing-on-worklet-thread.https.html [ Crash Failure Pass ]
 
-# Temporarily disable to fix DevTools issue reporting
-crbug.com/1241860 http/tests/inspector-protocol/issues/content-security-policy-issue-trusted-types-exception.js [ Skip ]
-crbug.com/1241860 http/tests/inspector-protocol/issues/content-security-policy-issue-trusted-types-policy-exception.js [ Skip ]
-crbug.com/1241860 http/tests/inspector-protocol/issues/cors-issues.js [ Skip ]
-crbug.com/1241860 http/tests/inspector-protocol/issues/renderer-cors-issues.js [ Skip ]
-
 # [CompositeClipPathAnimations] failing test
 crbug.com/1249071 virtual/composite-clip-path-animation/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-filter.html [ Crash Failure Pass ]
 
@@ -6977,9 +6921,6 @@
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/dom/xslt/transformToFragment.tentative.window.html [ Failure ]
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/webvtt/api/VTTCue/constructor.html [ Failure ]
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/content-security-policy/securitypolicyviolation/source-file-data-scheme.html [ Failure ]
-crbug.com/1249176 [ Mac11-arm64 ] external/wpt/webrtc-encoded-transform/script-metadata-transform.https.html [ Failure ]
-crbug.com/1249176 [ Mac11-arm64 ] external/wpt/webrtc-encoded-transform/sframe-keys.https.html [ Failure ]
-crbug.com/1249176 [ Mac11-arm64 ] external/wpt/webrtc-encoded-transform/script-write-twice-transform.https.html [ Failure ]
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/selection/textcontrols/selectionchange.tentative.html [ Failure ]
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/websockets/constructor/002_wss.html [ Failure ]
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/websockets/basic-auth.any.worker_wpt_flags=h2.html [ Failure ]
@@ -6990,7 +6931,6 @@
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/websockets/Create-protocols-repeated-case-insensitive.any_wss.html [ Failure ]
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/websockets/unload-a-document/002_wss.html [ Failure ]
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/websockets/stream/tentative/backpressure-send.any_wpt_flags=h2.html [ Failure ]
-crbug.com/1249176 [ Mac11-arm64 ] external/wpt/websockets/stream/tentative/backpressure-send.any.serviceworker_wpt_flags=h2.html [ Failure ]
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/websockets/stream/tentative/backpressure-send.any.worker_wpt_flags=h2.html [ Failure ]
 crbug.com/1249176 [ Mac11-arm64 ] fast/forms/color/color-picker-escape-cancellation-revert.html [ Failure ]
 crbug.com/1249176 [ Mac11-arm64 ] fast/css/focus-display-block-inline.html [ Failure ]
@@ -7000,14 +6940,12 @@
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/focus/focus-already-focused-iframe-deep-same-site.html [ Timeout ]
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/focus/focus-already-focused-iframe-different-site.html [ Timeout ]
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/focus/focus-already-focused-iframe-same-site.html [ Timeout ]
-crbug.com/1249176 [ Mac11-arm64 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-mouseup.html [ Failure Timeout ]
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/selection/textcontrols/selectionchange-bubble.html [ Timeout ]
 crbug.com/1249176 [ Mac11-arm64 ] http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js [ Failure Skip Timeout ]
 
 # Flaky tests in mac11-arm64
 crbug.com/1249176 [ Mac11-arm64 ] transforms/3d/general/cssmatrix-3d-zoom.html [ Failure Pass ]
 crbug.com/1249176 [ Mac11-arm64 ] http/tests/images/document-policy-lossy-images-max-bpp.php [ Failure Pass Timeout ]
-crbug.com/1249176 [ Mac11-arm64 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-simulcast.https.html [ Pass Timeout ]
 crbug.com/1249176 [ Mac11-arm64 ] fast/forms/plaintext-mode-2.html [ Failure Pass ]
 crbug.com/1249176 [ Mac11-arm64 ] virtual/gpu-rasterization/images/color-profile-image-canvas.html [ Failure Pass ]
 crbug.com/1249176 [ Mac11-arm64 ] virtual/gpu-rasterization/images/jpeg-with-color-profile.html [ Failure Pass ]
@@ -7034,7 +6972,6 @@
 crbug.com/1249176 [ Mac11-arm64 ] virtual/scroll-unification/plugins/multiple-plugins.html [ Failure Pass ]
 crbug.com/1249176 [ Mac11-arm64 ] virtual/gpu-rasterization/images/color-profile-animate.html [ Failure Pass ]
 crbug.com/1249176 [ Mac11-arm64 ] fast/layers/clip-rects-transformed-2.html [ Failure Pass ]
-crbug.com/1249176 [ Mac11-arm64 ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/location-setter-user-click.html [ Failure Timeout ]
 crbug.com/1249176 [ Mac11-arm64 ] inspector-protocol/timeline/page-frames.js [ Failure Pass ]
 crbug.com/1249176 [ Mac11-arm64 ] inspector-protocol/timeline/user-timing.js [ Failure Pass ]
 crbug.com/1249176 [ Mac11-arm64 ] http/tests/devtools/tracing/frame-model-instrumentation.js [ Failure Pass ]
@@ -7135,7 +7072,6 @@
 crbug.com/1249176 [ Mac11-arm64 ] virtual/not-site-per-process/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-no-1-no-same-2-yes-port.sub.https.html [ Crash Pass ]
 
 # Sheriff 2021-09-16
-crbug.com/1250457 [ Win7 ] http/tests/devtools/sources/debugger-ui/script-formatter-breakpoints-3.js [ Failure ]
 crbug.com/1250457 [ Mac ] virtual/scroll-unification/plugins/plugin-map-data-to-src.html [ Failure ]
 crbug.com/1250457 [ Mac ] storage/websql/open-database-set-empty-version.html [ Timeout ]
 crbug.com/1250457 [ Mac ] virtual/not-site-per-process/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-no-child-yes-same.sub.https.html [ Timeout ]
@@ -7210,10 +7146,6 @@
 # Sheriff 2021-10-04
 crbug.com/1226112 [ Win ] http/tests/text-autosizing/wide-iframe.html [ Pass Timeout ]
 
-# DevTools roll
-crbug.com/1222126 http/tests/devtools/cache-storage/cache-live-update-list.js [ Skip ]
-crbug.com/1215072 http/tests/devtools/elements/copy-styles.js [ Skip ]
-
 # Skip devtools test hitting an unexpected tracing infrastructure exception 2021-10-04
 crbug.com/1255679 http/tests/devtools/service-workers/service-workers-wasm-test.js [ Skip ]
 
@@ -7298,10 +7230,6 @@
 # Sheriff 2021-11-02
 crbug.com/1265924 [ Fuchsia ] synthetic_gestures/smooth-scroll-tiny-delta.html [ Failure Pass ]
 
-# V8 roll
-crbug.com/1257806 http/tests/devtools/console/console-external-array.js [ Skip ]
-crbug.com/1257806 http/tests/devtools/console/console-log-side-effects.js [ Skip ]
-
 # TODO(https://crbug.com/1265311): Make the test behave the same way on all platforms
 crbug.com/1265311 http/tests/navigation/location-change-repeated-from-blank.html [ Failure Pass ]
 
@@ -7319,7 +7247,7 @@
 # Sheriff 2021-11-09
 crbug.com/1268518 [ Linux ] external/wpt/web-animations/interfaces/Animation/onfinish.html [ Failure Pass ]
 crbug.com/1268518 [ Mac10.12 ] external/wpt/web-animations/interfaces/Animation/onfinish.html [ Failure Pass ]
-crbug.com/1268519 [ Win10.20h2 ] virtual/scroll-unification/http/tests/misc/resource-timing-sizes-multipart.html [ Failure Pass ]
+crbug.com/1269535 http/tests/misc/resource-timing-sizes-multipart.html [ Failure Pass ]
 crbug.com/1267734 [ Win7 ] virtual/scroll-unification/fast/forms/suggestion-picker/week-suggestion-picker-appearance.html [ Failure Pass ]
 
 # This test is flaky on all platforms
@@ -7333,13 +7261,6 @@
 crbug.com/1268594 [ Mac ] css3/filters/composited-layer-bounds-after-sw-blur-animation.html [ Failure Pass ]
 crbug.com/1268594 [ Win ] css3/filters/composited-layer-bounds-after-sw-blur-animation.html [ Failure Pass ]
 
-# Temporarily disable to update DevTools Application Panel
-crbug.com/1271044 http/tests/devtools/application-panel/resources-panel-iframe-idb.js [ Failure Pass ]
-crbug.com/1271044 http/tests/devtools/application-panel/resources-panel-on-navigation.js [ Failure Pass ]
-crbug.com/1271044 http/tests/devtools/application-panel/resources-panel-resource-preview.js [ Failure Pass ]
-crbug.com/1271044 http/tests/devtools/application-panel/resources-panel-selection-on-reload.js [ Failure Pass ]
-crbug.com/1271044 http/tests/devtools/application-panel/resources-panel-websql.js [ Failure Pass ]
-
 # Security OWP fixit week
 crbug.com/1270355 external/wpt/html/browsers/browsing-the-web/navigating-across-documents/009.html [ Timeout ]
 
@@ -7347,4 +7268,22 @@
 crbug.com/1180993 external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Failure Pass Timeout ]
 
 # Sheriff 2021-11-19
+crbug.com/1186771 [ Mac ] fast/scroll-snap/snaps-after-scrollbar-scrolling-track.html [ Crash ]
+crbug.com/1227911 [ Mac ] external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-no-child1-no-subdomain1-child2-yes-subdomain2.sub.https.html [ Failure Pass ]
+crbug.com/1227911 [ Linux ] external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-no-child1-no-subdomain1-child2-yes-subdomain2.sub.https.html [ Failure Pass ]
+crbug.com/894077 [ Linux ] virtual/android/fullscreen/video-fixed-background.html [ Pass Failure ]
+crbug.com/1271336 external/wpt/native-io/detach_iframe_during_open.https.window.html [ Crash Pass ]
 crbug.com/1197465 virtual/scroll-unification/fast/events/mouse-cursor-no-mousemove.html [ Skip ]
+crbug.com/1272017 [ Mac11-arm64 ] virtual/shared_array_buffer_on_desktop/http/tests/devtools/sources/debugger-ui/reveal-not-skipped.js [ Skip ]
+crbug.com/1272058 [ Linux ] fast/animation/request-animation-frame-cancel2.html [ Failure Pass ]
+crbug.com/1272058 [ Linux ] fast/animation/request-animation-frame-cancel.html [ Failure Pass ]
+
+# Sheriff 2021-11-22
+crbug.com/1272352 virtual/threaded/http/tests/devtools/isolated-code-cache/same-origin-test.js [ Pass Crash ]
+crbug.com/1272352 virtual/threaded/http/tests/devtools/isolated-code-cache/stale-revalidation-test.js [ Pass Crash ]
+crbug.com/1272376 virtual/scroll-unification/plugins/plugin-document-back-forward.html [ Failure Pass ]
+crbug.com/1272380 http/tests/devtools/bindings/bindings-multiple-frames.js [ Failure Pass ]
+
+# Flaky on Mac and Windows
+crbug.com/1272199 external/wpt/websockets/stream/tentative/backpressure-receive.any.serviceworker.html?wpt_flags=h2 [ Failure Pass ]
+crbug.com/1272203 external/wpt/websockets/stream/tentative/backpressure-send.any.serviceworker.html?wpt_flags=h2 [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index a99a9ea..5bb44a2 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -37,6 +37,7 @@
               "external/wpt/web-animations/timing-model/animations",
               "fast/events/pointerevents/pinch",
               "lifecycle",
+              "http/tests/devtools/isolated-code-cache",
               "http/tests/devtools/tracing",
               "http/tests/worklet",
               "printing",
@@ -99,8 +100,7 @@
     "prefix": "v8-off-thread-finalization",
     "bases": [
       "external/wpt/html/semantics/scripting-1",
-      "fast/dom",
-      "http/tests/devtools/isolated-code-cache/"
+      "fast/dom"
     ],
     "args": ["--enable-features=V8OffThreadFinalization,SmallScriptStreaming,SharedArrayBuffer"]
   },
@@ -507,14 +507,6 @@
     "args": ["--enable-blink-features=ExtraWebGLVideoTextureMetadata"]
   },
   {
-    "prefix": "cache-code-on-idle",
-    "bases": [
-      "http/tests/devtools/isolated-code-cache",
-      "http/tests/devtools/resources"
-    ],
-    "args": ["--enable-features=CacheCodeOnIdle"]
-  },
-  {
     "prefix": "wasm-site-isolated-code-cache",
     "bases": ["http/tests/devtools/wasm-isolated-code-cache"],
     "args": ["--disable-features=WebAssemblyBaseline",
@@ -540,13 +532,15 @@
     "prefix": "split-http-cache-not-site-per-process",
     "bases": ["http/tests/devtools/isolated-code-cache"],
     "args": ["--enable-features=SplitCacheByNetworkIsolationKey",
-             "--disable-site-isolation-trials"]
+             "--disable-site-isolation-trials",
+             "--enable-threaded-compositing"]
   },
   {
     "prefix": "not-split-http-cache-not-site-per-process",
     "bases": ["http/tests/devtools/isolated-code-cache"],
     "args": ["--disable-features=SplitCacheByNetworkIsolationKey",
-             "--disable-site-isolation-trials"]
+             "--disable-site-isolation-trials",
+             "--enable-threaded-compositing"]
   },
   {
     "prefix": "not-site-per-process",
diff --git a/third_party/blink/web_tests/W3CImportExpectations b/third_party/blink/web_tests/W3CImportExpectations
index 78462aa..17c2825 100644
--- a/third_party/blink/web_tests/W3CImportExpectations
+++ b/third_party/blink/web_tests/W3CImportExpectations
@@ -439,7 +439,6 @@
 external/wpt/streams/idlharness.any.html [ Skip ]
 external/wpt/streams/idlharness.any.sharedworker.html [ Skip ]
 external/wpt/webhid/idlharness.https.window.html [ Skip ]
-external/wpt/webrtc-encoded-transform/idlharness.https.window.html [ Skip ]
 external/wpt/webtransport/idlharness.any.html [ Skip ]
 external/wpt/webtransport/idlharness.any.sharedworker.html [ Skip ]
 external/wpt/webtransport/idlharness.any.worker.html [ Skip ]
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open-reload.https.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open-reload.https.html
index b2046ff7..32076c7 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open-reload.https.html
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open-reload.https.html
@@ -17,7 +17,7 @@
       return resetSameSiteCookies(origin, value)
         .then(_ => {
           return new Promise((resolve, reject) => {
-            var w = window.open(origin + "/cookies/resources/postToParent.py");
+            var w = window.open(target + "/cookies/resources/postToParent.py");
 
             var reloaded = false;
             var msgHandler = e => {
@@ -48,5 +48,5 @@
   // The reload status is always strictly same-site because this is a site-initiated reload, as opposed to a reload triggered by a user interface element.
   create_test(SECURE_ORIGIN, SECURE_ORIGIN, SameSiteStatus.STRICT, SameSiteStatus.STRICT, "Reloaded same-host auxiliary navigations are strictly same-site.");
   create_test(SECURE_SUBDOMAIN_ORIGIN, SECURE_SUBDOMAIN_ORIGIN, SameSiteStatus.STRICT, SameSiteStatus.STRICT, "Reloaded subdomain auxiliary navigations are strictly same-site.");
-  create_test(SECURE_CROSS_SITE_ORIGIN, SECURE_CROSS_SITE_ORIGIN, SameSiteStatus.LAX, SameSiteStatus.STRICT, "Reloaded cross-site auxiliary navigations are laxly same-site");
+  create_test(SECURE_CROSS_SITE_ORIGIN, SECURE_CROSS_SITE_ORIGIN, SameSiteStatus.LAX, SameSiteStatus.STRICT, "Reloaded cross-site auxiliary navigations are strictly same-site");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open.https.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open.https.html
index b460e1a..be42250 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open.https.html
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open.https.html
@@ -11,7 +11,7 @@
       return resetSameSiteCookies(origin, value)
         .then(_ => {
           return new Promise((resolve, reject) => {
-            var w = window.open(origin + "/cookies/resources/postToParent.py");
+            var w = window.open(target + "/cookies/resources/postToParent.py");
 
             var msgHandler = e => {
               window.removeEventListener("message", msgHandler);
@@ -40,12 +40,12 @@
   // Redirect from {same-host,subdomain,cross-site} to same-host:
   create_test(SECURE_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Same-host redirecting to same-host auxiliary navigations are strictly same-site");
   create_test(SECURE_ORIGIN, redirectTo(SECURE_SUBDOMAIN_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Subdomain redirecting to same-host auxiliary navigations are strictly same-site");
-  create_test(SECURE_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Cross-site redirecting to same-host auxiliary navigations are strictly same-site");
+  create_test(SECURE_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.LAX, "Cross-site redirecting to same-host auxiliary navigations are laxly same-site");
 
   // Redirect from {same-host,subdomain,cross-site} to same-host:
   create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Same-host redirecting to subdomain auxiliary navigations are strictly same-site");
   create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_SUBDOMAIN_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Subdomain redirecting to subdomain auxiliary navigations are strictly same-site");
-  create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Cross-site redirecting to subdomain auxiliary navigations are strictly same-site");
+  create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.LAX, "Cross-site redirecting to subdomain auxiliary navigations are laxly same-site");
 
   // Redirect from {same-host,subdomain,cross-site} to cross-site:
   create_test(SECURE_CROSS_SITE_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_CROSS_SITE_ORIGIN), SameSiteStatus.LAX, "Same-host redirecting to cross-site auxiliary navigations are laxly same-site");
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_status_checking-manual.html b/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_status_checking-manual.html
new file mode 100644
index 0000000..a4a3b41
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_status_checking-manual.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html manifest="../resources/manifest/clock.manifest">
+  <head>
+    <title>Offline Application Cache - API_status_CHECKING</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <ol>
+      <li>Refresh the page.</li>
+    </ol>
+
+    <div id="log"></div>
+    <script>
+      var t = async_test("checking status test"),
+          cache = window.applicationCache;
+
+      cache.onchecking = t.step_func_done(function() {
+        assert_equals(cache.status, cache.CHECKING, "cache.status should equals cache.CHECKING");
+      });
+    </script>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_status_downloading-manual.html b/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_status_downloading-manual.html
new file mode 100644
index 0000000..c09d11d7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_status_downloading-manual.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html manifest="../resources/manifest/clock.manifest">
+  <head>
+    <title>Offline Application Cache - API_status_DOWNLOADING</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <ol>
+      <li>Modify the commented part in the manifest file (manifest/clock.manifest) on the server.</li>
+      <li>Refresh the page.</li>
+    </ol>
+    <div id="log"></div>
+
+    <script>
+      var t = async_test("downloading status test"),
+          cache = window.applicationCache;
+
+      cache.ondownloading = t.step_func_done(function() {
+        assert_equals(cache.status, cache.DOWNLOADING, "cache.status should equals cache.DOWNLOADING");
+      });
+    </script>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_status_obsolete-manual.html b/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_status_obsolete-manual.html
new file mode 100644
index 0000000..7700564
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_status_obsolete-manual.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html manifest="../resources/manifest/clock.manifest">
+  <head>
+    <title>Offline Application Cache - API_status_OBSOLETE</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <ol>
+      <li>Remove the manifest file (manifest/clock.manifest) from the server.</li>
+      <li>Refresh the page.</li>
+    </ol>
+    <div id="log"></div>
+
+    <script>
+      var t = async_test("obsolete status test"),
+          cache = window.applicationCache;
+
+      cache.onobsolete = t.step_func_done(function() {
+        assert_equals(cache.status, cache.OBSOLETE, "cache.status should equals cache.OBSOLETE");
+      });
+    </script>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_status_updateready-manual.html b/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_status_updateready-manual.html
new file mode 100644
index 0000000..7e15333
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_status_updateready-manual.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html manifest="../resources/manifest/clock.manifest">
+  <head>
+    <title>Offline Application Cache - API_status_UPDATEREADY</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <ol>
+      <li>Modify the commented part in the manifest file (manifest/clock.manifest) on the server.</li>
+      <li>Refresh the page.</li>
+    </ol>
+
+    <div id="log"></div>
+
+    <script>
+      var t = async_test("updateready status test"),
+          cache = window.applicationCache;
+
+      cache.onupdateready = t.step_func_done(function() {
+        assert_equals(cache.status, cache.UPDATEREADY, "cache.status should equals cache.UPDATEREADY");
+      });
+    </script>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_swapcache-manual.html b/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_swapcache-manual.html
new file mode 100644
index 0000000..6649d98
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/offline/application-cache-api/api_swapcache-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html manifest="../resources/manifest/clock.manifest">
+  <head>
+    <title>Offline Application Cache - API_swapCache</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <ol>
+      <li>Modify the part of comment in manifest file of server.</li>
+      <li>Refresh the page.</li>
+    </ol>
+
+    <div id="log"></div>
+
+    <script>
+      var t = async_test("swapCache method test");
+      var cache = window.applicationCache;
+
+      cache.onupdateready = t.step_func(function() {
+        try {
+          cache.swapCache();
+          t.done();
+        } catch (e) {
+          assert_unreached("swapCache method failed.");
+        }
+      });
+    </script>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-is-popup-condition_combination-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-is-popup-condition_combination-expected.txt
deleted file mode 100644
index cc108eb..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-is-popup-condition_combination-expected.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-This is a testharness.js-based test.
-PASS "location,toolbar,menubar,resizable,scrollbars,status" should set BarProp visibility to true
-PASS "location,menubar,resizable,scrollbars,status" should set BarProp visibility to true
-PASS "toolbar,menubar,resizable,scrollbars,status" should set BarProp visibility to true
-FAIL "resizable,scrollbars,status" should set BarProp visibility to false assert_equals: window.scrollbars.visible expected false but got true
-FAIL "location=no,menubar=no,resizable,scrollbars,status" should set BarProp visibility to false assert_equals: window.scrollbars.visible expected false but got true
-FAIL "location,toolbar,resizable,scrollbars,status" should set BarProp visibility to false assert_equals: window.locationbar.visible expected false but got true
-PASS "location,toolbar,menubar,scrollbars,status" should set BarProp visibility to true
-FAIL "location,toolbar,menubar,resizable=no,scrollbars,status" should set BarProp visibility to false assert_equals: window.locationbar.visible expected false but got true
-FAIL "location,toolbar,menubar,resizable,status" should set BarProp visibility to false assert_equals: window.locationbar.visible expected false but got true
-FAIL "location,toolbar,menubar,resizable,scrollbars" should set BarProp visibility to false assert_equals: window.locationbar.visible expected false but got true
-FAIL "popup=1,location,toolbar,menubar,resizable,scrollbars,status" should set BarProp visibility to false assert_equals: window.locationbar.visible expected false but got true
-FAIL "popup=0,location,toolbar,menubar,resizable,scrollbars" should set BarProp visibility to true assert_equals: window.statusbar.visible expected true but got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-is-popup-condition_single-1-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-is-popup-condition_single-1-expected.txt
deleted file mode 100644
index 06fc00c..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-is-popup-condition_single-1-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-This is a testharness.js-based test.
-PASS undefined should set BarProp visibility to true
-PASS "popup" should set BarProp visibility to false
-PASS "popup=1" should set BarProp visibility to false
-FAIL "popup=0" should set BarProp visibility to true assert_equals: window.locationbar.visible expected true but got false
-FAIL "location" should set BarProp visibility to false assert_equals: window.locationbar.visible expected false but got true
-FAIL "location=yes" should set BarProp visibility to false assert_equals: window.locationbar.visible expected false but got true
-PASS "location=no" should set BarProp visibility to false
-FAIL "toolbar" should set BarProp visibility to false assert_equals: window.locationbar.visible expected false but got true
-FAIL "toolbar=yes" should set BarProp visibility to false assert_equals: window.locationbar.visible expected false but got true
-PASS "toolbar=no" should set BarProp visibility to false
-FAIL "menubar" should set BarProp visibility to false assert_equals: window.menubar.visible expected false but got true
-FAIL "menubar=yes" should set BarProp visibility to false assert_equals: window.menubar.visible expected false but got true
-PASS "menubar=no" should set BarProp visibility to false
-PASS "resizable" should set BarProp visibility to false
-PASS "resizable=yes" should set BarProp visibility to false
-PASS "resizable=no" should set BarProp visibility to false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-is-popup-condition_single-2-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-is-popup-condition_single-2-expected.txt
deleted file mode 100644
index 8ead92f..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-is-popup-condition_single-2-expected.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-This is a testharness.js-based test.
-FAIL "scrollbars" should set BarProp visibility to false assert_equals: window.scrollbars.visible expected false but got true
-FAIL "scrollbars=yes" should set BarProp visibility to false assert_equals: window.scrollbars.visible expected false but got true
-PASS "scrollbars=no" should set BarProp visibility to false
-FAIL "status" should set BarProp visibility to false assert_equals: window.statusbar.visible expected false but got true
-FAIL "status=yes" should set BarProp visibility to false assert_equals: window.statusbar.visible expected false but got true
-PASS "status=no" should set BarProp visibility to false
-PASS "titlebar" should set BarProp visibility to false
-PASS "titlebar=yes" should set BarProp visibility to false
-PASS "titlebar=no" should set BarProp visibility to false
-PASS "close" should set BarProp visibility to false
-PASS "close=yes" should set BarProp visibility to false
-PASS "close=no" should set BarProp visibility to false
-PASS "minimizable" should set BarProp visibility to false
-PASS "minimizable=yes" should set BarProp visibility to false
-PASS "minimizable=no" should set BarProp visibility to false
-PASS "personalbar" should set BarProp visibility to false
-PASS "personalbar=yes" should set BarProp visibility to false
-PASS "personalbar=no" should set BarProp visibility to false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/support/window-open-popup-target.html b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/support/window-open-popup-target.html
new file mode 100644
index 0000000..a0588de829
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/support/window-open-popup-target.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<script>
+  var channelName = window.name;
+  var channel = new BroadcastChannel(channelName);
+  const allBarProps = [
+    window.locationbar.visible,
+    window.menubar.visible,
+    window.personalbar.visible,
+    window.scrollbars.visible,
+    window.statusbar.visible,
+    window.toolbar.visible
+  ];
+  const allTrue = allBarProps.every(x=>x);
+  const allFalse = allBarProps.every(x=>!x);
+  channel.postMessage({isPopup: allFalse, mixedState: !allTrue && !allFalse});
+
+  // Because messages are not delivered synchronously and because closing a
+  // browsing context prompts the eventual clearing of all task sources, this
+  // document should not be closed until the opener document has confirmed
+  // receipt.
+  channel.onmessage = function() {
+    window.close();
+  };
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/window-open-popup-behavior.html b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/window-open-popup-behavior.html
new file mode 100644
index 0000000..258698d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/window-open-popup-behavior.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>Window.open popup behavior</title>
+<link rel="author" href="masonf@chromium.org">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/window-object.html#window-open-steps">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+function testOne(windowFeatures, expectPopup) {
+  const windowName = Math.round(Math.random()*1e12);
+  const channel = new BroadcastChannel(windowName);
+  var w;
+  promise_test(() => {
+    return new Promise(resolve => {
+      w = window.open("support/window-open-popup-target.html", windowName, windowFeatures);
+      channel.addEventListener('message', resolve);
+    }).then(e => {
+      // Send message first so if asserts throw the popup is still closed
+      channel.postMessage(null);
+      assert_false(e.data.mixedState, "No mixed state");
+      assert_equals(e.data.isPopup, expectPopup, "Popup state");
+    });
+  },`${windowFeatures} (expect ${expectPopup ? "popup" : "tab"})`);
+}
+
+// No windowpreferences at all - tab.
+testOne(undefined, /*expectPopup=*/false);
+
+// Test all permutations of these properties:
+const features = ["location","toolbar","menubar","resizable","scrollbars","status"];
+const nProps = features.length;
+const skip = 7; // To speed up the test, don't test all values. Skip 7 to pseudo-randomize.
+for(let i=0;i<2**nProps;i+=skip) {
+  const enableVec = Number(i).toString(2).padStart(nProps,'0').split('').map(s => (s==="1"));
+  let windowFeatures = [];
+  for(let i=0;i<nProps;++i) {
+    if (enableVec[i])
+      windowFeatures.push(features[i] + "=yes");
+  }
+  windowFeatures = windowFeatures.join(',');
+  // We get a popup we got windowFeatures, and any of them are false:
+  const expectPopup = !!windowFeatures.length && (!(enableVec[0] || enableVec[1]) || !enableVec[2] || !enableVec[3] || !enableVec[4] || !enableVec[5]);
+  testOne(windowFeatures, expectPopup);
+  testOne(windowFeatures + ",noopener", /*expectPopup=*/false);
+  testOne(windowFeatures + ",noreferrer", /*expectPopup=*/false);
+  testOne(windowFeatures + ",popup", /*expectPopup=*/true); // "popup" feature = popup
+  testOne(windowFeatures + ",noopener,noreferrer,popup", /*expectPopup=*/false);
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/svg-style-animate-crash.html b/third_party/blink/web_tests/external/wpt/svg/animations/svg-style-animate-crash.html
new file mode 100644
index 0000000..0ed2140
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/animations/svg-style-animate-crash.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>Starting a CSS Animation and Web Animation at the same time on SVG style elements</title>
+<link rel="help" href="https://crbug.com/1264236">
+<style>
+  @keyframes anim {
+    from { color: green; }
+    to { color: red; }
+  }
+
+  #target {
+    animation: anim 1s linear;
+  }
+</style>
+<svg>
+  <style id=target>Test</style>
+</svg>
+<script>
+  addEventListener('load', () => {
+    target.animate({'top': ['0px', '10px']}, 1000);
+    target.offsetTop;
+  });
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/text/reftests/transform-dynamic-change-ref.html b/third_party/blink/web_tests/external/wpt/svg/text/reftests/transform-dynamic-change-ref.html
index c7e238d..cdcad92 100644
--- a/third_party/blink/web_tests/external/wpt/svg/text/reftests/transform-dynamic-change-ref.html
+++ b/third_party/blink/web_tests/external/wpt/svg/text/reftests/transform-dynamic-change-ref.html
@@ -7,5 +7,9 @@
     <text fill="red" style="font-size: 40px;" transform="matrix(1, 0, 0, 1, 468, 988)">A</text>
   </svg>
 </div>
+
+<svg width="500" height="400" style="transform-origin: 0px 0px; transform: scale(2) translate(-300px, -300px);">
+  <text x="300" y="350" font-size="50" fill="green">PASS</text>
+</svg>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/svg/text/reftests/transform-dynamic-change.html b/third_party/blink/web_tests/external/wpt/svg/text/reftests/transform-dynamic-change.html
index 964a7d31..abd05cc 100644
--- a/third_party/blink/web_tests/external/wpt/svg/text/reftests/transform-dynamic-change.html
+++ b/third_party/blink/web_tests/external/wpt/svg/text/reftests/transform-dynamic-change.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html class="reftest-wait">
 <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1270713">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1271931">
 <link rel="match" href="transform-dynamic-change-ref.html">
 <body>
 
@@ -11,11 +12,18 @@
   </svg>
 </div>
 
+<svg id="svg2" width="500" height="400" style="transform-origin: 0px 0px; transform: translate(-300px, -300px);">
+  <text x="300" y="350" id="text2" font-size="50">PASS</text>
+</svg>
+
 <script>
 requestAnimationFrame(() => {
   requestAnimationFrame(() => {
     document.getElementById('moveme').style.transform = 'matrix(0.9, 0, 0, 0.9, -210, -777)';
     document.getElementById('txt').style.fill = 'red';
+
+    document.getElementById('svg2').style.transform = 'scale(2) translate(-300px, -300px)';
+    document.getElementById('text2').style.fill = 'green';
     document.documentElement.classList.remove('reftest-wait');
   });
 });
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/external/wpt/webrtc-encoded-transform/script-metadata-transform.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/script-metadata-transform.https-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-mac10.15/external/wpt/webrtc-encoded-transform/script-metadata-transform.https-expected.txt
rename to third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/script-metadata-transform.https-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/script-transform.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/script-transform.https-expected.txt
new file mode 100644
index 0000000..a1cc087
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/script-transform.https-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+FAIL transform messaging promise_test: Unhandled rejection with value: object "ReferenceError: RTCRtpScriptTransform is not defined"
+FAIL Cannot reuse attached transforms promise_test: Unhandled rejection with value: object "ReferenceError: RTCRtpScriptTransform is not defined"
+FAIL audio exchange with transform promise_test: Unhandled rejection with value: object "ReferenceError: RTCRtpScriptTransform is not defined"
+FAIL video exchange with transform promise_test: Unhandled rejection with value: object "ReferenceError: RTCRtpScriptTransform is not defined"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/external/wpt/webrtc-encoded-transform/script-write-twice-transform.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/script-write-twice-transform.https-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-mac10.15/external/wpt/webrtc-encoded-transform/script-write-twice-transform.https-expected.txt
rename to third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/script-write-twice-transform.https-expected.txt
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/external/wpt/webrtc-encoded-transform/sframe-keys.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/sframe-keys.https-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/mac-mac10.15/external/wpt/webrtc-encoded-transform/sframe-keys.https-expected.txt
rename to third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/sframe-keys.https-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/protocol/sdes-dont-dont-dont-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/protocol/sdes-dont-dont-dont-expected.txt
new file mode 100644
index 0000000..efdc199b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/protocol/sdes-dont-dont-dont-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL does not create offers with SDES assert_false: expected false got true
+PASS rejects a remote offer that only includes SDES and no DTLS fingerprint
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/fast/dom/Window/new-window-opener.html b/third_party/blink/web_tests/fast/dom/Window/new-window-opener.html
deleted file mode 100644
index 645fbd5..0000000
--- a/third_party/blink/web_tests/fast/dom/Window/new-window-opener.html
+++ /dev/null
@@ -1,119 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-    <title>New Window Opener Test</title>
-    <script src="../../../resources/js-test.js"></script>
-</head>
-
-<body>
-
-    <script type="text/javascript">
-        if (window.testRunner) {
-            testRunner.dumpAsText();
-            testRunner.waitUntilDone();
-            testRunner.setPopupBlockingEnabled(false);
-        }
-
-    
-        description(
-            'This tests that the different arguments given to a new window are honored.<br/>\
-            Take note that menubar is special and always on in Mac but not in Win.'
-        );
-
-        var args = [ "scrollbars=yes,width=75,height=100"
-                   , "scrollbars=no,width=75,height=100"
-                   , "scrollbars=1,width=75,height=100"
-                   , "scrollbars=0,width=75,height=100"
-                   , "toolbar=yes,width=75,height=100"
-                   , "toolbar=no,width=75,height=100"
-                   , "toolbar=1,width=75,height=100"
-                   , "toolbar=0,width=75,height=100"
-                   , "status=yes,width=75,height=100"
-                   , "status=no,width=75,height=100"
-                   , "status=1,width=75,height=100"
-                   , "status=0,width=75,height=100"
-                   , "menubar=yes,width=75,height=100"
-                   , "menubar=no,width=75,height=100"
-                   , "menubar=1,width=75,height=100"
-                   , "menubar=0,width=75,height=100"
-                   , "location=yes,width=75,height=100"
-                   , "location=no,width=75,height=100"
-                   , "location=1,width=75,height=100"
-                   , "location=0,width=75,height=100"
-                   ];
-
-        var actual = [ "newWin.scrollbars.visible", "newWin.scrollbars.visible", "newWin.scrollbars.visible", "newWin.scrollbars.visible"
-                     , "newWin.toolbar.visible", "newWin.toolbar.visible", "newWin.toolbar.visible", "newWin.toolbar.visible"
-                     , "newWin.statusbar.visible", "newWin.statusbar.visible", "newWin.statusbar.visible", "newWin.statusbar.visible"
-                     , "newWin.menubar.visible", "newWin.menubar.visible", "newWin.menubar.visible", "newWin.menubar.visible"
-                     , "newWin.locationbar.visible", "newWin.locationbar.visible", "newWin.locationbar.visible", "newWin.locationbar.visible"
-                     ];
-
-        var expected = [ "true", "false", "true", "false"
-                       , "true", "false", "true", "false"
-                       , "true", "false", "true", "false"
-                       , "true", "isMenubarAlwaysExpected", "true", "isMenubarAlwaysExpected"
-                       , "true", "false", "true", "false"
-                       ];
-
-        // Since Mac always shows the menu bar we need to special case it, but in
-        // a way that does not require platform specific results.
-        var isMacOSX = navigator.userAgent.indexOf("Mac OS X");
-        var isMenubarAlwaysExpected;
-        if (isMacOSX != -1)
-            isMenubarAlwaysExpected = true;
-        else
-            isMenubarAlwaysExpected = false;
-
-        var testNum = 0;
-        var lastTest = args.length;
-        var newWin;
-
-        nextTest();
-        function nextTest() {
-            if (testNum == lastTest) {
-                isSuccessfullyParsed();
-                if (window.testRunner)
-                    testRunner.notifyDone();
-                return;
-            } else if (testNum == 0) {
-                debug("");
-                debug("Scrollbar");
-            } else if (testNum == 4) {
-                debug("");
-                debug("Toolbar");
-            } else if (testNum == 8) {
-                debug("");
-                debug("Statusbar");
-            } else if (testNum == 12) {
-                debug("");
-                debug("Menubar");
-            } else if (testNum == 16) {
-                debug("");
-                debug("Locationbar");
-            }
-
-            //get the next test and run it.
-            newWin = window.open("../resources/abe.png", "testWindow", args[testNum] );
-            shouldBe(actual[testNum], expected[testNum]);
-            ++testNum;
-            closeAndRunNextTest(newWin);
-        }
-
-        function closeAndRunNextTest(winToClose) {
-            winToClose.close();
-            setTimeout(doneHandler, 1);
-
-            function doneHandler() {
-                if (winToClose.closed) {
-                    setTimeout(nextTest, 1);
-                    return;
-                }
-                setTimeout(doneHandler, 1);
-            }    
-        }
-
-    </script>
-</body>
-</html>
-
diff --git a/third_party/blink/web_tests/fast/events/window-open-after-keypress.html b/third_party/blink/web_tests/fast/events/window-open-after-keypress.html
index fca283e..ca01181 100644
--- a/third_party/blink/web_tests/fast/events/window-open-after-keypress.html
+++ b/third_party/blink/web_tests/fast/events/window-open-after-keypress.html
@@ -16,7 +16,7 @@
 
 function key()
 {
-    window.open("about:blank", "", "status=0");
+    window.open("about:blank", "", "popup");
 }
 </script>
 <body onload="test()">
diff --git a/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-opus-redundancy.html b/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-opus-redundancy.html
new file mode 100644
index 0000000..98ff310
--- /dev/null
+++ b/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-opus-redundancy.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>RTCPeerConnection red+opus support</title>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <script>
+// These tests are testing the support for audio/red.
+// Not suitable for WPT since this is not mandatory-to-implement.
+promise_test(async t => {
+  const pc1 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  const pc2 = new RTCPeerConnection();
+  t.add_cleanup(() => pc2.close());
+
+  const stream = await navigator.mediaDevices.getUserMedia({audio:true})
+  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+
+  const sender = pc1.addTrack(stream.getAudioTracks()[0], stream);
+  const codecs = RTCRtpSender.getCapabilities('audio').codecs;
+  const selectedCodecIndex = codecs.findIndex(c => c.mimeType === 'audio/red' && c.clockRate === 48000);
+  assert_greater_than(selectedCodecIndex, -1);
+  const selectedCodec = codecs[selectedCodecIndex];
+  codecs.splice(selectedCodecIndex, 1);
+  codecs.unshift(selectedCodec);
+  pc1.getTransceivers()[0].setCodecPreferences(codecs);
+  await pc1.setLocalDescription();
+  await pc2.setRemoteDescription(pc1.localDescription);
+  await pc2.setLocalDescription();
+  await pc1.setRemoteDescription(pc2.localDescription);
+
+  const parameters = await sender.getParameters();
+  assert_equals(parameters.codecs[0].mimeType, 'audio/red');
+}, 'setCodecPreferences allows preferring audio/red + opus');
+    </script>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-sdes-constraint.html b/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-sdes-constraint.html
index c69ad96..c341dd8 100644
--- a/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-sdes-constraint.html
+++ b/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-sdes-constraint.html
@@ -42,9 +42,101 @@
   pc1.addTrack(track);
   let offer = await pc1.createOffer();
   // assert_regexp_match doesn't work
-  assert_true(offer.sdp.match('\na=fingerprint') !== null);
-  assert_true(offer.sdp.match('\na=crypto') === null);
-}, 'DTLS constraint false has no effect');
+  assert_true(offer.sdp.match('\na=fingerprint') === null);
+  assert_true(offer.sdp.match('\na=crypto') !== null);
+  await pc1.setLocalDescription(offer);
+  await pc2.setRemoteDescription(offer);
+  let answer = await pc2.createAnswer();
+  assert_true(answer.sdp.match('\na=fingerprint') === null);
+  assert_true(answer.sdp.match('\na=crypto') !== null);
+  await pc2.setLocalDescription(answer);
+  await pc1.setRemoteDescription(answer);
+}, 'DTLS constraint false means SDES');
+
+promise_test(async t => {
+  let pc1 = new RTCPeerConnection(null, sdes_constraint);
+  t.add_cleanup(() => pc1.close());
+  let pc2 = new RTCPeerConnection();
+  t.add_cleanup(() => pc2.close());
+  let stream = await navigator.mediaDevices.getUserMedia({audio: true});
+  let track = stream.getAudioTracks()[0];
+  pc1.addTrack(track);
+  let offer = await pc1.createOffer();
+  await pc1.setLocalDescription(offer);
+  try {
+    await pc2.setRemoteDescription(offer);
+    assert_unreached('pc2.setRemote should have thrown');
+  } catch(e) {
+    assert_equals(e.name, 'InvalidAccessError');
+  }
+}, 'SDES can\'t connect to default configuration');
+
+promise_test(async t => {
+  let pc1 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  let pc2 = new RTCPeerConnection(null, sdes_constraint);
+  t.add_cleanup(() => pc2.close());
+  let stream = await navigator.mediaDevices.getUserMedia({audio: true});
+  let track = stream.getAudioTracks()[0];
+  pc1.addTrack(track);
+  let offer = await pc1.createOffer();
+  try {
+    await pc2.setRemoteDescription(offer);
+    assert_unreached('pc2.setRemote should have thrown');
+  } catch(e) {
+    assert_equals(e.name, 'InvalidAccessError');
+  }
+}, 'Default configuration can\'t connect to SDES');
+
+causes_sdes = async function(constraint) {
+  pc = new RTCPeerConnection(null, constraint);
+  let stream = await navigator.mediaDevices.getUserMedia({audio: true});
+  let track = stream.getAudioTracks()[0];
+  pc.addTrack(track);
+  let offer = await pc.createOffer();
+  return offer.sdp.match('\na=crypto') !== null
+}
+
+valid_constraint_for_pc = async function(constraint) {
+  console.log(JSON.stringify(constraint));
+  try {
+    pc = new RTCPeerConnection(null, constraint);
+    return true;
+  } catch (e) {
+    assert_equals(e.name, 'OperationError');
+    return false;
+  }
+}
+
+promise_test(async t => {
+  assert_true(await causes_sdes(sdes_constraint));
+  assert_false(await causes_sdes(
+    {'mandatory': {'DtlsSrtpKeyAgreement': true}}));
+  assert_true(await causes_sdes(
+    {'mandatory': {'DtlsSrtpKeyAgreement': 'false'}}));
+  assert_false(await causes_sdes(
+    {'optional': [{'DtlsSrtpKeyAgreement': true}]}));
+  assert_true(await causes_sdes(
+    {'optional': [{'DtlsSrtpKeyAgreement': false}]}));
+}, 'SDES shows up when expected');
+
+valid_for_pc = function(constraint) {
+  try {
+    pc = new RTCPeerConnection(null, constraint);
+    return true;
+  } catch (e) {
+    return false;
+  }
+}
+
+test(t => {
+  assert_true(valid_for_pc(sdes_constraint));
+  assert_true(valid_for_pc({'optional': [{'DtlsSrtpKeyAgreement': false}]}));
+  assert_true(valid_for_pc({'optional': [{'DtlsSrtpKeyAgreement': 'false'}]}));
+  assert_false(valid_for_pc({'DtlsSrtpKeyAgreement': false}),
+               'Modern style constraint is not supported');
+}, 'Syntaxes valid for PC are as expected');
+
 
 </script>
 </body>
diff --git a/third_party/blink/web_tests/http/tests/devtools/cache-storage/cache-live-update-list.js b/third_party/blink/web_tests/http/tests/devtools/cache-storage/cache-live-update-list.js
index 0e95aeb6..1bc144ac 100644
--- a/third_party/blink/web_tests/http/tests/devtools/cache-storage/cache-live-update-list.js
+++ b/third_party/blink/web_tests/http/tests/devtools/cache-storage/cache-live-update-list.js
@@ -12,7 +12,7 @@
 
   var cacheStorageModel = TestRunner.mainTarget.model(SDK.ServiceWorkerCacheModel);
   cacheStorageModel.enable();
-  cacheStorageModel.throttler._timeout = 0;
+  cacheStorageModel.setThrottlerSchedulesAsSoonAsPossibleForTest();
 
   await ApplicationTestRunner.clearAllCaches();
   await ApplicationTestRunner.dumpCacheTree();
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-big-array-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-big-array-expected.txt
index 2ee9b8c..8a66771 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-big-array-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-big-array-expected.txt
@@ -48,6 +48,7 @@
         41: 41
         100: 100
     length: 101
+    [[Prototype]]: Array(0)
 console-big-array.js:23 Array(10)
     0: undefined
     1: undefined
@@ -74,6 +75,7 @@
     9: 9
     100: 100
     length: 101
+    [[Prototype]]: Array(0)
 console-big-array.js:34 Array(405)
     [0 … 399]
         [0 … 19]
@@ -103,6 +105,7 @@
         403: 403
         404: 404
     length: 405
+    [[Prototype]]: Array(0)
 console-big-array.js:47 Array(124)
     0: 0
     1: 1
@@ -123,6 +126,7 @@
     -123: -123
     NaN: NaN
     length: 124
+    [[Prototype]]: Array(0)
 console-big-array.js:57 Array(4294967295)
     [0 … 19]
         0: 0
@@ -179,6 +183,7 @@
     4294967296: 4294967296
     8589934592: 8589934592
     length: 4294967295
+    [[Prototype]]: Array(0)
 console-big-array.js:60 Uint8Array(64160003)
     [0 … 63999999]
         [0 … 3199999]
@@ -204,4 +209,16 @@
     [64000000 … 64160002]
         [64000000 … 64159999]
         [64160000 … 64160002]
+    buffer: ArrayBuffer(64160003)  
+        byteLength: 64160003
+        [[Prototype]]: ArrayBuffer
+        [[Int8Array]]: Int8Array(64160003)
+        [[Uint8Array]]: Uint8Array(64160003)
+        [[ArrayBufferByteLength]]: 64160003
+        [[ArrayBufferData]]: 1
+    byteLength: 64160003
+    byteOffset: 0
+    length: 64160003
+    Symbol(Symbol.toStringTag): "Uint8Array"
+    [[Prototype]]: TypedArray
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-external-array-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-external-array-expected.txt
index ad33b09..38629249 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-external-array-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-external-array-expected.txt
@@ -1,13 +1,13 @@
 Tests that console logging detects external arrays as arrays.
 
-console-external-array.js:14 Int8Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(10), byteLength: 10, byteOffset: 0, length: 10]
-console-external-array.js:15 Int16Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(20), byteLength: 20, byteOffset: 0, length: 10]
-console-external-array.js:16 Int32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(40), byteLength: 40, byteOffset: 0, length: 10]
-console-external-array.js:17 Uint8Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(10), byteLength: 10, byteOffset: 0, length: 10]
-console-external-array.js:18 Uint16Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(20), byteLength: 20, byteOffset: 0, length: 10]
-console-external-array.js:19 Uint32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(40), byteLength: 40, byteOffset: 0, length: 10]
-console-external-array.js:20 Float32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(40), byteLength: 40, byteOffset: 0, length: 10]
-console-external-array.js:21 Float64Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(80), byteLength: 80, byteOffset: 0, length: 10]
+console-external-array.js:14 Int8Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(10), byteLength: 10, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Int8Array']
+console-external-array.js:15 Int16Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(20), byteLength: 20, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Int16Array']
+console-external-array.js:16 Int32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(40), byteLength: 40, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Int32Array']
+console-external-array.js:17 Uint8Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(10), byteLength: 10, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Uint8Array']
+console-external-array.js:18 Uint16Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(20), byteLength: 20, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Uint16Array']
+console-external-array.js:19 Uint32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(40), byteLength: 40, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Uint32Array']
+console-external-array.js:20 Float32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(40), byteLength: 40, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Float32Array']
+console-external-array.js:21 Float64Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, buffer: ArrayBuffer(80), byteLength: 80, byteOffset: 0, length: 10, Symbol(Symbol.toStringTag): 'Float64Array']
 console-external-array.js:23 Int8Array(10)
 console-external-array.js:24 Int16Array(10)
 console-external-array.js:25 Int32Array(10)
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-side-effects-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-side-effects-expected.txt
index 1f6b0e1..745d43b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-side-effects-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-side-effects-expected.txt
@@ -17,7 +17,7 @@
 console-log-side-effects.js:43 
 console-log-side-effects.js:47 {foo: 1, bar: 2}
 console-log-side-effects.js:48 (3) [1, 2, 3]
-console-log-side-effects.js:50 Uint32Array(3) [1, 2, 3, buffer: ArrayBuffer(12), byteLength: 12, byteOffset: 0, length: 3]
+console-log-side-effects.js:50 Uint32Array(3) [1, 2, 3, buffer: ArrayBuffer(12), byteLength: 12, byteOffset: 0, length: 3, Symbol(Symbol.toStringTag): 'Uint32Array']
 console-log-side-effects.js:53 (4) [1, 2, 3, {…}]
 console-log-side-effects.js:56 {toString: ƒ}
 console-log-side-effects.js:59 (5) [1, 2, 3, {…}, {…}]
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/copy-styles-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/copy-styles-expected.txt
index 19dceda..c0a604a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/copy-styles-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/copy-styles-expected.txt
@@ -20,7 +20,6 @@
         border: 1px solid black;
         font-weight: bold;
       }
-    
 
 <body>​
 InspectorFrontendHost.copyText:
diff --git a/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/README.txt b/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/README.txt
new file mode 100644
index 0000000..0a2fa5e
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/README.txt
@@ -0,0 +1,2 @@
+These tests must run with --enable-threaded-compositor (e.g. as virtual/threaded)
+because they require requestIdleCallback.
diff --git a/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/cross-origin-test.js b/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/cross-origin-test.js
index 5e69fe8f..1b1d67f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/cross-origin-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/cross-origin-test.js
@@ -15,14 +15,18 @@
       'http://127.0.0.1:8000/devtools/resources/test-page-v8-code-cache.html');
 
   await TestRunner.evaluateInPagePromise(`
-      function loadScript() {
+      function waitUntilIdle() {
+        return new Promise(resolve=>window.requestIdleCallback(resolve));
+      }
+      async function loadScript() {
         const url =
             'http://localhost:8000/devtools/resources/v8-cache-script.js';
         const frameId = 'frame_id';
         let iframeWindow = document.getElementById(frameId).contentWindow;
-        return iframeWindow.loadScript(url)
-            .then(() => iframeWindow.loadScript(url))
-            .then(() => iframeWindow.loadScript(url));
+        await iframeWindow.loadScript(url);
+        await iframeWindow.loadScript(url);
+        await waitUntilIdle();
+        await iframeWindow.loadScript(url);
       }
   `);
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/same-origin-module-test.js b/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/same-origin-module-test.js
index 25fb65a..e8bde56 100644
--- a/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/same-origin-module-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/same-origin-module-test.js
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+function waitUntilIdle() {
+  return new Promise(resolve=>window.requestIdleCallback(resolve));
+}
+
 (async function() {
   TestRunner.addResult(`Tests V8 code cache for javascript resources\n`);
   await TestRunner.loadLegacyModule('timeline'); await TestRunner.loadTestModule('performance_test_runner');
@@ -35,6 +39,7 @@
   // <script> loading.
   await TestRunner.addIframe(scope);
   await TestRunner.addIframe(scope);
+  await waitUntilIdle();
   await TestRunner.addIframe(scope);
 
   // Load [B]. Should not use the cached code.
diff --git a/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/same-origin-test.js b/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/same-origin-test.js
index b2669c4..b3d3ef3b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/same-origin-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/same-origin-test.js
@@ -2,6 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+function waitUntilIdle() {
+  return new Promise(resolve=>{
+    window.requestIdleCallback(()=>resolve());
+  });
+}
+
 (async function() {
   TestRunner.addResult(`Tests V8 code cache for javascript resources\n`);
   await TestRunner.loadLegacyModule('timeline'); await TestRunner.loadTestModule('performance_test_runner');
@@ -51,6 +57,7 @@
 
   await expectationComment('Load [A] 2nd time. Produce code cache. -->');
   await TestRunner.addIframe(scope);
+  await waitUntilIdle();
 
   await expectationComment('Load [A] 3rd time. Consume code cache. -->');
   await TestRunner.addIframe(scope);
diff --git a/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/stale-revalidation-test.js b/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/stale-revalidation-test.js
index 83d5248..811e9ab 100644
--- a/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/stale-revalidation-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/isolated-code-cache/stale-revalidation-test.js
@@ -2,6 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+function waitUntilIdle() {
+  return new Promise(resolve=>{
+    window.requestIdleCallback(()=>resolve());
+  });
+}
+
 (async function() {
   TestRunner.addResult('Tests V8 code cache for resources revalidated with 304.\n');
   // The main purpose of the test is to demonstrate that after producing the
@@ -45,6 +51,7 @@
 
   await expectationComment('2nd load. Produce code cache. -->');
   await TestRunner.addIframe(resource);
+  await waitUntilIdle();
 
   await expectationComment('3rd load. Consume code cache. -->');
   await TestRunner.addIframe(resource);
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/script-formatter-breakpoints-2-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/script-formatter-breakpoints-2-expected.txt
deleted file mode 100644
index d6f3d79..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/script-formatter-breakpoints-2-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-Tests the script formatting is working fine with breakpoints.
-
-
-Running: testSetup
-
-Running: testBreakpointsSetAndRemoveInFormattedSource
-Script execution paused.
-Breakpoint sidebar pane while paused in pretty printed
-unformatted2.js:formatted:4checked    var c = 3;
-Breakpoint sidebar pane while paused in raw
-No breakpoints
-Script execution resumed.
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/script-formatter-breakpoints-2.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/script-formatter-breakpoints-2.js
deleted file mode 100644
index 489fec4..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/script-formatter-breakpoints-2.js
+++ /dev/null
@@ -1,56 +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.
-
-(async function() {
-  TestRunner.addResult(`Tests the script formatting is working fine with breakpoints.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-  await TestRunner.addScriptTag('../debugger/resources/unformatted2.js');
-
-  Bindings.breakpointManager.storage.breakpoints = new Map();
-  var panel = UI.panels.sources;
-  var scriptFormatter;
-  var formattedSourceFrame;
-
-  SourcesTestRunner.runDebuggerTestSuite([
-    function testSetup(next) {
-      SourcesTestRunner.scriptFormatter().then(function(sf) {
-        scriptFormatter = sf;
-        next();
-      });
-    },
-
-    function testBreakpointsSetAndRemoveInFormattedSource(next) {
-      SourcesTestRunner.showScriptSource('unformatted2.js', didShowScriptSource);
-
-      function didShowScriptSource(frame) {
-        TestRunner.addSniffer(
-            Sources.ScriptFormatterEditorAction.prototype, 'updateButton', uiSourceCodeScriptFormatted);
-        scriptFormatter.toggleFormatScriptSource();
-      }
-
-      async function uiSourceCodeScriptFormatted() {
-        formattedSourceFrame = panel.visibleView;
-        await SourcesTestRunner.waitUntilDebuggerPluginLoaded(
-            formattedSourceFrame);
-        await SourcesTestRunner.setBreakpoint(formattedSourceFrame, 3, '', true);
-        SourcesTestRunner.waitBreakpointSidebarPane().then(evaluateF2);
-      }
-
-      function evaluateF2() {
-        SourcesTestRunner.waitUntilPaused(pausedInF2);
-        setTimeout(() => TestRunner.evaluateInPageAnonymously('f2()'), 1);
-      }
-
-      async function pausedInF2(callFrames) {
-        SourcesTestRunner.dumpBreakpointSidebarPane('while paused in pretty printed');
-        SourcesTestRunner.waitBreakpointSidebarPane()
-            .then(() => SourcesTestRunner.dumpBreakpointSidebarPane('while paused in raw'))
-            .then(() => SourcesTestRunner.resumeExecution(next));
-        SourcesTestRunner.removeBreakpoint(formattedSourceFrame, 3);
-        await Formatter.SourceFormatter.instance().discardFormattedUISourceCode(panel.visibleView.uiSourceCode());
-      }
-    }
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/script-formatter-breakpoints-3-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/script-formatter-breakpoints-3-expected.txt
deleted file mode 100644
index ae64391..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/script-formatter-breakpoints-3-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-Tests the script formatting is working fine with breakpoints.
-
-
-Running: testSetup
-
-Running: testBreakpointsSetInFormattedAndRemoveInOriginalSource
-Script execution paused.
-Breakpoint sidebar pane while paused in pretty printed
-unformatted3.js:formatted:4checked    var c = 3;
-Breakpoint sidebar pane while paused in raw
-unformatted3.js:3checked breakpoint hit    var a=0;var b=1;var c=3;var d=4;var e=5;
-Script execution resumed.
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/script-formatter-breakpoints-3.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/script-formatter-breakpoints-3.js
deleted file mode 100644
index 86a90ab..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/script-formatter-breakpoints-3.js
+++ /dev/null
@@ -1,56 +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.
-
-(async function() {
-  TestRunner.addResult(`Tests the script formatting is working fine with breakpoints.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-  await TestRunner.addScriptTag('../debugger/resources/unformatted3.js');
-
-  Bindings.breakpointManager.storage._breakpoints = new Map();
-  var panel = UI.panels.sources;
-  var scriptFormatter;
-
-  SourcesTestRunner.runDebuggerTestSuite([
-    function testSetup(next) {
-      SourcesTestRunner.scriptFormatter().then(function(sf) {
-        scriptFormatter = sf;
-        next();
-      });
-    },
-
-    function testBreakpointsSetInFormattedAndRemoveInOriginalSource(next) {
-      SourcesTestRunner.showScriptSource('unformatted3.js', didShowScriptSource);
-
-      function didShowScriptSource(frame) {
-        TestRunner.addSniffer(
-            Sources.ScriptFormatterEditorAction.prototype, 'updateButton', uiSourceCodeScriptFormatted);
-        scriptFormatter.toggleFormatScriptSource();
-      }
-
-      async function uiSourceCodeScriptFormatted() {
-        var formattedSourceFrame = panel.visibleView;
-        await SourcesTestRunner.waitUntilDebuggerPluginLoaded(
-            formattedSourceFrame);
-        await SourcesTestRunner.setBreakpoint(formattedSourceFrame, 3, '', true);
-        SourcesTestRunner.waitBreakpointSidebarPane().then(evaluateF2);
-      }
-
-      function evaluateF2() {
-        SourcesTestRunner.waitUntilPaused(pausedInF2);
-        setTimeout(() => TestRunner.evaluateInPageAnonymously('f2()'), 1);
-      }
-
-
-      async function pausedInF2(callFrames) {
-        SourcesTestRunner.dumpBreakpointSidebarPane('while paused in pretty printed');
-        SourcesTestRunner.waitBreakpointSidebarPane()
-            .then(() => SourcesTestRunner.dumpBreakpointSidebarPane('while paused in raw'))
-            .then(() => SourcesTestRunner.resumeExecution(next));
-        // No need to remove breakpoint since formattedUISourceCode was removed.
-        await Formatter.SourceFormatter.instance().discardFormattedUISourceCode(panel.visibleView.uiSourceCode());
-      }
-    }
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-test.js b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
index f8798ba..dc50e31 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
@@ -199,9 +199,9 @@
       params.height = options.height;
     if (options.enableBeginFrameControl)
       params.enableBeginFrameControl = true;
-    if (options.createContext) {
-      const browserContextId = (await browserProtocol.Target.createBrowserContext()).result.browserContextId;
-      options.browserContextId = browserContextId;
+    if (options.createContextOptions) {
+      const browserContextId = (await browserProtocol.Target.createBrowserContext(options.createContextOptions)).result.browserContextId;
+      params.browserContextId = browserContextId;
     }
     const targetId = (await browserProtocol.Target.createTarget(params)).result.targetId;
     const page = new TestRunner.Page(this, targetId);
@@ -249,7 +249,7 @@
     options = options || {};
     options.width = options.width || 800;
     options.height = options.height || 600;
-    options.createContext = true;
+    options.createContextOptions = {};
     options.enableBeginFrameControl = true;
     return this._start(description, options);
   }
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/webrtc-encoded-transform/idlharness.https.window-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/webrtc-encoded-transform/idlharness.https.window-expected.txt
deleted file mode 100644
index 7acdaa27..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/webrtc-encoded-transform/idlharness.https.window-expected.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-This is a testharness.js-based test.
-Found 50 tests; 33 PASS, 17 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS idl_test setup
-PASS idl_test validation
-PASS Partial interface RTCRtpSender: original interface defined
-PASS Partial interface RTCRtpSender: member names are unique
-PASS Partial interface RTCRtpReceiver: original interface defined
-PASS Partial interface RTCRtpReceiver: member names are unique
-PASS Partial interface DedicatedWorkerGlobalScope: original interface defined
-PASS Partial interface DedicatedWorkerGlobalScope: member names are unique
-PASS Partial interface RTCRtpSender[2]: member names are unique
-PASS SFrameTransform includes GenericTransformStream: member names are unique
-PASS WorkerGlobalScope includes WindowOrWorkerGlobalScope: member names are unique
-PASS DedicatedWorkerGlobalScope includes AnimationFrameProvider: member names are unique
-FAIL SFrameTransform interface: existence and properties of interface object assert_own_property: self does not have own property "SFrameTransform" expected property "SFrameTransform" missing
-FAIL SFrameTransform interface object length assert_own_property: self does not have own property "SFrameTransform" expected property "SFrameTransform" missing
-FAIL SFrameTransform interface object name assert_own_property: self does not have own property "SFrameTransform" expected property "SFrameTransform" missing
-FAIL SFrameTransform interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SFrameTransform" expected property "SFrameTransform" missing
-FAIL SFrameTransform interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SFrameTransform" expected property "SFrameTransform" missing
-FAIL SFrameTransform interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "SFrameTransform" expected property "SFrameTransform" missing
-FAIL SFrameTransform interface: operation setEncryptionKey(CryptoKey, optional CryptoKeyID) assert_own_property: self does not have own property "SFrameTransform" expected property "SFrameTransform" missing
-PASS RTCEncodedVideoFrame interface: existence and properties of interface object
-PASS RTCEncodedVideoFrame interface object length
-PASS RTCEncodedVideoFrame interface object name
-PASS RTCEncodedVideoFrame interface: existence and properties of interface prototype object
-PASS RTCEncodedVideoFrame interface: existence and properties of interface prototype object's "constructor" property
-PASS RTCEncodedVideoFrame interface: existence and properties of interface prototype object's @@unscopables property
-PASS RTCEncodedVideoFrame interface: attribute type
-PASS RTCEncodedVideoFrame interface: attribute timestamp
-PASS RTCEncodedVideoFrame interface: attribute data
-PASS RTCEncodedVideoFrame interface: operation getMetadata()
-PASS RTCEncodedAudioFrame interface: existence and properties of interface object
-PASS RTCEncodedAudioFrame interface object length
-PASS RTCEncodedAudioFrame interface object name
-PASS RTCEncodedAudioFrame interface: existence and properties of interface prototype object
-PASS RTCEncodedAudioFrame interface: existence and properties of interface prototype object's "constructor" property
-PASS RTCEncodedAudioFrame interface: existence and properties of interface prototype object's @@unscopables property
-PASS RTCEncodedAudioFrame interface: attribute timestamp
-PASS RTCEncodedAudioFrame interface: attribute data
-PASS RTCEncodedAudioFrame interface: operation getMetadata()
-PASS RTCTransformEvent interface: existence and properties of interface object
-PASS RTCRtpScriptTransformer interface: existence and properties of interface object
-FAIL RTCRtpScriptTransform interface: existence and properties of interface object assert_own_property: self does not have own property "RTCRtpScriptTransform" expected property "RTCRtpScriptTransform" missing
-FAIL RTCRtpScriptTransform interface object length assert_own_property: self does not have own property "RTCRtpScriptTransform" expected property "RTCRtpScriptTransform" missing
-FAIL RTCRtpScriptTransform interface object name assert_own_property: self does not have own property "RTCRtpScriptTransform" expected property "RTCRtpScriptTransform" missing
-FAIL RTCRtpScriptTransform interface: existence and properties of interface prototype object assert_own_property: self does not have own property "RTCRtpScriptTransform" expected property "RTCRtpScriptTransform" missing
-FAIL RTCRtpScriptTransform interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "RTCRtpScriptTransform" expected property "RTCRtpScriptTransform" missing
-FAIL RTCRtpScriptTransform interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "RTCRtpScriptTransform" expected property "RTCRtpScriptTransform" missing
-FAIL RTCRtpSender interface: attribute transform assert_true: The prototype object must have a property "transform" expected true got false
-FAIL RTCRtpSender interface: new RTCPeerConnection().addTransceiver('audio').sender must inherit property "transform" with the proper type assert_inherits: property "transform" not found in prototype chain
-FAIL RTCRtpReceiver interface: attribute transform assert_true: The prototype object must have a property "transform" expected true got false
-FAIL RTCRtpReceiver interface: new RTCPeerConnection().addTransceiver('audio').receiver must inherit property "transform" with the proper type assert_inherits: property "transform" not found in prototype chain
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/external/wpt/webrtc-encoded-transform/sframe-transform-buffer-source-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.14/external/wpt/webrtc-encoded-transform/sframe-transform-buffer-source-expected.txt
deleted file mode 100644
index eef58c5..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.14/external/wpt/webrtc-encoded-transform/sframe-transform-buffer-source-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Uint8Array as input to SFrameTransform promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'importKey')"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/external/wpt/webrtc-encoded-transform/sframe-transform-buffer-source-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.15/external/wpt/webrtc-encoded-transform/sframe-transform-buffer-source-expected.txt
deleted file mode 100644
index 0a239da..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.15/external/wpt/webrtc-encoded-transform/sframe-transform-buffer-source-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Uint8Array as input to SFrameTransform promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'importKey' of undefined"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/threaded/http/tests/devtools/isolated-code-cache/README.txt b/third_party/blink/web_tests/virtual/threaded/http/tests/devtools/isolated-code-cache/README.txt
new file mode 100644
index 0000000..5ad1e6e
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/threaded/http/tests/devtools/isolated-code-cache/README.txt
@@ -0,0 +1,3 @@
+This suite runs the tests in devtools/isolated-code-cache with a threaded
+compositor. This is required for requestIdleCallback to work, which is required
+for --enable-features=CacheCodeOnIdle.
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-011.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-011.html
index 12deac3..7307dffc5e 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-011.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-011.html
@@ -22,7 +22,7 @@
     container-type: inline-size;
   }
 
-  @container (max-width: 200px), (min-width: 300px) {
+  @container (max-width: 200px) or (min-width: 300px) {
     #child { color: green; }
   }
 
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-parsing.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-parsing.html
new file mode 100644
index 0000000..912e825
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-parsing.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<title>@container: parsing</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div style="container:size; width:100px; height:100px">
+  <main id=main></main>
+</div>
+<script>
+
+  function cleanup_main() {
+    while (main.firstChild)
+      main.firstChild.remove();
+  }
+
+  function set_style(text) {
+    let style = document.createElement('style');
+    style.innerText = text;
+    main.append(style);
+    return style;
+  }
+
+  function test_query_invalid(query) {
+    test(t => {
+      t.add_cleanup(cleanup_main);
+      let style = set_style(`@container ${query} {}`);
+      assert_equals(style.sheet.rules.length, 0);
+    }, query);
+  }
+
+  // Tests that 1) the query parses, and 2) it does not evaluate to "unknown".
+  function test_query_known(query) {
+    test(t => {
+      t.add_cleanup(cleanup_main);
+      let style = set_style(`
+        @container ${query} {}
+        @container (${query}) or (not (${query})) { main { --match:true; } }
+      `);
+      assert_equals(style.sheet.rules.length, 2);
+      assert_equals(getComputedStyle(main).getPropertyValue('--match'), 'true');
+    }, query);
+  }
+
+  function test_container_selector_invalid(container_selector) {
+    test(t => {
+      t.add_cleanup(cleanup_main);
+      let style = set_style(`@container ${container_selector} (width) {}`);
+      assert_equals(style.sheet.rules.length, 0);
+    }, `Container selector: ${container_selector}`);
+  }
+
+  function test_container_selector_valid(container_selector) {
+    test(t => {
+      t.add_cleanup(cleanup_main);
+      let style = set_style(`@container ${container_selector} (width) {}`);
+      assert_equals(style.sheet.rules.length, 1);
+    }, `Container selector: ${container_selector}`);
+  }
+
+  test_query_known('(width: 100px)');
+  test_query_known('((width: 100px))');
+  test_query_known('(not (width: 100px))');
+  test_query_known('(width: 100px) and (height: 100px)');
+  test_query_known('(width: 50px) or (height: 100px)');
+  test_query_known('(width < 100px)');
+  test_query_known('(100px < width)');
+  test_query_known('(100px < width < 200px)');
+
+  test_query_invalid('screen');
+  test_query_invalid('print');
+  test_query_invalid('not print');
+  test_query_invalid('only print');
+  test_query_invalid('screen and (width: 100px)');
+  test_query_invalid('screen or (width: 100px)');
+  test_query_invalid('not screen and (width: 100px)');
+  test_query_invalid('not screen or (width: 100px)');
+  test_query_invalid('(width: 100px), (height: 100px)');
+
+  test_container_selector_valid(' foo');
+  test_container_selector_valid(' foo ');
+  test_container_selector_valid('name(foo)');
+  test_container_selector_valid('name( foo )');
+  test_container_selector_valid('type(size)');
+  test_container_selector_valid('type( size )');
+  test_container_selector_valid('type(inline-size)');
+  test_container_selector_valid('type(block-size)');
+  test_container_selector_valid('name(bar) type(block-size)');
+  test_container_selector_valid('type(block-size) name(bar)');
+
+  test_container_selector_invalid('foo foo');
+  test_container_selector_invalid('1px');
+  test_container_selector_invalid('50gil');
+  test_container_selector_invalid('name(1px)');
+  test_container_selector_invalid('type(1px)');
+  test_container_selector_invalid('type(red)');
+  test_container_selector_invalid('type(size) type(size)');
+  test_container_selector_invalid('type(inline-size) type(block-size)');
+  test_container_selector_invalid('name(foo) name(bar)');
+  test_container_selector_invalid('type(inline-size) name(foo) type(block-size)');
+  test_container_selector_invalid('name(foo) type(size) name(bar)');
+  test_container_selector_invalid('name(type(size))');
+  test_container_selector_invalid('type(name(bar))');
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/container-selection.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/container-selection.html
new file mode 100644
index 0000000..b5c7220a
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/container-selection.html
@@ -0,0 +1,179 @@
+<!DOCTYPE html>
+<title>@container: selection using name(), type()</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+
+  main { background-color: lightgray; }
+  main > div { background-color: skyblue; }
+  main > div > div { background-color: seagreen; }
+  main > div > div > div { background-color: tomato; }
+
+  main {
+    width: 64px;
+    height: 64px;
+  }
+
+  main div {
+    width: 50%;
+    height: 50%;
+  }
+
+  .inline { container-type: inline-size; }
+  .block { container-type: block-size; }
+  .size { container-type: size; }
+
+  .a-inline { container:  inline-size / a; }
+  .a-block { container:  block-size / a; }
+  .a-size { container:  size / a; }
+
+  .b-inline { container:  inline-size / b; }
+  .b-block { container:  block-size / b; }
+  .b-size { container:  size / b; }
+
+</style>
+
+<main>
+  <div class="inline">
+    <div class="block">
+      <span></span>
+    </div>
+  </div>
+</main>
+
+<main>
+  <div class="block">
+    <div class="inline">
+      <span></span>
+    </div>
+  </div>
+</main>
+
+<main>
+  <div class="size">
+    <div class="block">
+      <span></span>
+    </div>
+  </div>
+</main>
+
+<main>
+  <div class="size">
+    <div class="inline">
+      <span></span>
+    </div>
+  </div>
+</main>
+
+<main>
+  <div class="a-inline">
+    <div class="b-inline">
+      <span></span>
+    </div>
+  </div>
+</main>
+
+<main>
+  <div class="a-inline">
+    <div class="a-inline">
+      <span></span>
+    </div>
+  </div>
+</main>
+
+<main>
+  <div class="a-inline">
+    <div class="b-inline">
+      <div class="a-block">
+        <span></span>
+      </div>
+    </div>
+  </div>
+</main>
+
+<script>
+
+  function test_query(prelude, selector, expected) {
+    test(t => {
+      let elements = document.querySelectorAll(selector);
+      assert_equals(elements.length, 1);
+      let element = elements[0];
+
+      let style = document.createElement('style');
+      t.add_cleanup(() => { style.remove(); });
+      style.innerText = `@container ${prelude} { span { --match:true; } } `;
+      document.body.append(style);
+
+      assert_equals(getComputedStyle(element).getPropertyValue('--match'), expected);
+    }, `${prelude} for ${selector}`);
+  }
+
+  // Test that a given container query applies to the specified element.
+  // The provided selector must unique identify the element.
+  function test_applied(prelude, selector) {
+    test_query(prelude, selector, 'true');
+  }
+
+  function test_rejected(prelude, selector) {
+    test_query(prelude, selector, '');
+  }
+
+  // For the following tests, the inner container has a size of 16x16px,
+  // and the outer container has a size of 32x32px.
+
+  // "Nearest" selection:
+  test_applied('(width: 16px)', '.block > .inline > span');
+  test_applied('(height: 16px)', '.inline > .block > span');
+  test_rejected('(height)', '.block > .inline > span');
+  test_rejected('(width)', '.inline > .block > span');
+
+  // type():
+  test_applied('type(inline-size) (width: 32px)', '.inline > .block > span');
+  test_applied('type(inline-size) (width: 16px)', '.block > .inline > span');
+  test_applied('type(inline-size) (width: 32px)', '.size > .block > span');
+  test_applied('type(inline-size) (width: 16px)', '.size > .inline > span');
+
+  test_applied('type(block-size) (height: 16px)', '.inline > .block > span');
+  test_applied('type(block-size) (height: 32px)', '.block > .inline > span');
+  test_applied('type(block-size) (height: 16px)', '.size > .block > span');
+  test_applied('type(block-size) (height: 32px)', '.size > .inline > span');
+
+  test_rejected('type(size) (height)', '.inline > .block > span');
+  test_rejected('type(size) (height)', '.block > .inline > span');
+  test_rejected('type(size) (width)', '.inline > .block > span');
+  test_rejected('type(size) (width)', '.block > .inline > span');
+  test_applied('type(size) (height: 32px)', '.size > .block > span');
+  test_applied('type(size) (height: 32px)', '.size > .inline > span');
+
+  // name():
+  test_applied('name(a) (width: 32px)', '.a-inline > .b-inline > span');
+  test_applied('name(b) (width: 16px)', '.a-inline > .b-inline > span');
+  test_rejected('name(c) (width)', '.a-inline > .b-inline > span');
+  test_applied('name(a) (width: 16px)', '.a-inline > .a-inline > span');
+
+  // Name as plain ident:
+  test_applied('a (width: 32px)', '.a-inline > .b-inline > span');
+  test_applied('b (width: 16px)', '.a-inline > .b-inline > span');
+  test_rejected('c (width)', '.a-inline > .b-inline > span');
+  test_applied('a (width: 16px)', '.a-inline > .a-inline > span');
+
+  // The following tests have three containers:
+  //
+  //  outer  -> 32x32px
+  //  middle -> 16x16px
+  //  inner -> 8x8px
+
+  // Mixing name() and type():
+  test_applied('name(a) type(inline-size) (width: 32px)', '.a-inline > .b-inline > .a-block > span');
+  test_applied('name(a) type(block-size) (height: 8px)', '.a-inline > .b-inline > .a-block > span');
+  test_rejected('name(a) type(size) (height)', '.a-inline > .b-inline > .a-block > span');
+  test_applied('name(b) type(inline-size) (width: 16px)', '.a-inline > .b-inline > .a-block > span');
+  test_rejected('name(b) type(block-size) (height)', '.a-inline > .b-inline > .a-block > span');
+  test_rejected('name(b) type(size) (height)', '.a-inline > .b-inline > .a-block > span');
+
+  // type() first, then name():
+  test_applied('type(inline-size) name(a) (width: 32px)', '.a-inline > .b-inline > .a-block > span');
+  test_applied('type(block-size) name(a) (height: 8px)', '.a-inline > .b-inline > .a-block > span');
+
+</script>
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index 7ebff1f..799ecf9 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: ab9a87fb5463e5d1579e16bacb1f79d0dd71119b
+Revision: c8edcf1bb8c89d94e99b85e2942e0a81a8572828
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/handler/BUILD.gn b/third_party/crashpad/crashpad/handler/BUILD.gn
index f66da69a..e7a4966 100644
--- a/third_party/crashpad/crashpad/handler/BUILD.gn
+++ b/third_party/crashpad/crashpad/handler/BUILD.gn
@@ -112,6 +112,7 @@
     "../client:common",
     "../snapshot",
     "../util",
+    "../util:net",
   ]
   if (crashpad_is_win) {
     cflags = [ "/wd4201" ]  # nonstandard extension used : nameless struct/union
diff --git a/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc b/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc
index 60f172b..3872e11 100644
--- a/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc
+++ b/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc
@@ -46,6 +46,21 @@
 
 namespace crashpad {
 
+namespace {
+
+// The number of seconds to wait between checking for pending reports.
+const int kRetryWorkIntervalSeconds = 15 * 60;
+
+#if defined(OS_IOS)
+// The number of times to attempt to upload a pending report, repeated on
+// failure. Attempts will happen once per launch, once per call to
+// ReportPending(), and, if Options.watch_pending_reports is true, once every
+// kRetryWorkIntervalSeconds. Currently iOS only.
+const int kRetryAttempts = 5;
+#endif
+
+}  // namespace
+
 CrashReportUploadThread::CrashReportUploadThread(CrashReportDatabase* database,
                                                  const std::string& url,
                                                  const Options& options)
@@ -55,7 +70,7 @@
       // absence of a signal from the handler thread. This allows for failed
       // uploads to be retried periodically, and for pending reports written by
       // other processes to be recognized.
-      thread_(options.watch_pending_reports ? 15 * 60.0
+      thread_(options.watch_pending_reports ? kRetryWorkIntervalSeconds
                                             : WorkerThread::kIndefiniteWait,
               this),
       known_pending_report_uuids_(),
@@ -154,45 +169,13 @@
     return;
   }
 
-  // This currently implements very simplistic rate-limiting, compatible with
-  // the Breakpad client, where the strategy is to permit one upload attempt per
-  // hour, and retire reports that would exceed this limit or for which the
-  // upload fails on the first attempt.
-  //
-  // If upload was requested explicitly (i.e. by user action), we do not
-  // throttle the upload.
-  //
-  // TODO(mark): Provide a proper rate-limiting strategy and allow for failed
-  // upload attempts to be retried.
-  if (!report.upload_explicitly_requested && options_.rate_limit) {
-    time_t last_upload_attempt_time;
-    if (settings->GetLastUploadAttemptTime(&last_upload_attempt_time)) {
-      time_t now = time(nullptr);
-      if (now >= last_upload_attempt_time) {
-        // If the most recent upload attempt occurred within the past hour,
-        // don’t attempt to upload the new report. If it happened longer ago,
-        // attempt to upload the report.
-        constexpr int kUploadAttemptIntervalSeconds = 60 * 60;  // 1 hour
-        if (now - last_upload_attempt_time < kUploadAttemptIntervalSeconds) {
-          database_->SkipReportUpload(
-              report.uuid, Metrics::CrashSkippedReason::kUploadThrottled);
-          return;
-        }
-      } else {
-        // The most recent upload attempt purportedly occurred in the future. If
-        // it “happened” at least one day in the future, assume that the last
-        // upload attempt time is bogus, and attempt to upload the report. If
-        // the most recent upload time is in the future but within one day,
-        // accept it and don’t attempt to upload the report.
-        constexpr int kBackwardsClockTolerance = 60 * 60 * 24;  // 1 day
-        if (last_upload_attempt_time - now < kBackwardsClockTolerance) {
-          database_->SkipReportUpload(
-              report.uuid, Metrics::CrashSkippedReason::kUnexpectedTime);
-          return;
-        }
-      }
-    }
-  }
+  if (ShouldRateLimitUpload(report))
+    return;
+
+#if defined(OS_IOS)
+  if (ShouldRateLimitRetry(report))
+    return;
+#endif
 
   std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report;
   CrashReportDatabase::OperationStatus status =
@@ -234,6 +217,19 @@
           report.uuid, Metrics::CrashSkippedReason::kPrepareForUploadFailed);
       break;
     case UploadResult::kRetry:
+#if defined(OS_IOS)
+      if (upload_report->upload_attempts > kRetryAttempts) {
+        upload_report.reset();
+        database_->SkipReportUpload(report.uuid,
+                                    Metrics::CrashSkippedReason::kUploadFailed);
+      } else {
+        Metrics::CrashUploadSkipped(
+            Metrics::CrashSkippedReason::kUploadFailedButCanRetry);
+        retry_uuid_time_map_[report.uuid] =
+            time(nullptr) +
+            (1 << upload_report->upload_attempts) * kRetryWorkIntervalSeconds;
+      }
+#else
       upload_report.reset();
 
       // TODO(mark): Deal with retries properly: don’t call SkipReportUplaod()
@@ -241,6 +237,7 @@
       // too many times.
       database_->SkipReportUpload(report.uuid,
                                   Metrics::CrashSkippedReason::kUploadFailed);
+#endif
       break;
   }
 }
@@ -344,4 +341,55 @@
   ProcessPendingReports();
 }
 
+bool CrashReportUploadThread::ShouldRateLimitUpload(
+    const CrashReportDatabase::Report& report) {
+  if (report.upload_explicitly_requested || !options_.rate_limit)
+    return false;
+
+  Settings* const settings = database_->GetSettings();
+  time_t last_upload_attempt_time;
+  if (settings->GetLastUploadAttemptTime(&last_upload_attempt_time)) {
+    time_t now = time(nullptr);
+    if (now >= last_upload_attempt_time) {
+      // If the most recent upload attempt occurred within the past hour,
+      // don’t attempt to upload the new report. If it happened longer ago,
+      // attempt to upload the report.
+      constexpr int kUploadAttemptIntervalSeconds = 60 * 60;  // 1 hour
+      if (now - last_upload_attempt_time < kUploadAttemptIntervalSeconds) {
+        database_->SkipReportUpload(
+            report.uuid, Metrics::CrashSkippedReason::kUploadThrottled);
+        return true;
+      }
+    } else {
+      // The most recent upload attempt purportedly occurred in the future. If
+      // it “happened” at least one day in the future, assume that the last
+      // upload attempt time is bogus, and attempt to upload the report. If
+      // the most recent upload time is in the future but within one day,
+      // accept it and don’t attempt to upload the report.
+      constexpr int kBackwardsClockTolerance = 60 * 60 * 24;  // 1 day
+      if (last_upload_attempt_time - now < kBackwardsClockTolerance) {
+        database_->SkipReportUpload(
+            report.uuid, Metrics::CrashSkippedReason::kUnexpectedTime);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+#if defined(OS_IOS)
+bool CrashReportUploadThread::ShouldRateLimitRetry(
+    const CrashReportDatabase::Report& report) {
+  if (retry_uuid_time_map_.find(report.uuid) != retry_uuid_time_map_.end()) {
+    time_t now = time(nullptr);
+    if (now < retry_uuid_time_map_[report.uuid]) {
+      return true;
+    } else {
+      retry_uuid_time_map_.erase(report.uuid);
+    }
+  }
+  return false;
+}
+#endif
+
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/handler/crash_report_upload_thread.h b/third_party/crashpad/crashpad/handler/crash_report_upload_thread.h
index 1a88a08..7649ae0 100644
--- a/third_party/crashpad/crashpad/handler/crash_report_upload_thread.h
+++ b/third_party/crashpad/crashpad/handler/crash_report_upload_thread.h
@@ -17,6 +17,7 @@
 
 #include <memory>
 #include <string>
+#include <unordered_map>
 
 #include "client/crash_report_database.h"
 #include "util/misc/uuid.h"
@@ -170,10 +171,45 @@
   //!     been called on any thread, as well as periodically on a timer.
   void DoWork(const WorkerThread* thread) override;
 
+  //! \brief Rate-limit uploads.
+  //!
+  //! \param[in] report The crash report to process.
+  //!
+  //! This currently implements very simplistic rate-limiting, compatible with
+  //! the Breakpad client, where the strategy is to permit one upload attempt
+  //! per hour, and retire reports that would exceed this limit or for which the
+  //! upload fails on the first attempt.
+  //! If upload was requested explicitly (i.e. by user action), do not throttle
+  //! the upload.
+  //!
+  //! TODO(mark): Provide a proper rate-limiting strategy and allow for failed
+  //! upload attempts to be retried.
+  bool ShouldRateLimitUpload(const CrashReportDatabase::Report& report);
+
+#if defined(OS_IOS)
+  //! \brief Rate-limit report retries.
+  //!
+  //! \param[in] report The crash report to process.
+  //!
+  //! This implements a per-report retry rate limit (as opposed to per upload
+  //! rate limit in ShouldRateLimitUpload). When a report upload ends in a retry
+  //! state, an in-memory only timestamp is stored in |retry_uuid_time_map_|
+  //! with the next possible retry time. This timestamp is a backoff from the
+  //! main thread work interval, doubling on each attemt. Because this is only
+  //! stored in memory, on restart reports in the retry state will always be
+  //! tried once, and then fall back into the next backoff. This continues until
+  //! kRetryAttempts is reached.
+  bool ShouldRateLimitRetry(const CrashReportDatabase::Report& report);
+#endif
+
   const Options options_;
   const std::string url_;
   WorkerThread thread_;
   ThreadSafeVector<UUID> known_pending_report_uuids_;
+#if defined(OS_IOS)
+  // This is not thread-safe, and only used by the worker thread.
+  std::map<UUID, time_t> retry_uuid_time_map_;
+#endif
   CrashReportDatabase* database_;  // weak
 };
 
diff --git a/third_party/crashpad/crashpad/tools/BUILD.gn b/third_party/crashpad/crashpad/tools/BUILD.gn
index 91e20a0..4069e07 100644
--- a/third_party/crashpad/crashpad/tools/BUILD.gn
+++ b/third_party/crashpad/crashpad/tools/BUILD.gn
@@ -48,6 +48,7 @@
       "../compat",
       "$mini_chromium_source_parent:base",
       "../util",
+      "../util:net",
     ]
   }
 }
diff --git a/third_party/crashpad/crashpad/util/BUILD.gn b/third_party/crashpad/crashpad/util/BUILD.gn
index c0d8fae..ffedf1e 100644
--- a/third_party/crashpad/crashpad/util/BUILD.gn
+++ b/third_party/crashpad/crashpad/util/BUILD.gn
@@ -225,17 +225,6 @@
     "misc/uuid.h",
     "misc/zlib.cc",
     "misc/zlib.h",
-    "net/http_body.cc",
-    "net/http_body.h",
-    "net/http_body_gzip.cc",
-    "net/http_body_gzip.h",
-    "net/http_headers.h",
-    "net/http_multipart_builder.cc",
-    "net/http_multipart_builder.h",
-    "net/http_transport.cc",
-    "net/http_transport.h",
-    "net/url.cc",
-    "net/url.h",
     "numeric/checked_address_range.cc",
     "numeric/checked_address_range.h",
     "numeric/checked_range.h",
@@ -377,7 +366,6 @@
       "mach/scoped_task_suspend.h",
       "mach/task_for_pid.cc",
       "mach/task_for_pid.h",
-      "net/http_transport_mac.mm",
       "posix/process_info_mac.cc",
       "process/process_memory_mac.cc",
       "process/process_memory_mac.h",
@@ -405,34 +393,11 @@
       "ios/raw_logging.h",
       "ios/scoped_vm_read.cc",
       "ios/scoped_vm_read.h",
-      "net/http_transport_mac.mm",
     ]
   }
 
   deps = [ "//build:chromeos_buildflags" ]
 
-  if (crashpad_http_transport_impl == "socket") {
-    sources += [ "net/http_transport_socket.cc" ]
-    if (crashpad_use_boringssl_for_http_transport_socket) {
-      defines += [ "CRASHPAD_USE_BORINGSSL" ]
-
-      if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) {
-        deps += [ "//third_party/boringssl" ]
-      } else {
-        libs = [
-          "crypto",
-          "ssl",
-        ]
-      }
-    }
-  } else if (crashpad_http_transport_impl == "libcurl") {
-    sources += [ "net/http_transport_libcurl.cc" ]
-    if (crashpad_is_in_fuchsia) {
-      # Host Linux builds in Fuchsia don't have libcurl in a sysroot.
-      deps += [ "//third_party/curl:libcurl" ]
-    }
-  }
-
   if (crashpad_is_android) {
     sources += [
       "linux/initial_signal_dispositions.cc",
@@ -496,7 +461,6 @@
       "misc/clock_win.cc",
       "misc/paths_win.cc",
       "misc/time_win.cc",
-      "net/http_transport_win.cc",
       "process/process_memory_win.cc",
       "process/process_memory_win.h",
       "synchronization/semaphore_win.cc",
@@ -660,12 +624,70 @@
   }
 }
 
+# net is split into a separate target from util so that client code does
+# not have to depend on it.
+crashpad_static_library("net") {
+  sources = [
+    "net/http_body.cc",
+    "net/http_body.h",
+    "net/http_body_gzip.cc",
+    "net/http_body_gzip.h",
+    "net/http_headers.h",
+    "net/http_multipart_builder.cc",
+    "net/http_multipart_builder.h",
+    "net/http_transport.cc",
+    "net/http_transport.h",
+    "net/url.cc",
+    "net/url.h",
+  ]
+
+  deps = [
+    ":util",
+    "$mini_chromium_source_parent:base",
+  ]
+
+  if (crashpad_is_mac && !crashpad_is_in_fuchsia) {
+    sources += [ "net/http_transport_mac.mm" ]
+  }
+
+  if (crashpad_is_ios) {
+    sources += [ "net/http_transport_mac.mm" ]
+  }
+
+  if (crashpad_is_win) {
+    sources += [ "net/http_transport_win.cc" ]
+  }
+
+  if (crashpad_http_transport_impl == "socket") {
+    sources += [ "net/http_transport_socket.cc" ]
+    if (crashpad_use_boringssl_for_http_transport_socket) {
+      defines += [ "CRASHPAD_USE_BORINGSSL" ]
+
+      if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) {
+        deps += [ "//third_party/boringssl" ]
+      } else {
+        libs = [
+          "crypto",
+          "ssl",
+        ]
+      }
+    }
+  } else if (crashpad_http_transport_impl == "libcurl") {
+    sources += [ "net/http_transport_libcurl.cc" ]
+    if (crashpad_is_in_fuchsia) {
+      # Host Linux builds in Fuchsia don't have libcurl in a sysroot.
+      deps += [ "//third_party/curl:libcurl" ]
+    }
+  }
+}
+
 if (!crashpad_is_android && !crashpad_is_ios) {
   crashpad_executable("http_transport_test_server") {
     testonly = true
     sources = [ "net/http_transport_test_server.cc" ]
 
     deps = [
+      ":net",
       ":util",
       "$mini_chromium_source_parent:base",
       "../third_party/cpp-httplib",
@@ -874,6 +896,7 @@
   ]
 
   deps = [
+    ":net",
     ":util",
     "$mini_chromium_source_parent:base",
     "../client",
diff --git a/third_party/crashpad/crashpad/util/misc/metrics.h b/third_party/crashpad/crashpad/util/misc/metrics.h
index 63c673a..dcd37a6 100644
--- a/third_party/crashpad/crashpad/util/misc/metrics.h
+++ b/third_party/crashpad/crashpad/util/misc/metrics.h
@@ -89,6 +89,10 @@
     //!     and uploading it to the crash server.
     kPrepareForUploadFailed = 5,
 
+    //! \brief The upload of the crash failed during communication with the
+    //!     server, but the upload can be retried later.
+    kUploadFailedButCanRetry = 6,
+
     //! \brief The number of values in this enumeration; not a valid value.
     kMaxValue
   };
diff --git a/third_party/crashpad/crashpad/util/misc/uuid.cc b/third_party/crashpad/crashpad/util/misc/uuid.cc
index 32ffea52..4ed3831 100644
--- a/third_party/crashpad/crashpad/util/misc/uuid.cc
+++ b/third_party/crashpad/crashpad/util/misc/uuid.cc
@@ -43,6 +43,10 @@
   return memcmp(this, &that, sizeof(*this)) == 0;
 }
 
+bool UUID::operator<(const UUID& that) const {
+  return memcmp(this, &that, sizeof(*this)) < 0;
+}
+
 void UUID::InitializeToZero() {
   memset(this, 0, sizeof(*this));
 }
diff --git a/third_party/crashpad/crashpad/util/misc/uuid.h b/third_party/crashpad/crashpad/util/misc/uuid.h
index 291baa9..7e504a2 100644
--- a/third_party/crashpad/crashpad/util/misc/uuid.h
+++ b/third_party/crashpad/crashpad/util/misc/uuid.h
@@ -39,6 +39,7 @@
 struct UUID {
   bool operator==(const UUID& that) const;
   bool operator!=(const UUID& that) const { return !operator==(that); }
+  bool operator<(const UUID& that) const;
 
   //! \brief Initializes the %UUID to zero.
   void InitializeToZero();
diff --git a/third_party/crashpad/crashpad/util/misc/uuid_test.cc b/third_party/crashpad/crashpad/util/misc/uuid_test.cc
index 936e76b..28d7ce4 100644
--- a/third_party/crashpad/crashpad/util/misc/uuid_test.cc
+++ b/third_party/crashpad/crashpad/util/misc/uuid_test.cc
@@ -85,24 +85,40 @@
   EXPECT_EQ(uuid_2, uuid);
   EXPECT_FALSE(uuid != uuid_2);
 
+  // Test operator< operator
+  UUID uuid_3{};
+  UUID uuid_4;
+  uuid_4.InitializeFromString("11111111-1111-1111-1111-111111111111");
+  UUID uuid_5;
+  uuid_5.InitializeFromString("22222222-2222-2222-2222-222222222222");
+
+  EXPECT_LT(uuid_3, uuid_4);
+  EXPECT_LT(uuid_3, uuid_5);
+  EXPECT_LT(uuid_4, uuid_5);
+
   // Make sure that operator== and operator!= check the entire UUID.
   ++uuid.data_1;
   EXPECT_NE(uuid, uuid_2);
+  EXPECT_LT(uuid_2, uuid);
   --uuid.data_1;
   ++uuid.data_2;
   EXPECT_NE(uuid, uuid_2);
+  EXPECT_LT(uuid_2, uuid);
   --uuid.data_2;
   ++uuid.data_3;
   EXPECT_NE(uuid, uuid_2);
+  EXPECT_LT(uuid_2, uuid);
   --uuid.data_3;
   for (size_t index = 0; index < base::size(uuid.data_4); ++index) {
     ++uuid.data_4[index];
     EXPECT_NE(uuid, uuid_2);
+    EXPECT_LT(uuid_2, uuid);
     --uuid.data_4[index];
   }
   for (size_t index = 0; index < base::size(uuid.data_5); ++index) {
     ++uuid.data_5[index];
     EXPECT_NE(uuid, uuid_2);
+    EXPECT_LT(uuid_2, uuid);
     --uuid.data_5[index];
   }
 
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 7da0748..6ca8e68d 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-11-0-172-g9079c5d91
-Revision: 9079c5d91aa87bcae223fc933b9c0ebf346b7d64
+Version: VER-2-11-0-180-g81912a138
+Revision: 81912a1385e8fc7694eda820221e15745cdcada4
 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/freetype/include/freetype-custom/freetype/config/public-macros.h b/third_party/freetype/include/freetype-custom/freetype/config/public-macros.h
index 058312e8..60ccb49 100644
--- a/third_party/freetype/include/freetype-custom/freetype/config/public-macros.h
+++ b/third_party/freetype/include/freetype-custom/freetype/config/public-macros.h
@@ -112,11 +112,16 @@
    * Support for casts in both C and C++.
    */
 #ifdef __cplusplus
-#define FT_STATIC_CAST( type )       static_cast<type>
-#define FT_REINTERPRET_CAST( type )  reinterpret_cast<type>
+#define FT_STATIC_CAST( type, var )       static_cast<type>(var)
+#define FT_REINTERPRET_CAST( type, var )  reinterpret_cast<type>(var)
+
+#define FT_STATIC_BYTE_CAST( type, var )                         \
+          static_cast<type>( static_cast<unsigned char>( var ) )
 #else
-#define FT_STATIC_CAST( type )       (type)
-#define FT_REINTERPRET_CAST( type )  (type)
+#define FT_STATIC_CAST( type, var )       (type)(var)
+#define FT_REINTERPRET_CAST( type, var )  (type)(var)
+
+#define FT_STATIC_BYTE_CAST( type, var )  (type)(unsigned char)(var)
 #endif
 
 
diff --git a/third_party/wuffs/README.chromium b/third_party/wuffs/README.chromium
index 69e735a1f..170280d 100644
--- a/third_party/wuffs/README.chromium
+++ b/third_party/wuffs/README.chromium
@@ -1,8 +1,8 @@
 Name: Wuffs (Wrangling Untrusted File Formats Safely)
 Short name: Wuffs
 URL: https://github.com/google/wuffs-mirror-release-c
-Version: 0.3.0-beta.9
-Revision: c9d2ed7983381ab659a56e0b8bc0d077e421f697
+Version: 0.3.0-beta.12
+Revision: a0e2454f0c21369f9775cad3bcaf1e3bb1db70b6
 Security critical: yes
 License: Apache 2.0
 
diff --git a/tools/binary_size/libsupersize/apkanalyzer.py b/tools/binary_size/libsupersize/apkanalyzer.py
index 226fd348..2285241 100644
--- a/tools/binary_size/libsupersize/apkanalyzer.py
+++ b/tools/binary_size/libsupersize/apkanalyzer.py
@@ -38,9 +38,16 @@
     args.extend(['--proguard-mappings', mapping_path])
   env = os.environ.copy()
   env['JAVA_HOME'] = path_util.GetJavaHome()
-  output = subprocess.check_output(args, env=env).decode('ascii')
+  result = subprocess.run(args,
+                          env=env,
+                          encoding='utf8',
+                          capture_output=True,
+                          check=True)
+  stderr = re.sub(r'Successfully loaded.*?\n', '', result.stderr)
+  if stderr.strip():
+    raise Exception('Unexpected stderr:\n' + stderr)
   data = []
-  for line in output.splitlines():
+  for line in result.stdout.splitlines():
     try:
       vals = line.split()
       # We want to name these columns so we know exactly which is which.
diff --git a/tools/clang/rewrite_raw_ptr_fields/RewriteRawPtrFields.cpp b/tools/clang/rewrite_raw_ptr_fields/RewriteRawPtrFields.cpp
index d49ff34d..9bb437c 100644
--- a/tools/clang/rewrite_raw_ptr_fields/RewriteRawPtrFields.cpp
+++ b/tools/clang/rewrite_raw_ptr_fields/RewriteRawPtrFields.cpp
@@ -1112,9 +1112,11 @@
   //
   // See also testcases in tests/affected-expr-original.cc
   auto templated_function_arg_matcher = forEachArgumentWithParam(
-      affected_expr_matcher, parmVarDecl(hasType(qualType(allOf(
-                                 findAll(qualType(substTemplateTypeParmType())),
-                                 unless(referenceType()))))));
+      affected_expr_matcher,
+      parmVarDecl(allOf(
+          hasType(qualType(allOf(findAll(qualType(substTemplateTypeParmType())),
+                                 unless(referenceType())))),
+          unless(hasAncestor(functionDecl(hasName("Unretained")))))));
   match_finder.addMatcher(callExpr(templated_function_arg_matcher),
                           &affected_expr_rewriter);
   // TODO(lukasza): It is unclear why |traverse| below is needed.  Maybe it can
diff --git a/tools/clang/rewrite_raw_ptr_fields/manual-fields-to-ignore.txt b/tools/clang/rewrite_raw_ptr_fields/manual-fields-to-ignore.txt
index 8ee9c390..327ae6a4 100644
--- a/tools/clang/rewrite_raw_ptr_fields/manual-fields-to-ignore.txt
+++ b/tools/clang/rewrite_raw_ptr_fields/manual-fields-to-ignore.txt
@@ -44,6 +44,27 @@
 blink::PersistentBase::raw_
 blink::SVGFilterBuilder::last_effect_
 
+# Populated manually - missing |.get()| in not-rewritten platform specific code
+viz::OverlayCandidate::rpdq
+viz::CALayerOverlay::rpdq
+viz::DrawQuad::shared_quad_state
+content::RenderWidgetHostInputEventRouter::wheel_target_
+NavigateParams::navigated_or_inserted_contents
+web_app::WebAppTabStripBrowserTest::App::web_contents
+policy::ChromePolicyConversionsClient::profile_
+
+# Populated manually - reference to raw_ptr in not-rewritten platform specific code
+viz::DirectRenderer::DrawingFrame::current_render_pass
+TabGroupViews::header_
+TabGroupViews::underline_
+TabGroupViews::highlight_
+
+# Populated manually - incompatibilities with tracing in not-rewritten platform specific code
+TabStripModelChange::RemovedTab::contents
+
+# Populated manually - extra .get() added in not-rewritten platform specific code
+SECItem::data
+
 # Populated manually - the rewriter has trouble appending |.get()| inside macros
 # that work with |XDisplay*|.
 extensions::GlobalShortcutListenerX11::x_display_
@@ -186,6 +207,10 @@
 device::RSAPublicKey::ExtractFromCOSEKey(int32_t, base::span<const uint8_t>, const cbor::Value::MapValue &)::COSEKey::n
 device::RSAPublicKey::ExtractFromCOSEKey(int32_t, base::span<const uint8_t>, const cbor::Value::MapValue &)::COSEKey::e
 
+# Populated manually - pointer to Objective-C object
+gfx::ScopedNSGraphicsContextSaveGState::context_
+base::mac::ScopedNSAutoreleasePool::autorelease_pool_
+
 #######
 # BackupRefPtr-specific sections
 #######
diff --git a/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-expected.cc b/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-expected.cc
index 53fcad5..8e348301 100644
--- a/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-expected.cc
+++ b/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-expected.cc
@@ -222,10 +222,7 @@
 // We also want to append |.get()| for |T| parameters (i.e. not just for |T*|
 // parameters).
 //
-// One motivating example is ActivityLogDatabasePolicy::ScheduleAndForget which
-// passes its argument to base::Unretained.
-//
-// Another motivating example, is the following pattern from
+// One motivating example is the following pattern from
 // //components/variations/service/ui_string_overrider.cc where the type of the
 // 2 arguments needs to be kept consistent:
 //     const uint32_t* end = ptr_field_ + num_resources_;
@@ -233,6 +230,15 @@
 template <typename T>
 void AffectedNonPointerFunction(T t) {}
 
+// base::Unretained has a template specialization that accepts `const
+// raw_ptr<T>&` as an argument (since https://crrev.com/c/3283196).  Therefore
+// we expect that `.get()` is *not* used when calling base::Unretained.
+//
+// Originally, ActivityLogDatabasePolicy::ScheduleAndForget was used as a
+// motivating example - passes a raw_ptr to base::Unretained.
+template <typename T>
+void Unretained(T* t) {}
+
 // AffectedFunctionWithDeepT mimics ConvertPPResourceArrayToObjects from
 // //ppapi/cpp/array_output.h
 template <typename T>
@@ -271,6 +277,11 @@
   // No rewrite expected - T& parameter.
   std::swap(my_struct.ptr, my_struct.ptr2);
   std::tie(my_struct.ptr, my_struct.ptr2) = std::make_pair(nullptr, nullptr);
+
+  // No rewrite expected - functions named "Unretained" are excluded (they have
+  // been manually modified to also provide a template specialization that
+  // accepts `const raw_ptr<T>&` as an argument).
+  Unretained(my_struct.ptr);
 }
 
 }  // namespace templated_functions
diff --git a/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-original.cc b/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-original.cc
index 472a280..5acdf850 100644
--- a/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-original.cc
+++ b/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-original.cc
@@ -220,10 +220,7 @@
 // We also want to append |.get()| for |T| parameters (i.e. not just for |T*|
 // parameters).
 //
-// One motivating example is ActivityLogDatabasePolicy::ScheduleAndForget which
-// passes its argument to base::Unretained.
-//
-// Another motivating example, is the following pattern from
+// One motivating example is the following pattern from
 // //components/variations/service/ui_string_overrider.cc where the type of the
 // 2 arguments needs to be kept consistent:
 //     const uint32_t* end = ptr_field_ + num_resources_;
@@ -231,6 +228,15 @@
 template <typename T>
 void AffectedNonPointerFunction(T t) {}
 
+// base::Unretained has a template specialization that accepts `const
+// raw_ptr<T>&` as an argument (since https://crrev.com/c/3283196).  Therefore
+// we expect that `.get()` is *not* used when calling base::Unretained.
+//
+// Originally, ActivityLogDatabasePolicy::ScheduleAndForget was used as a
+// motivating example - passes a raw_ptr to base::Unretained.
+template <typename T>
+void Unretained(T* t) {}
+
 // AffectedFunctionWithDeepT mimics ConvertPPResourceArrayToObjects from
 // //ppapi/cpp/array_output.h
 template <typename T>
@@ -269,6 +275,11 @@
   // No rewrite expected - T& parameter.
   std::swap(my_struct.ptr, my_struct.ptr2);
   std::tie(my_struct.ptr, my_struct.ptr2) = std::make_pair(nullptr, nullptr);
+
+  // No rewrite expected - functions named "Unretained" are excluded (they have
+  // been manually modified to also provide a template specialization that
+  // accepts `const raw_ptr<T>&` as an argument).
+  Unretained(my_struct.ptr);
 }
 
 }  // namespace templated_functions
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py
index 3ac1958..23598b1 100755
--- a/tools/clang/scripts/package.py
+++ b/tools/clang/scripts/package.py
@@ -305,9 +305,6 @@
         # Copy the stdlibc++.so.6 we linked the binaries against.
         'lib/libstdc++.so.6',
 
-        # dwp needed for use_debug_fission.
-        'bin/llvm-dwp',
-
         # Add llvm-objcopy for partition extraction on Android.
         'bin/llvm-objcopy',
 
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 9a8bae5..b3acd14 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -35,7 +35,7 @@
 # Reverting problematic clang rolls is safe, though.
 # This is the output of `git describe` and is usable as a commit-ish.
 CLANG_REVISION = 'llvmorg-14-init-8564-g34b903d8'
-CLANG_SUB_REVISION = 2
+CLANG_SUB_REVISION = 4
 
 PACKAGE_VERSION = '%s-%s' % (CLANG_REVISION, CLANG_SUB_REVISION)
 RELEASE_VERSION = '14.0.0'
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 069481e..08222ad 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -954,13 +954,13 @@
 
     'tryserver.chromium.dawn': {
       'dawn-linux-x64-deps-rel': 'dawn_tests_with_desktop_gl_release_trybot',
-      'dawn-mac-x64-deps-rel': 'dawn_tests_release_trybot',
-      'dawn-try-mac-amd-exp': 'dawn_tests_release_trybot',
+      'dawn-mac-x64-deps-rel': 'dawn_tests_release_trybot_alloc_none',
+      'dawn-try-mac-amd-exp': 'dawn_tests_release_trybot_alloc_none',
       'dawn-try-mac-intel-exp': 'dawn_tests_release_trybot',
       'dawn-win10-x86-deps-rel': 'dawn_tests_release_trybot_x86',
       'dawn-win10-x64-deps-rel': 'dawn_tests_release_trybot',
       'linux-dawn-rel': 'dawn_tests_with_desktop_gl_release_trybot',
-      'mac-dawn-rel': 'dawn_tests_release_trybot',
+      'mac-dawn-rel': 'dawn_tests_release_trybot_alloc_none',
       'win-dawn-rel': 'dawn_tests_release_trybot',
       'dawn-try-win10-x86-rel': 'dawn_tests_release_trybot_x86',
       'dawn-try-win10-x64-asan-rel': 'dawn_tests_asan_release_trybot',
@@ -2107,6 +2107,12 @@
       'dawn_tests', 'release_trybot',
     ],
 
+    # https://crbug.com/dawn/1200: temporarily avoid using partition alloc
+    # while we investigate a crash in the mac AMD shader compiler.
+    'dawn_tests_release_trybot_alloc_none': [
+      'dawn_tests', 'release_trybot', 'padisabled',
+    ],
+
     'dawn_tests_release_trybot_x86': [
       'dawn_tests', 'release_trybot', 'x86',
     ],
@@ -3757,6 +3763,12 @@
       'gn_args': 'ozone_platform_x11=false'
     },
 
+    # https://crbug.com/dawn/1200: Used to disable partition alloc while we
+    # investigate a crash in the mac AMD shader compiler.
+    'padisabled': {
+      'gn_args': 'use_allocator="none"',
+    },
+
     'paeverywhere': {
       'gn_args': 'use_allocator="partition"',
     },
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.dawn.json b/tools/mb/mb_config_expectations/tryserver.chromium.dawn.json
index 6c541d53..f6ba12d8 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.dawn.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.dawn.json
@@ -20,6 +20,7 @@
       "is_component_build": false,
       "is_debug": false,
       "symbol_level": 0,
+      "use_allocator": "none",
       "use_dawn": true,
       "use_goma": true
     }
@@ -32,6 +33,7 @@
       "is_component_build": false,
       "is_debug": false,
       "symbol_level": 0,
+      "use_allocator": "none",
       "use_dawn": true,
       "use_goma": true
     }
@@ -120,6 +122,7 @@
       "is_component_build": false,
       "is_debug": false,
       "symbol_level": 0,
+      "use_allocator": "none",
       "use_dawn": true,
       "use_goma": true
     }
diff --git a/tools/metrics/actions/extract_actions.py b/tools/metrics/actions/extract_actions.py
index 8cfd916..cba37db 100755
--- a/tools/metrics/actions/extract_actions.py
+++ b/tools/metrics/actions/extract_actions.py
@@ -97,21 +97,13 @@
 # generate the known actions to AddComputedActions() below.
 KNOWN_COMPUTED_USERS = (
     'back_forward_menu_model.cc',
-    'options_page_view.cc',
-    'render_view_host.cc',  # called using webkit identifiers
     'user_metrics.cc',  # method definition
-    'new_tab_ui.cc',  # most visited clicks 1-9
-    'extension_metrics_module.cc',  # extensions hook for user metrics
     'external_metrics.cc',  # see AddChromeOSActions()
-    'core_options_handler.cc',  # see AddWebUIActions()
-    'browser_render_process_host.cc',  # see AddRendererActions()
     'render_thread_impl.cc',  # impl of RenderThread::RecordComputedAction()
     'render_process_host_impl.cc',  # browser side impl for
     # RenderThread::RecordComputedAction()
     'mock_render_thread.cc',  # mock of RenderThread::RecordComputedAction()
-    'ppb_pdf_impl.cc',  # see AddClosedSourceActions()
     'pepper_pdf_host.cc',  # see AddClosedSourceActions()
-    'record_user_action.cc',  # see RecordUserAction.java
     'blink_platform_impl.cc',  # see WebKit/public/platform/Platform.h
     'devtools_ui_bindings.cc',  # see AddDevToolsActions()
     'sharing_hub_bubble_controller.cc',  # share targets
@@ -150,10 +142,6 @@
       actions.add(dir + 'HistoryClick' + str(i))
       actions.add(dir + 'ChapterClick' + str(i))
 
-  # Actions for new_tab_ui.cc.
-  for i in range(1, 10):
-    actions.add('MostVisited%d' % i)
-
   # Actions for sharing_hub_bubble_controller.cc and
   # sharing_hub_sub_menu_model.cc.
   for share_target in SHARE_TARGETS:
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index ba0a25f..fc2e1f3b 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -27620,6 +27620,9 @@
   <int value="5"
       label="Yes in browser BackForwardCacheImpl::RestoreEntry succeed"/>
   <int value="6" label="Yes in browser RenderFrameHostManager::CommitPending"/>
+  <int value="7" label="Yes in browser seen in renderer"/>
+  <int value="8" label="Yes in browser seen in renderer with Page"/>
+  <int value="9" label="Yes in browser seen in ACK to browser"/>
 </enum>
 
 <enum name="EventPreFilterResult">
@@ -43970,7 +43973,7 @@
   <int value="9" label="Canceled"/>
 </enum>
 
-<enum name="InProductHelp.SnoozeAction">
+<enum name="InProductHelpSnoozeAction">
   <int value="0" label="Unknown"/>
   <int value="1" label="Snooze"/>
   <int value="2" label="Dismiss"/>
@@ -49859,6 +49862,7 @@
   <int value="-1179917414" label="DefaultChromeAppUninstallSync:disabled"/>
   <int value="-1178350793" label="RemoteCopyReceiver:disabled"/>
   <int value="-1177802205" label="enable-hosted-app-quit-notification"/>
+  <int value="-1177230990" label="PrefetchAndroidFonts:enabled"/>
   <int value="-1176748003"
       label="FramebustingNeedsSameOriginOrUserGesture:disabled"/>
   <int value="-1176493523" label="enable-md-extensions"/>
@@ -50490,6 +50494,7 @@
   <int value="-705212373" label="IncognitoNtpRevamp:disabled"/>
   <int value="-704459022" label="ContinuousSearch:enabled"/>
   <int value="-704232562" label="UseMonitorColorSpace:enabled"/>
+  <int value="-703552662" label="PrefetchAndroidFonts:disabled"/>
   <int value="-702477233" label="ContentFullscreen:enabled"/>
   <int value="-700762821" label="RequestDesktopSiteForTablets:disabled"/>
   <int value="-700300613" label="use-fake-device-for-media-stream:disabled"/>
@@ -57563,6 +57568,24 @@
   </int>
 </enum>
 
+<enum name="MimeTypeOfHlsManifest">
+  <summary>
+    Captures the MIME type of the HTTP response that carried an HLS manifest.
+  </summary>
+  <int value="0" label="Other MIME type"/>
+  <int value="1" label="application/dash+xml"/>
+  <int value="2" label="application/ogg"/>
+  <int value="3" label="application/mpegurl"/>
+  <int value="4" label="application/vnd.apple.mpegurl"/>
+  <int value="5" label="application/x-mpegurl"/>
+  <int value="6" label="audio/mpegurl"/>
+  <int value="7" label="audio/x-mpegurl"/>
+  <int value="8" label="audio/*"/>
+  <int value="9" label="image/*"/>
+  <int value="10" label="video/*"/>
+  <int value="11" label="text/vtt"/>
+</enum>
+
 <enum name="MirrorFailureType">
   <int value="0" label="Capture Tab failed due to empty stream"/>
   <int value="1" label="Capture Desktop failed due to timeout"/>
diff --git a/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS b/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
index 3b317ce..2351791 100644
--- a/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
+++ b/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
@@ -72,6 +72,7 @@
 vsemeniuk@google.com
 wanderview@chromium.org
 wychen@chromium.org
+xiaohuic@chromium.org
 xinghuilu@chromium.org
 yashard@chromium.org
 yigu@chromium.org
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index a5dae65..4970654 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -1380,10 +1380,20 @@
   </summary>
 </histogram>
 
+<histogram name="Android.FontLookup.FetchAllFontFiles.Time" units="ms"
+    expires_after="2022-05-01">
+  <owner>twellington@chromium.org</owner>
+  <owner>clank-app-team@google.com</owner>
+  <summary>
+    Records the time taken to fetch all available font files from the GMS Core
+    Android downloadable font provider.
+  </summary>
+</histogram>
+
 <histogram name="Android.FontLookup.FetchFontName" enum="FetchFontName"
     expires_after="2022-04-24">
-  <owner>chouinard@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
+  <owner>clank-app-team@google.com</owner>
   <summary>
     Records font fetch requests by font name. These results may be used to
     determine whether it remains worthwhile to preload fonts that are available
@@ -1393,8 +1403,8 @@
 
 <histogram name="Android.FontLookup.FetchFontResult" enum="FetchFontResult"
     expires_after="2022-05-01">
-  <owner>chouinard@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
+  <owner>clank-app-team@google.com</owner>
   <summary>
     Records the result of font fetch requests made to the GMS Core Android
     downloadable font provider. The result may be success, or failure with a
@@ -1405,8 +1415,8 @@
 
 <histogram name="Android.FontLookup.GmsFontRequest.Time" units="ms"
     expires_after="2022-05-01">
-  <owner>chouinard@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
+  <owner>clank-app-team@google.com</owner>
   <summary>
     Records the time taken to make a fetchFonts font request to GMS Core via the
     Android downloadable font provider API. This metric may be used to determine
@@ -1417,8 +1427,8 @@
 
 <histogram name="Android.FontLookup.MatchLocalFontByUniqueName.Time" units="ms"
     expires_after="2022-05-01">
-  <owner>chouinard@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
+  <owner>clank-app-team@google.com</owner>
   <summary>
     Records the time taken to respond to a request from the renderer to fetch a
     specific font file from the GMS Core Android downloadable font provider.
@@ -2866,6 +2876,74 @@
   </summary>
 </histogram>
 
+<histogram name="Android.StartupTabPreloader.ActivityStartToLoadDecision"
+    units="ms" expires_after="2022-09-01">
+  <owner>blundell@chromium.org</owner>
+  <owner>yfriedman@chromium.org</owner>
+  <summary>
+    The time in a cold start between the start of the activity and the
+    triggerpoint for a startup tab being preloaded.
+  </summary>
+</histogram>
+
+<histogram
+    name="Android.StartupTabPreloader.LoadDecisionToFirstContentfulPaint.{LoadAndMatchResult}"
+    units="ms" expires_after="2022-09-01">
+  <owner>blundell@chromium.org</owner>
+  <owner>yfriedman@chromium.org</owner>
+  <summary>
+    The time in a cold start between the triggerpoint for a startup tab being
+    preloaded and Android.Startup.Cold.TimeToFirstContentfulPaint being
+    recorded, recorded in the case where a startup tab preload is determined
+    {LoadAndMatchResult}. In the case where the ElideTabPreloadAtStartup feature
+    is enabled, this metric will be segmented to reflect the state that would
+    have resulted if tab preloading was not disabled by the feature.
+  </summary>
+  <token key="LoadAndMatchResult">
+    <variant name="LoadAndMatch"
+        summary="to be viable and the preload is a match for the actual
+                 initial load"/>
+    <variant name="LoadAndMismatch"
+        summary="to be viable and the preload is not a match for the actual
+                 initial load"/>
+    <variant name="LoadPreMatch"
+        summary="to be viable and first contentful paint is recorded before
+                 it was determined whether the preload was a match for the
+                 actual initial load. Note that it is not expected that this
+                 case occurs in practice, but it is theoretically possible"/>
+    <variant name="NoLoad" summary="not to be viable"/>
+  </token>
+</histogram>
+
+<histogram
+    name="Android.StartupTabPreloader.LoadDecisionToFirstNavigationCommit.{LoadAndMatchResult}"
+    units="ms" expires_after="2022-09-01">
+  <owner>blundell@chromium.org</owner>
+  <owner>yfriedman@chromium.org</owner>
+  <summary>
+    The time in a cold start between the triggerpoint for a startup tab being
+    preloaded and Android.Startup.Cold.TimeToFirstNavigationCommit being
+    recorded, recorded in the case where a startup tab preload is determined
+    {LoadAndMatchResult}. In the case where the ElideTabPreloadAtStartup feature
+    is enabled, this metric will be segmented to reflect the state that would
+    have resulted if tab preloading was not disabled by the feature.
+  </summary>
+  <token key="LoadAndMatchResult">
+    <variant name="LoadAndMatch"
+        summary="to be viable and the preload is a match for the actual
+                 initial load"/>
+    <variant name="LoadAndMismatch"
+        summary="to be viable and the preload is not a match for the actual
+                 initial load"/>
+    <variant name="LoadPreMatch"
+        summary="to be viable and first navigation commit is recorded before
+                 it was determined whether the preload was a match for the
+                 actual initial load. Note that it is not expected that this
+                 case occurs in practice, but it is theoretically possible"/>
+    <variant name="NoLoad" summary="not to be viable"/>
+  </token>
+</histogram>
+
 <histogram
     name="Android.StartupTabPreloader.LoadDecisionToFirstNavigationStart.{LoadDecision}"
     units="ms" expires_after="2022-09-01">
@@ -2874,7 +2952,10 @@
   <summary>
     The time in a cold start between the triggerpoint for a startup tab being
     preloaded and first navigation start, recorded in the case where a startup
-    tab preload is determined {LoadDecision} viable.
+    tab preload is determined {LoadDecision} viable. In the case where the
+    ElideTabPreloadAtStartup feature is enabled, this metric will be segmented
+    to reflect the state that would have resulted if tab preloading was not
+    disabled by the feature.
   </summary>
   <token key="LoadDecision">
     <variant name="Load" summary="to be"/>
@@ -2891,7 +2972,9 @@
     The time in a cold start between the triggerpoint for a startup tab being
     preloaded and Android.Startup.Cold.TimeToFirstVisibleContent being recorded,
     recorded in the case where a startup tab preload is determined
-    {LoadAndMatchResult}.
+    {LoadAndMatchResult}. In the case where the ElideTabPreloadAtStartup feature
+    is enabled, this metric will be segmented to reflect the state that would
+    have resulted if tab preloading was not disabled by the feature.
   </summary>
   <token key="LoadAndMatchResult">
     <variant name="LoadAndMatch"
@@ -2909,6 +2992,26 @@
   </token>
 </histogram>
 
+<histogram
+    name="Android.StartupTabPreloader.LoadDecisionToMatchDecision.{LoadDecision}"
+    units="ms" expires_after="2022-09-01">
+  <owner>blundell@chromium.org</owner>
+  <owner>yfriedman@chromium.org</owner>
+  <summary>
+    The time in a cold start between the triggerpoint for a startup tab being
+    preloaded and the decision being made on whether the preload is a match for
+    the information of the actual initial load that needs to occur, recorded in
+    the case where a startup tab preload is determined {LoadDecision} viable. In
+    the case where the ElideTabPreloadAtStartup feature is enabled, this metric
+    will be segmented to reflect the state that would have resulted if tab
+    preloading was not disabled by the feature.
+  </summary>
+  <token key="LoadDecision">
+    <variant name="Load" summary="to be"/>
+    <variant name="NoLoad" summary="not to be"/>
+  </token>
+</histogram>
+
 <histogram name="Android.StrictMode.OverrideUrlLoadingTime" units="ms"
     expires_after="2022-04-24">
   <owner>yfriedman@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/assistant/OWNERS b/tools/metrics/histograms/metadata/assistant/OWNERS
new file mode 100644
index 0000000..8961bd82
--- /dev/null
+++ b/tools/metrics/histograms/metadata/assistant/OWNERS
@@ -0,0 +1,5 @@
+per-file OWNERS=file://tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
+
+# Prefer sending CLs to the owners listed below.
+# Use chromium-metrics-reviews@google.com as a backup.
+xiaohuic@chromium.org
diff --git a/tools/metrics/histograms/metadata/dev/histograms.xml b/tools/metrics/histograms/metadata/dev/histograms.xml
index 34e2857..c13b7f15 100644
--- a/tools/metrics/histograms/metadata/dev/histograms.xml
+++ b/tools/metrics/histograms/metadata/dev/histograms.xml
@@ -206,7 +206,7 @@
 </histogram>
 
 <histogram name="DevTools.ExperimentDisabled" enum="DevtoolsExperiments"
-    expires_after="2021-12-05">
+    expires_after="2022-04-24">
   <owner>yangguo@chromium.org</owner>
   <owner>brgoddar@microsoft.com</owner>
   <owner>shanejc@microsoft.com</owner>
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
index bf7e882..1902832 100644
--- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
+++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -298,7 +298,7 @@
 </histogram>
 
 <histogram name="InProductHelp.Db.Update.{IPHDatabase}" enum="BooleanSuccess"
-    expires_after="2021-12-26">
+    expires_after="2022-12-26">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
   <summary>
@@ -391,6 +391,15 @@
   <token key="IPHFeature" variants="IPHFeature"/>
 </histogram>
 
+<histogram name="InProductHelp.SnoozeAction" enum="InProductHelpSnoozeAction"
+    expires_after="2022-10-01">
+  <owner>haileywang@chromium.org</owner>
+  <owner>shaktisahu@chromium.org</owner>
+  <summary>
+    Records the action taken by the user on a snoozable in-product help bubble.
+  </summary>
+</histogram>
+
 <histogram name="InProductHelp.TextBubble.ShownTime" units="ms"
     expires_after="2022-10-01">
   <owner>haileywang@chromium.org</owner>
@@ -400,7 +409,7 @@
   </summary>
 </histogram>
 
-<histogram name="InProductHelp.TextBubble.ShowSnooze" enum="BooleanSuccess"
+<histogram name="InProductHelp.TextBubble.ShowSnooze" enum="BooleanShown"
     expires_after="2022-10-01">
   <owner>haileywang@chromium.org</owner>
   <owner>shaktisahu@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index 062303f..94b0c099 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -4811,6 +4811,16 @@
   </summary>
 </histogram>
 
+<histogram name="Media.VideoCapture.Win.D3DDeviceRemovedReason" enum="Hresult"
+    expires_after="2022-06-17">
+  <owner>ilnik@chromium.org</owner>
+  <owner>video-cmi-mpp@chromium.org</owner>
+  <summary>
+    Error codes received by VideoCaptureDeviceMFWin when checking for D3D11
+    device removal reason.
+  </summary>
+</histogram>
+
 <histogram name="Media.VideoCapture.Win.Device.CapturePixelFormat"
     enum="VideoPixelFormatUnion" expires_after="2022-05-01">
   <owner>ilnik@google.com</owner>
@@ -5279,6 +5289,25 @@
   </summary>
 </histogram>
 
+<histogram name="Media.WebMediaPlayerImpl.HLS{Variant}.MimeType"
+    enum="MimeTypeOfHlsManifest" expires_after="2022-06-01">
+  <owner>sandersd@chromium.org</owner>
+  <owner>lukasza@chromium.org</owner>
+  <summary>
+    When an HLS manifest is found during loading (on Android only), {Variant}
+    then this histogram records the MIME type of the response.
+
+    This metric should help assess the web compatibility risk of strict MIME
+    type enforcement, as discussed in
+    https://github.com/annevk/orb/issues/29#issuecomment-967432934
+  </summary>
+  <token key="Variant">
+    <variant name="" summary=""/>
+    <variant name=".CorsCrossOrigin"
+        summary="and the response is cross-origin/opaque,"/>
+  </token>
+</histogram>
+
 <histogram name="Media.WebMediaPlayerImpl.WatchTime"
     enum="WebMediaPlayerWatchTimeType" expires_after="2021-08-01">
   <owner>sandersd@chromium.org</owner>
@@ -5427,6 +5456,16 @@
   </summary>
 </histogram>
 
+<histogram name="MediaRouter.Cast.DeviceNameLength" units="characters"
+    expires_after="2022-05-01">
+  <owner>takumif@chromium.org</owner>
+  <owner>openscreen-eng@google.com</owner>
+  <summary>
+    Records the length of the friendly name of a Cast device when we succeed to
+    open a Cast channel to it.
+  </summary>
+</histogram>
+
 <histogram name="MediaRouter.Cast.Discovery.CachedSinksAvailableCount"
     units="devices" expires_after="2022-05-01">
   <owner>btolsch@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 86061c28..6fb4843 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -1793,8 +1793,9 @@
 
 <histogram name="Bookmarks.BookmarkAllTabsWithTabsCount.Incognito" units="tabs"
     expires_after="2022-05-01">
-  <owner>rhalavati@chromium.org</owner>
-  <owner>chrome-privacy-core@google.com</owner>
+  <owner>roagarwal@chromium.org</owner>
+  <owner>sideyilmaz@chromium.org</owner>
+  <owner>chrome-incognito@google.com</owner>
   <component>UI&gt;Browser&gt;Bookmarks</component>
   <summary>
     This histogram records the count of tabs when a user bookmarks all open
@@ -1803,9 +1804,10 @@
 </histogram>
 
 <histogram name="Bookmarks.BookmarkAllTabsWithTabsCount.Regular" units="tabs"
-    expires_after="2021-12-12">
-  <owner>rhalavati@chromium.org</owner>
-  <owner>chrome-privacy-core@google.com</owner>
+    expires_after="2022-05-01">
+  <owner>roagarwal@chromium.org</owner>
+  <owner>sideyilmaz@chromium.org</owner>
+  <owner>chrome-incognito@google.com</owner>
   <component>UI&gt;Browser&gt;Bookmarks</component>
   <summary>
     This histogram records the count of tabs when a user bookmarks all open
diff --git a/tools/perf/benchmarks/blink_perf_unittest.py b/tools/perf/benchmarks/blink_perf_unittest.py
index 6a522e7d..cedff51 100644
--- a/tools/perf/benchmarks/blink_perf_unittest.py
+++ b/tools/perf/benchmarks/blink_perf_unittest.py
@@ -47,6 +47,7 @@
     story_set.AddStory(blink_page)
     return story_set
 
+  @decorators.Disabled('chromeos')  # Flaky: https://crbug.com/1271916
   def testBlinkPerfTracingMetricsForMeasureTime(self):
     measurements = self.RunPageTest(
         self.blink_page_test, 'file://append-child-measure-time.html')
diff --git a/tools/perf/core/bot_platforms.py b/tools/perf/core/bot_platforms.py
index 65d58afa..977219b 100644
--- a/tools/perf/core/bot_platforms.py
+++ b/tools/perf/core/bot_platforms.py
@@ -489,6 +489,10 @@
 ])
 _FUCHSIA_PERF_FYI_BENCHMARK_CONFIGS = PerfSuite([
     _GetBenchmarkConfig('system_health.memory_desktop'),
+    _GetBenchmarkConfig('media.mobile')
+])
+_FUCHSIA_SHERLOCK_PERF_FYI_BENCHMARK_CONFIGS = PerfSuite([
+    _GetBenchmarkConfig('system_health.memory_desktop'),
     _GetBenchmarkConfig('rendering.mobile'),
     _GetBenchmarkConfig('media.mobile')
 ])
@@ -661,12 +665,13 @@
                                 10,
                                 'fuchsia',
                                 is_fyi=True)
-FUCHSIA_PERF_SHERLOCK_FYI = PerfPlatform('fuchsia-perf-sherlock-fyi',
-                                         '',
-                                         _FUCHSIA_PERF_FYI_BENCHMARK_CONFIGS,
-                                         6,
-                                         'fuchsia',
-                                         is_fyi=True)
+FUCHSIA_PERF_SHERLOCK_FYI = PerfPlatform(
+    'fuchsia-perf-sherlock-fyi',
+    '',
+    _FUCHSIA_SHERLOCK_PERF_FYI_BENCHMARK_CONFIGS,
+    6,
+    'fuchsia',
+    is_fyi=True)
 
 # Calibration bots
 LINUX_PERF_CALIBRATION = PerfPlatform(
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index e914e28..0ee5bfc 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@
             "remote_path": "perfetto_binaries/trace_processor_shell/linux_arm/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "win": {
-            "hash": "56cdfba852e499f10ac7c48088f3262e467edaa3",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/2cf84d0e9cd28fe5956c8c50b75f33c109e21c4d/trace_processor_shell.exe"
+            "hash": "05d5c503e1afca8501aa013849c2c44ecbb3a9fe",
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/03cb3fd2f9c1b7475bf3838ecdf014b786b791f3/trace_processor_shell.exe"
         },
         "mac": {
             "hash": "186a99c6b3924ba51d617233ae428a97bc45ac4f",
@@ -18,7 +18,7 @@
         },
         "linux": {
             "hash": "59990b7cb4121fe340b079e231b5bf289db1cf6b",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/514e743cbfd9ae549cb95d9c43a0a3bc1b188883/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/1ddb4ac023df5492842451b563e35033869ef5d6/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/core/shard_maps/fuchsia-perf-fyi_map.json b/tools/perf/core/shard_maps/fuchsia-perf-fyi_map.json
index e486e3c..72754eb 100644
--- a/tools/perf/core/shard_maps/fuchsia-perf-fyi_map.json
+++ b/tools/perf/core/shard_maps/fuchsia-perf-fyi_map.json
@@ -4,65 +4,62 @@
             "media.mobile": {
                 "abridged": false
             },
-            "rendering.mobile": {
-                "end": 24,
+            "system_health.memory_desktop": {
+                "end": 17,
                 "abridged": false
             }
         }
     },
     "1": {
         "benchmarks": {
-            "rendering.mobile": {
-                "begin": 24,
-                "end": 94,
+            "system_health.memory_desktop": {
+                "begin": 17,
+                "end": 27,
                 "abridged": false
             }
         }
     },
     "2": {
         "benchmarks": {
-            "rendering.mobile": {
-                "begin": 94,
-                "end": 164,
+            "system_health.memory_desktop": {
+                "begin": 27,
+                "end": 33,
                 "abridged": false
             }
         }
     },
     "3": {
         "benchmarks": {
-            "rendering.mobile": {
-                "begin": 164,
-                "end": 234,
+            "system_health.memory_desktop": {
+                "begin": 33,
+                "end": 41,
                 "abridged": false
             }
         }
     },
     "4": {
         "benchmarks": {
-            "rendering.mobile": {
-                "begin": 234,
-                "end": 305,
+            "system_health.memory_desktop": {
+                "begin": 41,
+                "end": 49,
                 "abridged": false
             }
         }
     },
     "5": {
         "benchmarks": {
-            "rendering.mobile": {
-                "begin": 305,
-                "end": 375,
+            "system_health.memory_desktop": {
+                "begin": 49,
+                "end": 53,
                 "abridged": false
             }
         }
     },
     "6": {
         "benchmarks": {
-            "rendering.mobile": {
-                "begin": 375,
-                "abridged": false
-            },
             "system_health.memory_desktop": {
-                "end": 11,
+                "begin": 53,
+                "end": 59,
                 "abridged": false
             }
         }
@@ -70,8 +67,8 @@
     "7": {
         "benchmarks": {
             "system_health.memory_desktop": {
-                "begin": 11,
-                "end": 26,
+                "begin": 59,
+                "end": 65,
                 "abridged": false
             }
         }
@@ -79,8 +76,8 @@
     "8": {
         "benchmarks": {
             "system_health.memory_desktop": {
-                "begin": 26,
-                "end": 33,
+                "begin": 65,
+                "end": 75,
                 "abridged": false
             }
         }
@@ -88,26 +85,26 @@
     "9": {
         "benchmarks": {
             "system_health.memory_desktop": {
-                "begin": 33,
+                "begin": 75,
                 "abridged": false
             }
         }
     },
     "extra_infos": {
-        "num_stories": 531,
-        "predicted_min_shard_time": 637.0,
-        "predicted_min_shard_index": 9,
-        "predicted_max_shard_time": 744.0,
-        "predicted_max_shard_index": 7,
-        "shard #0": 703.0,
-        "shard #1": 700,
-        "shard #2": 700,
-        "shard #3": 700,
-        "shard #4": 710,
-        "shard #5": 700,
-        "shard #6": 710,
-        "shard #7": 744.0,
-        "shard #8": 732.0,
-        "shard #9": 637.0
+        "num_stories": 96,
+        "predicted_min_shard_time": 609.0,
+        "predicted_min_shard_index": 5,
+        "predicted_max_shard_time": 736.0,
+        "predicted_max_shard_index": 0,
+        "shard #0": 736.0,
+        "shard #1": 660.0,
+        "shard #2": 636.0,
+        "shard #3": 729.0,
+        "shard #4": 714.0,
+        "shard #5": 609.0,
+        "shard #6": 696.0,
+        "shard #7": 678.0,
+        "shard #8": 630.0,
+        "shard #9": 615.0
     }
 }
\ No newline at end of file
diff --git a/tools/perf/core/shard_maps/timing_data/fuchsia-perf-fyi_timing.json b/tools/perf/core/shard_maps/timing_data/fuchsia-perf-fyi_timing.json
index 2cec223..77b61572 100644
--- a/tools/perf/core/shard_maps/timing_data/fuchsia-perf-fyi_timing.json
+++ b/tools/perf/core/shard_maps/timing_data/fuchsia-perf-fyi_timing.json
@@ -36,7 +36,7 @@
         "name": "media.mobile/video.html?src=tulip2.mp3&type=audio&seek"
     },
     {
-        "duration": "37.0",
+        "duration": "36.0",
         "name": "media.mobile/video.html?src=tulip2.mp4"
     },
     {
@@ -60,7 +60,7 @@
         "name": "media.mobile/video.html?src=tulip2.vp9.webm&background"
     },
     {
-        "duration": "36.0",
+        "duration": "35.0",
         "name": "media.mobile/video.html?src=tulip2.vp9.webm_WiFi"
     },
     {
@@ -72,10 +72,38 @@
         "name": "system_health.memory_desktop/browse:media:imgur"
     },
     {
-        "duration": "104.0",
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/browse:media:pinterest:2018"
+    },
+    {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/browse:media:tumblr:2018"
+    },
+    {
+        "duration": "106.0",
+        "name": "system_health.memory_desktop/browse:media:youtube:2019"
+    },
+    {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/browse:media:youtubetv:2019"
+    },
+    {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/browse:media:youtubetv_watch:2020"
+    },
+    {
+        "duration": "99.0",
         "name": "system_health.memory_desktop/browse:news:hackernews:2020"
     },
     {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/browse:news:nytimes:2020"
+    },
+    {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/browse:news:reddit:2020"
+    },
+    {
         "duration": "1.0",
         "name": "system_health.memory_desktop/browse:search:google:2020"
     },
@@ -84,6 +112,18 @@
         "name": "system_health.memory_desktop/browse:search:google_india:2021"
     },
     {
+        "duration": "131.0",
+        "name": "system_health.memory_desktop/browse:social:tumblr_infinite_scroll:2018"
+    },
+    {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/browse:social:twitter:2018"
+    },
+    {
+        "duration": "93.0",
+        "name": "system_health.memory_desktop/browse:social:twitter_infinite_scroll:2018"
+    },
+    {
         "duration": "50.0",
         "name": "system_health.memory_desktop/browse:tools:docs_scrolling"
     },
@@ -120,6 +160,18 @@
         "name": "system_health.memory_desktop/load:games:bubbles:2020"
     },
     {
+        "duration": "47.0",
+        "name": "system_health.memory_desktop/load:games:lazors"
+    },
+    {
+        "duration": "34.0",
+        "name": "system_health.memory_desktop/load:games:miniclip:2018"
+    },
+    {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/load:games:spychase:2018"
+    },
+    {
         "duration": "53.0",
         "name": "system_health.memory_desktop/load:media:9gag"
     },
@@ -128,6 +180,42 @@
         "name": "system_health.memory_desktop/load:media:dailymotion:2019"
     },
     {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/load:media:facebook_feed:desktop:2020"
+    },
+    {
+        "duration": "26.0",
+        "name": "system_health.memory_desktop/load:media:facebook_photos:2018"
+    },
+    {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/load:media:facebook_photos:desktop:2020"
+    },
+    {
+        "duration": "36.0",
+        "name": "system_health.memory_desktop/load:media:flickr:2018"
+    },
+    {
+        "duration": "24.0",
+        "name": "system_health.memory_desktop/load:media:google_images:2018"
+    },
+    {
+        "duration": "52.0",
+        "name": "system_health.memory_desktop/load:media:imgur:2018"
+    },
+    {
+        "duration": "35.0",
+        "name": "system_health.memory_desktop/load:media:soundcloud:2018"
+    },
+    {
+        "duration": "42.0",
+        "name": "system_health.memory_desktop/load:media:youtube:2018"
+    },
+    {
+        "duration": "27.0",
+        "name": "system_health.memory_desktop/load:media:youtubelivingroom:2020"
+    },
+    {
         "duration": "48.0",
         "name": "system_health.memory_desktop/load:news:bbc:2018"
     },
@@ -136,6 +224,30 @@
         "name": "system_health.memory_desktop/load:news:cnn:2020"
     },
     {
+        "duration": "43.0",
+        "name": "system_health.memory_desktop/load:news:flipboard"
+    },
+    {
+        "duration": "24.0",
+        "name": "system_health.memory_desktop/load:news:hackernews:2018"
+    },
+    {
+        "duration": "75.0",
+        "name": "system_health.memory_desktop/load:news:nytimes:2018"
+    },
+    {
+        "duration": "63.0",
+        "name": "system_health.memory_desktop/load:news:qq:2018"
+    },
+    {
+        "duration": "54.0",
+        "name": "system_health.memory_desktop/load:news:reddit:2018"
+    },
+    {
+        "duration": "32.0",
+        "name": "system_health.memory_desktop/load:news:wikipedia:2018"
+    },
+    {
         "duration": "32.0",
         "name": "system_health.memory_desktop/load:search:amazon:2018"
     },
@@ -144,6 +256,42 @@
         "name": "system_health.memory_desktop/load:search:baidu:2018"
     },
     {
+        "duration": "48.0",
+        "name": "system_health.memory_desktop/load:search:ebay:2018"
+    },
+    {
+        "duration": "36.0",
+        "name": "system_health.memory_desktop/load:search:flipkart:2018"
+    },
+    {
+        "duration": "25.0",
+        "name": "system_health.memory_desktop/load:search:google:2018"
+    },
+    {
+        "duration": "60.0",
+        "name": "system_health.memory_desktop/load:search:taobao:2018"
+    },
+    {
+        "duration": "53.0",
+        "name": "system_health.memory_desktop/load:search:yahoo:2018"
+    },
+    {
+        "duration": "26.0",
+        "name": "system_health.memory_desktop/load:search:yandex:2018"
+    },
+    {
+        "duration": "28.0",
+        "name": "system_health.memory_desktop/load:social:instagram:2018"
+    },
+    {
+        "duration": "31.0",
+        "name": "system_health.memory_desktop/load:social:pinterest:2019"
+    },
+    {
+        "duration": "38.0",
+        "name": "system_health.memory_desktop/load:social:vk:2018"
+    },
+    {
         "duration": "2.0",
         "name": "system_health.memory_desktop/load:tools:chat:2020"
     },
@@ -152,7 +300,43 @@
         "name": "system_health.memory_desktop/load:tools:docs:2019"
     },
     {
+        "duration": "27.0",
+        "name": "system_health.memory_desktop/load:tools:drive:2019"
+    },
+    {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/load:tools:gmail:2019"
+    },
+    {
+        "duration": "43.0",
+        "name": "system_health.memory_desktop/load:tools:stackoverflow:2018"
+    },
+    {
+        "duration": "46.0",
+        "name": "system_health.memory_desktop/load:tools:weather:2019"
+    },
+    {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/long_running:tools:gmail-background"
+    },
+    {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/long_running:tools:gmail-foreground"
+    },
+    {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/multitab:misc:typical24"
+    },
+    {
+        "duration": "2.0",
+        "name": "system_health.memory_desktop/multitab:misc:typical24:2018"
+    },
+    {
         "duration": "1.0",
         "name": "system_health.memory_desktop/play:media:google_play_music"
+    },
+    {
+        "duration": "63.0",
+        "name": "system_health.memory_desktop/play:media:soundcloud:2018"
     }
 ]
\ No newline at end of file
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 23af29e..cbe467b 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -534,6 +534,9 @@
 crbug.com/v8/11180 [ android ] system_health.pcscan/browse:news:cnn:2021 [ Skip ]
 crbug.com/v8/11180 [ desktop ] system_health.pcscan/browse:news:cnn:2021 [ Skip ]
 
+# Benchmark: system_health.webview_startup
+crbug.com/1271869 [ android-webview ] system_health.webview_startup/load:chrome:blank [ Skip ]
+
 # Benchmark: tab_switching.typical_25
 crbug.com/747026 [ mac ] tab_switching.typical_25/multitab:misc:typical24 [ Skip ]
 crbug.com/883731 [ win ] tab_switching.typical_25/multitab:misc:typical24 [ Skip ]
diff --git a/tools/resources/find_unused_assets.py b/tools/resources/find_unused_assets.py
index eec164a8..3c83a3e 100755
--- a/tools/resources/find_unused_assets.py
+++ b/tools/resources/find_unused_assets.py
@@ -295,16 +295,16 @@
     A set of image filepaths that are referenced by grd/grdp.
   """
   used_files = set()
-  maybe_unused_files = set()
   grd_files = set(get_all_ext_files('grd') + get_all_ext_files('grdp'))
   for grd_file in grd_files:
     grd_dir = os.path.dirname(grd_file)
-    cur_used_files = set()
+    cur_relpaths = set()
     grd_root = ET.parse(grd_file).getroot()
     for elem in itertools.chain(grd_root.iter('include'),
                                 grd_root.iter('structure')):
       relpath = elem.get('file')
       if relpath and relpath.endswith('.png'):
+        relpath = relpath.replace('\\', '/')
         relpath = relpath.replace(
             '${input_tools_root_dir}',
             'third_party/google_input_tools/src/chrome/os')
@@ -314,14 +314,15 @@
           logger.error('When processing %s got weird relpath: %s', grd_file,
                        relpath)
           raise ValueError('Unexpected relpath!')
-        cur_used_files.add(relpath)
-    for png_file in all_png_files:
-      if os.path.commonpath([grd_dir, png_file]) == grd_dir:
-        relpath = os.path.relpath(png_file, start=grd_dir)
-        if any(relpath.endswith(used) for used in cur_used_files):
+        rooted_filepath = os.path.normpath(os.path.join(grd_dir, relpath))
+        if rooted_filepath in all_png_files:
+          used_files.add(rooted_filepath)
+        cur_relpaths.add(relpath)
+    for relpath in cur_relpaths:
+      pattern = re.compile(grd_dir + r'/(default_\d+_percent/)?' + relpath)
+      for png_file in all_png_files:
+        if pattern.match(png_file):
           used_files.add(png_file)
-        else:
-          maybe_unused_files.add(png_file)
   return used_files
 
 
@@ -421,6 +422,38 @@
   return os.path.normpath(rooted_path)
 
 
+def find_images_used_by_markdown(all_png_files: Set[Text]) -> Set[Text]:
+  """Finds images used by markdown files.
+
+  Args:
+    all_png_files: The set of all PNG files, used to filter results.
+
+  Returns:
+    A set of image filepaths used by markdown files.
+  """
+  md_url_pattern = re.compile(r'\(([^\s\)]+\.png)[\s\)]')
+  md_files = list_files(['**/README', '**/*.md'])
+  used_files = set()
+  for md_file in md_files:
+    file_dir = os.path.dirname(md_file)
+    with open(md_file, 'rb') as f:
+      for match in md_url_pattern.finditer(f.read().decode('utf-8')):
+        url_relpath = match.group(1)
+        if url_relpath.startswith('http'):
+          continue
+        if url_relpath.startswith('/'):
+          rooted_filepath = url_relpath.lstrip('/')
+        else:
+          rooted_filepath = os.path.join(file_dir, url_relpath)
+        rooted_filepath = os.path.normpath(rooted_filepath)
+        if rooted_filepath in all_png_files:
+          used_files.add(rooted_filepath)
+        else:
+          logger.warning('PNG file %s does not exist, reffed in %s as %s',
+                         rooted_filepath, md_file, url_relpath)
+  return used_files
+
+
 def find_images_used_by_ios_imageset(all_png_files: Set[Text]
                                      ) -> Tuple[Set[Text], Set[Text]]:
   """Finds images used and unused by ios imagesets and friends.
@@ -509,6 +542,13 @@
   used_png_files |= used_by_css
   png_files -= used_png_files
 
+  # Find files used by markdown.
+  logger.info('Looking for usages by markdown files...')
+  used_by_markdown = find_images_used_by_markdown(all_png_files)
+  logger.info('Found %d PNG files used by markdown.', len(used_by_markdown))
+  used_png_files |= used_by_markdown
+  png_files -= used_png_files
+
   # Find images used by ios imagesets.
   logger.info('Looking for usages by ios imagesets...')
   used_by_imageset, unused_by_imageset = find_images_used_by_ios_imageset(
diff --git a/tools/style_variable_generator/base_generator.py b/tools/style_variable_generator/base_generator.py
index 0fe22e9..5fe0e84 100644
--- a/tools/style_variable_generator/base_generator.py
+++ b/tools/style_variable_generator/base_generator.py
@@ -35,6 +35,9 @@
     ALL = [LIGHT, DARK, DEBUG]
 
 
+RESERVED_SUFFIXES = ['_' + s for s in Modes.ALL + ['rgb', 'inverted']]
+
+
 class VariableType:
     COLOR = 'color'
     OPACITY = 'opacity'
@@ -49,10 +52,12 @@
 
 
 class ModeKeyedModel(object):
-    def __init__(self):
+    def __init__(self, generator):
         self.variables = collections.OrderedDict()
+        self.generator = generator
 
-    def Add(self, name, value_obj):
+    def Add(self, name, value_obj, context):
+        self.generator.SetVariableContext(name, context)
         if name not in self.variables:
             self.variables[name] = {}
 
@@ -61,7 +66,7 @@
                 value = self._CreateValue(value_obj[mode])
                 if mode == 'default':
                     mode = Modes.DEFAULT
-                assert mode in Modes.ALL
+                assert mode in Modes.ALL and mode not in self.variables[name]
                 self.variables[name][mode] = value
         else:
             self.variables[name][Modes.DEFAULT] = self._CreateValue(value_obj)
@@ -107,8 +112,8 @@
        e.g OpacityModel['disabled_opacity'][Modes.LIGHT] = Opacity(...)
     '''
 
-    def __init__(self):
-        super(OpacityModel, self).__init__()
+    def __init__(self, generator):
+        super(OpacityModel, self).__init__(generator)
 
     # Returns a float from 0-1 representing the concrete value of |opacity|.
     def ResolveOpacity(self, opacity, mode):
@@ -126,10 +131,45 @@
        e.g ColorModel['blue'][Modes.LIGHT] = Color(...)
     '''
 
-    def __init__(self, opacity_model):
-        super(ColorModel, self).__init__()
+    def __init__(self, generator, opacity_model):
+        super(ColorModel, self).__init__(generator)
         self.opacity_model = opacity_model
 
+    def Add(self, name, value_obj, context):
+        # If a color has generate_per_mode set, a separate variable will be
+        # created for each mode, suffixed by mode name.
+        # (e.g my_color_light, my_color_debug)
+        generate_per_mode = False
+
+        # If a color has generate_inverted set, a |color_name|_inverted will be
+        # generated which uses the dark color for light mode and vice versa.
+        generate_inverted = False
+        if isinstance(value_obj, dict):
+            generate_per_mode = value_obj.pop('generate_per_mode', None)
+            generate_inverted = value_obj.pop('generate_inverted', None)
+
+        generated_context = dict(context)
+        generated_context['generated'] = True
+
+        if generate_per_mode or generate_inverted:
+            for mode, value in value_obj.items():
+                per_mode_name = name + '_' + mode
+                ModeKeyedModel.Add(self, per_mode_name, value,
+                                   generated_context)
+                value_obj[mode] = '$' + per_mode_name
+        if generate_inverted:
+            if Modes.LIGHT not in value_obj or Modes.DARK not in value_obj:
+                raise ValueError(
+                    'generate_inverted requires both dark and light modes to be'
+                    ' set')
+            ModeKeyedModel.Add(
+                self, name + '_inverted', {
+                    Modes.LIGHT: '$' + name + '_dark',
+                    Modes.DARK: '$' + name + '_light'
+                }, generated_context)
+
+        ModeKeyedModel.Add(self, name, value_obj, context)
+
     # Returns a Color that is the final RGBA value for |name| in |mode|.
     def ResolveToRGBA(self, name, mode):
         return self._ResolveColorToRGBA(self.Resolve(name, mode), mode)
@@ -220,8 +260,8 @@
         # If specified, only generates the given mode.
         self.generate_single_mode = None
 
-        opacity_model = OpacityModel()
-        color_model = ColorModel(opacity_model)
+        opacity_model = OpacityModel(self)
+        color_model = ColorModel(self, opacity_model)
 
         # A dictionary of |VariableType| to models containing mappings of
         # variable names to values.
@@ -251,7 +291,7 @@
         # ./README.md for each generators list of options.
         self.generator_options = {}
 
-    def _SetVariableContext(self, name, context):
+    def SetVariableContext(self, name, context):
         if name in self.context_map.keys():
             raise ValueError('Variable name "%s" is reused' % name)
         self.context_map[name] = context or {}
@@ -260,9 +300,8 @@
         return self.GetName()
 
     def AddColor(self, name, value_obj, context=None):
-        self._SetVariableContext(name, context)
         try:
-            self.model[VariableType.COLOR].Add(name, value_obj)
+            self.model[VariableType.COLOR].Add(name, value_obj, context)
         except ValueError as err:
             raise ValueError('Error parsing color "%s": %s' % (value_obj, err))
 
@@ -273,8 +312,9 @@
                 raise ValueError(
                     '%s is not a valid variable name (lower case, 0-9, _)' %
                     name)
-
             self.AddColor(name, value, generator_context)
+
+    def _ResolveBlendedColors(self):
         # Calculate the final RGBA for all blended colors because the
         # generator's subclasses can't blend yet.
         color_model = self.model[VariableType.COLOR]
@@ -292,24 +332,30 @@
                 color_model[name][mode] = temp_model[name][mode]
 
     def AddOpacity(self, name, value_obj, context=None):
-        self._SetVariableContext(name, context)
         try:
-            self.model[VariableType.OPACITY].Add(name, value_obj)
+            self.model[VariableType.OPACITY].Add(name, value_obj, context)
         except ValueError as err:
             raise ValueError('Error parsing opacity "%s": %s' %
                              (value_obj, err))
 
     def AddUntypedCSSGroup(self, group_name, value_obj, context=None):
         for var_name in value_obj.keys():
-            self._SetVariableContext(var_name, context)
+            self.SetVariableContext(var_name, context)
         self.model[VariableType.UNTYPED_CSS][group_name] = value_obj
 
-    def AddJSONFileToModel(self, path):
-        try:
-            with open(path, 'r') as f:
-                return self.AddJSONToModel(f.read(), path)
-        except ValueError as err:
-            raise ValueError('\n%s:\n    %s' % (path, err))
+    def AddJSONFilesToModel(self, paths):
+        '''Adds one or more JSON files to the model.
+        '''
+        for path in paths:
+            try:
+                with open(path, 'r') as f:
+                    self.AddJSONToModel(f.read(), path)
+            except ValueError as err:
+                raise ValueError('\n%s:\n    %s' % (path, err))
+
+        # Resolve blended colors after all the files are added because some
+        # color dependencies are between different files.
+        self._ResolveBlendedColors()
 
     def AddJSONToModel(self, json_string, in_file=None):
         '''Adds a |json_string| with variable definitions to the model.
@@ -341,11 +387,11 @@
         if typography:
             typography_model = self.model[VariableType.TYPOGRAPHY]
             for name, value in typography['font_families'].items():
-                self._SetVariableContext(name, generator_context)
+                self.SetVariableContext(name, generator_context)
                 typography_model.AddFontFamily(name, value)
 
             for name, value_obj in typography['typefaces'].items():
-                self._SetVariableContext(name, generator_context)
+                self.SetVariableContext(name, generator_context)
                 typography_model.AddTypeface(name, value_obj)
 
         for name, value in data.get('untyped_css', {}).items():
@@ -387,6 +433,12 @@
         # Check all colors in all modes refer to colors that exist in the
         # default mode.
         for name, mode_values in colors.items():
+            for suffix in RESERVED_SUFFIXES:
+                if not self.context_map[name].get(
+                        'generated') and name.endswith(suffix):
+                    raise ValueError(
+                        'Variable name "%s" uses a reserved suffix: %s' %
+                        (name, suffix))
             if Modes.DEFAULT not in mode_values:
                 raise ValueError("Color %s not defined for default mode" % name)
             for mode, color in mode_values.items():
@@ -396,6 +448,10 @@
                     CheckColorReference(color.RGBVarToVar(), name)
                 if color.opacity and color.opacity.var:
                     CheckOpacityReference(color.opacity.var, name)
+                if color.blended_colors:
+                    assert len(color.blended_colors) == 2
+                    CheckColorReference(color.blended_colors[0], name)
+                    CheckColorReference(color.blended_colors[1], name)
 
         for name, mode_values in opacities.items():
             for mode, opacity in mode_values.items():
diff --git a/tools/style_variable_generator/base_generator_test.py b/tools/style_variable_generator/base_generator_test.py
index af0356a..5653226 100755
--- a/tools/style_variable_generator/base_generator_test.py
+++ b/tools/style_variable_generator/base_generator_test.py
@@ -255,6 +255,75 @@
         self.assertEqual(self.ResolveRGBA('expect_color_black'),
                          'rgba(0, 0, 0, 1)')
 
+    def testMissingBlendColor(self):
+        self.generator.AddJSONToModel('''
+{
+  colors: {
+    bg_color_elevation_10: "blend($white, $google_grey_900)",
+  }
+}
+        ''')
+        self.assertRaises(ValueError, self.generator.Validate)
+
+    def testInvertedColors(self):
+        # Add an inverted color.
+        self.generator.AddJSONToModel('''
+{
+  colors: {
+    alert: { light: "$white", dark: "$black", generate_inverted: true },
+  },
+}
+        ''')
+        self.assertEqual(self.ResolveRGBA('alert', Modes.LIGHT),
+                         'rgba(255, 255, 255, 1)')
+        self.assertEqual(self.ResolveRGBA('alert', Modes.DARK),
+                         'rgba(0, 0, 0, 1)')
+        self.assertEqual(self.ResolveRGBA('alert_inverted', Modes.LIGHT),
+                         'rgba(0, 0, 0, 1)')
+        self.assertEqual(self.ResolveRGBA('alert_inverted', Modes.DARK),
+                         'rgba(255, 255, 255, 1)')
+
+    def testInvertedWithSingleMode(self):
+        # Add an inverted color without a dark mode.
+        self.assertRaises(
+            ValueError, self.generator.AddJSONToModel, '''
+{
+  colors: {
+    alert: { light: "$white", generate_inverted: true },
+  },
+}
+        ''')
+
+    def testIllegalSuffix(self):
+        self.generator.AddJSONToModel('''
+{
+  colors: {
+    some_inverted: "$black",
+  }
+}
+        ''')
+        self.assertRaises(ValueError, self.generator.Validate)
+
+    def testPerModeColors(self):
+        # Add a per-mode color.
+        self.generator.AddJSONToModel('''
+{
+  colors: {
+    alert: {
+      light: "$white",
+      dark: "$black",
+      debug: "$black",
+      generate_per_mode: true
+    },
+  },
+}
+        ''')
+        self.assertEqual(self.ResolveRGBA('alert_dark'), 'rgba(0, 0, 0, 1)')
+        self.assertEqual(self.ResolveRGBA('alert_light'),
+                         'rgba(255, 255, 255, 1)')
+        self.assertEqual(self.ResolveRGBA('alert_debug'), 'rgba(0, 0, 0, 1)')
+        self.assertEqual(self.ResolveRGBA('alert'), 'rgba(255, 255, 255, 1)')
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tools/style_variable_generator/colors_test.json5 b/tools/style_variable_generator/colors_test.json5
index 51d99d5..95ccf6a 100644
--- a/tools/style_variable_generator/colors_test.json5
+++ b/tools/style_variable_generator/colors_test.json5
@@ -18,6 +18,10 @@
       light: "rgba($text_color_primary_rgb, 0.1)",
       dark: "rgba($text_color_primary_rgb, $disabled_opacity)",
       debug: "$white",
+    },
+    bg_color_elevation_1: {
+      light: "$white",
+      dark: "blend(rgba($white_rgb, 0.04), $google_grey_900)",
     }
   },
   opacities: {
diff --git a/tools/style_variable_generator/colors_test_custom_dark_toggle_expected.css b/tools/style_variable_generator/colors_test_custom_dark_toggle_expected.css
index 33420bc5..30dcdd3 100644
--- a/tools/style_variable_generator/colors_test_custom_dark_toggle_expected.css
+++ b/tools/style_variable_generator/colors_test_custom_dark_toggle_expected.css
@@ -17,6 +17,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), 0.1);
 
+  --cros-bg-color-elevation-1-rgb: 255, 255, 255;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-disabled-opacity: 0.38;
 
   --cros-reference-opacity: var(--cros-disabled-opacity);
@@ -29,5 +32,8 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), var(--cros-disabled-opacity));
 
+  --cros-bg-color-elevation-1-rgb: 41, 42, 45;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-reference-opacity: 1;
 }
diff --git a/tools/style_variable_generator/colors_test_dark_only_expected.css b/tools/style_variable_generator/colors_test_dark_only_expected.css
index 6213811..54111256 100644
--- a/tools/style_variable_generator/colors_test_dark_only_expected.css
+++ b/tools/style_variable_generator/colors_test_dark_only_expected.css
@@ -17,6 +17,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), var(--cros-disabled-opacity));
 
+  --cros-bg-color-elevation-1-rgb: 41, 42, 45;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-disabled-opacity: 0.38;
 
   --cros-reference-opacity: 1;
diff --git a/tools/style_variable_generator/colors_test_debug_placeholder_expected.css b/tools/style_variable_generator/colors_test_debug_placeholder_expected.css
index 5469876..333ec0f 100644
--- a/tools/style_variable_generator/colors_test_debug_placeholder_expected.css
+++ b/tools/style_variable_generator/colors_test_debug_placeholder_expected.css
@@ -17,6 +17,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), 0.1);
 
+  --cros-bg-color-elevation-1-rgb: 255, 255, 255;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-disabled-opacity: 0.38;
 
   --cros-reference-opacity: var(--cros-disabled-opacity);
@@ -30,6 +33,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), var(--cros-disabled-opacity));
 
+  --cros-bg-color-elevation-1-rgb: 41, 42, 45;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-reference-opacity: 1;
 }
 }
diff --git a/tools/style_variable_generator/colors_test_expected.css b/tools/style_variable_generator/colors_test_expected.css
index aeda7279a..afc7e75 100644
--- a/tools/style_variable_generator/colors_test_expected.css
+++ b/tools/style_variable_generator/colors_test_expected.css
@@ -17,6 +17,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), 0.1);
 
+  --cros-bg-color-elevation-1-rgb: 255, 255, 255;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-disabled-opacity: 0.38;
 
   --cros-reference-opacity: var(--cros-disabled-opacity);
@@ -30,6 +33,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), var(--cros-disabled-opacity));
 
+  --cros-bg-color-elevation-1-rgb: 41, 42, 45;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-reference-opacity: 1;
 }
 }
diff --git a/tools/style_variable_generator/colors_test_expected.h.generated b/tools/style_variable_generator/colors_test_expected.h.generated
index b05dcd5d..a6cd52a 100644
--- a/tools/style_variable_generator/colors_test_expected.h.generated
+++ b/tools/style_variable_generator/colors_test_expected.h.generated
@@ -18,6 +18,7 @@
   kGoogleGrey900,
   kTextColorPrimary,
   kToggleColor,
+  kBgColorElevation1,
 };
 
 enum class OpacityName {
@@ -56,6 +57,10 @@
       if (is_dark_mode)
         return SkColorSetA(ResolveColor(ColorName::kTextColorPrimary, is_dark_mode, use_debug_colors), GetOpacity(OpacityName::kDisabledOpacity, is_dark_mode));
       return SkColorSetA(ResolveColor(ColorName::kTextColorPrimary, is_dark_mode, use_debug_colors), 0x19);
+    case ColorName::kBgColorElevation1:
+      if (is_dark_mode)
+        return SkColorSetRGB(0x29, 0x2A, 0x2D);
+      return SkColorSetRGB(0xFF, 0xFF, 0xFF);
   }
 }
 
diff --git a/tools/style_variable_generator/colors_test_expected.protojson b/tools/style_variable_generator/colors_test_expected.protojson
index 4a49a05..5e8c9a6 100644
--- a/tools/style_variable_generator/colors_test_expected.protojson
+++ b/tools/style_variable_generator/colors_test_expected.protojson
@@ -27,6 +27,13 @@
     }
   },
   {
+    key: "bg_color_elevation_1",
+    value: {
+      light_value: 0xFFFFFFFF,
+      dark_value: 0xFF292A2D
+    }
+  },
+  {
     key: "text_color",
     value: {
       light_value: 0xFF000000,
diff --git a/tools/style_variable_generator/colors_test_expected.ts b/tools/style_variable_generator/colors_test_expected.ts
index 3b73ec5..23fa70d 100644
--- a/tools/style_variable_generator/colors_test_expected.ts
+++ b/tools/style_variable_generator/colors_test_expected.ts
@@ -12,5 +12,6 @@
 export const GOOGLE_GREY_900 = css`var(--google-grey-900)`;
 export const TEXT_COLOR_PRIMARY = css`var(--cros-text-color-primary)`;
 export const TOGGLE_COLOR = css`var(--cros-toggle-color)`;
+export const BG_COLOR_ELEVATION_1 = css`var(--cros-bg-color-elevation-1)`;
 export const DISABLED_OPACITY = css`var(--cros-disabled-opacity)`;
 export const REFERENCE_OPACITY = css`var(--cros-reference-opacity)`;
diff --git a/tools/style_variable_generator/colors_test_include_style_sheet_expected.ts b/tools/style_variable_generator/colors_test_include_style_sheet_expected.ts
index f954a650..ec9113b 100644
--- a/tools/style_variable_generator/colors_test_include_style_sheet_expected.ts
+++ b/tools/style_variable_generator/colors_test_include_style_sheet_expected.ts
@@ -25,6 +25,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), 0.1);
 
+  --cros-bg-color-elevation-1-rgb: 255, 255, 255;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-disabled-opacity: 0.38;
 
   --cros-reference-opacity: var(--cros-disabled-opacity);
@@ -39,6 +42,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), var(--cros-disabled-opacity));
 
+  --cros-bg-color-elevation-1-rgb: 41, 42, 45;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-reference-opacity: 1;
 }
 `;
@@ -78,5 +84,6 @@
 export const GOOGLE_GREY_900 = css`var(--google-grey-900)`;
 export const TEXT_COLOR_PRIMARY = css`var(--cros-text-color-primary)`;
 export const TOGGLE_COLOR = css`var(--cros-toggle-color)`;
+export const BG_COLOR_ELEVATION_1 = css`var(--cros-bg-color-elevation-1)`;
 export const DISABLED_OPACITY = css`var(--cros-disabled-opacity)`;
 export const REFERENCE_OPACITY = css`var(--cros-reference-opacity)`;
diff --git a/tools/style_variable_generator/colors_test_typography_and_untyped_css_expected.ts b/tools/style_variable_generator/colors_test_typography_and_untyped_css_expected.ts
index 32bb7ee..b77dccab 100644
--- a/tools/style_variable_generator/colors_test_typography_and_untyped_css_expected.ts
+++ b/tools/style_variable_generator/colors_test_typography_and_untyped_css_expected.ts
@@ -27,6 +27,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), 0.1);
 
+  --cros-bg-color-elevation-1-rgb: 255, 255, 255;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-disabled-opacity: 0.38;
 
   --cros-reference-opacity: var(--cros-disabled-opacity);
@@ -59,6 +62,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), var(--cros-disabled-opacity));
 
+  --cros-bg-color-elevation-1-rgb: 41, 42, 45;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-reference-opacity: 1;
 }
 `;
@@ -98,6 +104,7 @@
 export const GOOGLE_GREY_900 = css`var(--google-grey-900)`;
 export const TEXT_COLOR_PRIMARY = css`var(--cros-text-color-primary)`;
 export const TOGGLE_COLOR = css`var(--cros-toggle-color)`;
+export const BG_COLOR_ELEVATION_1 = css`var(--cros-bg-color-elevation-1)`;
 export const DISABLED_OPACITY = css`var(--cros-disabled-opacity)`;
 export const REFERENCE_OPACITY = css`var(--cros-reference-opacity)`;
 
diff --git a/tools/style_variable_generator/colors_test_typography_expected.ts b/tools/style_variable_generator/colors_test_typography_expected.ts
index a73a12c..1beca9c 100644
--- a/tools/style_variable_generator/colors_test_typography_expected.ts
+++ b/tools/style_variable_generator/colors_test_typography_expected.ts
@@ -26,6 +26,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), 0.1);
 
+  --cros-bg-color-elevation-1-rgb: 255, 255, 255;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-disabled-opacity: 0.38;
 
   --cros-reference-opacity: var(--cros-disabled-opacity);
@@ -52,6 +55,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), var(--cros-disabled-opacity));
 
+  --cros-bg-color-elevation-1-rgb: 41, 42, 45;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-reference-opacity: 1;
 }
 `;
@@ -91,6 +97,7 @@
 export const GOOGLE_GREY_900 = css`var(--google-grey-900)`;
 export const TEXT_COLOR_PRIMARY = css`var(--cros-text-color-primary)`;
 export const TOGGLE_COLOR = css`var(--cros-toggle-color)`;
+export const BG_COLOR_ELEVATION_1 = css`var(--cros-bg-color-elevation-1)`;
 export const DISABLED_OPACITY = css`var(--cros-disabled-opacity)`;
 export const REFERENCE_OPACITY = css`var(--cros-reference-opacity)`;
 
diff --git a/tools/style_variable_generator/colors_test_untyped_css_expected.ts b/tools/style_variable_generator/colors_test_untyped_css_expected.ts
index ad7e9bb0..e443f65 100644
--- a/tools/style_variable_generator/colors_test_untyped_css_expected.ts
+++ b/tools/style_variable_generator/colors_test_untyped_css_expected.ts
@@ -26,6 +26,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), 0.1);
 
+  --cros-bg-color-elevation-1-rgb: 255, 255, 255;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-disabled-opacity: 0.38;
 
   --cros-reference-opacity: var(--cros-disabled-opacity);
@@ -46,6 +49,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), var(--cros-disabled-opacity));
 
+  --cros-bg-color-elevation-1-rgb: 41, 42, 45;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-reference-opacity: 1;
 }
 `;
@@ -85,6 +91,7 @@
 export const GOOGLE_GREY_900 = css`var(--google-grey-900)`;
 export const TEXT_COLOR_PRIMARY = css`var(--cros-text-color-primary)`;
 export const TOGGLE_COLOR = css`var(--cros-toggle-color)`;
+export const BG_COLOR_ELEVATION_1 = css`var(--cros-bg-color-elevation-1)`;
 export const DISABLED_OPACITY = css`var(--cros-disabled-opacity)`;
 export const REFERENCE_OPACITY = css`var(--cros-reference-opacity)`;
 
diff --git a/tools/style_variable_generator/inverted_colors_test.json5 b/tools/style_variable_generator/inverted_colors_test.json5
new file mode 100644
index 0000000..54d5193
--- /dev/null
+++ b/tools/style_variable_generator/inverted_colors_test.json5
@@ -0,0 +1,33 @@
+{
+  options: {
+    CSS: {
+      prefix: 'cros'
+    },
+  },
+  colors: {
+    bg_color: {
+      light: "$white",
+      dark: "rgba($google_grey_900_rgb, 0.7)",
+      generate_inverted: true,
+    },
+    toggle_color: {
+      light: "rgba($google_grey_900_rgb, 0.1)",
+      dark: "rgba($black_rgb, $reference_opacity)",
+      debug: "$white",
+      generate_per_mode: true,
+    },
+    toast_color: "$bg_color_inverted",
+    composite_color: {
+      light: "rgba($toggle_color_dark_rgb, 0.3)",
+      dark: "rgba($bg_color_inverted_rgb, $disabled_opacity)",
+      generate_inverted: true,
+    }
+  },
+  opacities: {
+    disabled_opacity: 0.38,
+    reference_opacity: {
+        light: '$disabled_opacity',
+        dark: 1,
+    },
+  },
+}
diff --git a/tools/style_variable_generator/inverted_colors_test_expected.css b/tools/style_variable_generator/inverted_colors_test_expected.css
new file mode 100644
index 0000000..9a7ecc6e
--- /dev/null
+++ b/tools/style_variable_generator/inverted_colors_test_expected.css
@@ -0,0 +1,77 @@
+/* Copyright 2020 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+/* This file is generated from:
+ *  colors_test_palette.json5
+ *  inverted_colors_test.json5
+ */
+
+html:not(body) {
+  --google-grey-900-rgb: 32, 33, 36;
+  --google-grey-900: rgb(var(--google-grey-900-rgb));
+
+  --cros-bg-color-light-rgb: 255, 255, 255;
+  --cros-bg-color-light: rgb(var(--cros-bg-color-light-rgb));
+
+  --cros-bg-color-dark-rgb: var(--google-grey-900-rgb);
+  --cros-bg-color-dark: rgba(var(--cros-bg-color-dark-rgb), 0.7);
+
+  --cros-bg-color-inverted-rgb: var(--cros-bg-color-dark-rgb);
+  --cros-bg-color-inverted: var(--cros-bg-color-dark);
+
+  --cros-bg-color-rgb: var(--cros-bg-color-light-rgb);
+  --cros-bg-color: var(--cros-bg-color-light);
+
+  --cros-toggle-color-light-rgb: var(--google-grey-900-rgb);
+  --cros-toggle-color-light: rgba(var(--cros-toggle-color-light-rgb), 0.1);
+
+  --cros-toggle-color-dark-rgb: 0, 0, 0;
+  --cros-toggle-color-dark: rgba(var(--cros-toggle-color-dark-rgb), var(--cros-reference-opacity));
+
+  --cros-toggle-color-debug-rgb: 255, 255, 255;
+  --cros-toggle-color-debug: rgb(var(--cros-toggle-color-debug-rgb));
+
+  --cros-toggle-color-rgb: var(--cros-toggle-color-light-rgb);
+  --cros-toggle-color: var(--cros-toggle-color-light);
+
+  --cros-toast-color-rgb: var(--cros-bg-color-inverted-rgb);
+  --cros-toast-color: var(--cros-bg-color-inverted);
+
+  --cros-composite-color-light-rgb: var(--cros-toggle-color-dark-rgb);
+  --cros-composite-color-light: rgba(var(--cros-composite-color-light-rgb), 0.3);
+
+  --cros-composite-color-dark-rgb: var(--cros-bg-color-inverted-rgb);
+  --cros-composite-color-dark: rgba(var(--cros-composite-color-dark-rgb), var(--cros-disabled-opacity));
+
+  --cros-composite-color-inverted-rgb: var(--cros-composite-color-dark-rgb);
+  --cros-composite-color-inverted: var(--cros-composite-color-dark);
+
+  --cros-composite-color-rgb: var(--cros-composite-color-light-rgb);
+  --cros-composite-color: var(--cros-composite-color-light);
+
+  --cros-disabled-opacity: 0.38;
+
+  --cros-reference-opacity: var(--cros-disabled-opacity);
+}
+
+@media (prefers-color-scheme: dark) {
+html:not(body) {
+  --cros-bg-color-inverted-rgb: var(--cros-bg-color-light-rgb);
+  --cros-bg-color-inverted: var(--cros-bg-color-light);
+
+  --cros-bg-color-rgb: var(--cros-bg-color-dark-rgb);
+  --cros-bg-color: var(--cros-bg-color-dark);
+
+  --cros-toggle-color-rgb: var(--cros-toggle-color-dark-rgb);
+  --cros-toggle-color: var(--cros-toggle-color-dark);
+
+  --cros-composite-color-inverted-rgb: var(--cros-composite-color-light-rgb);
+  --cros-composite-color-inverted: var(--cros-composite-color-light);
+
+  --cros-composite-color-rgb: var(--cros-composite-color-dark-rgb);
+  --cros-composite-color: var(--cros-composite-color-dark);
+
+  --cros-reference-opacity: 1;
+}
+}
diff --git a/tools/style_variable_generator/main.py b/tools/style_variable_generator/main.py
index a250ccb..3768487 100755
--- a/tools/style_variable_generator/main.py
+++ b/tools/style_variable_generator/main.py
@@ -58,8 +58,7 @@
         if args.generator == g.GetName():
             style_generator = g()
 
-    for t in args.targets:
-        style_generator.AddJSONFileToModel(t)
+    style_generator.AddJSONFilesToModel(args.targets)
 
     style_generator.generate_single_mode = args.generate_single_mode
     style_generator.out_file_path = args.out_file
diff --git a/tools/style_variable_generator/style_variable_generator_test.py b/tools/style_variable_generator/style_variable_generator_test.py
index 94c1f53..ced1a69 100755
--- a/tools/style_variable_generator/style_variable_generator_test.py
+++ b/tools/style_variable_generator/style_variable_generator_test.py
@@ -31,16 +31,16 @@
 class ViewsStyleGeneratorTest(unittest.TestCase, BaseStyleGeneratorTest):
     def setUp(self):
         self.generator = ViewsStyleGenerator()
-        self.generator.AddJSONFileToModel('colors_test_palette.json5')
-        self.generator.AddJSONFileToModel('colors_test.json5')
+        self.generator.AddJSONFilesToModel(
+            ['colors_test_palette.json5', 'colors_test.json5'])
         self.expected_output_file = 'colors_test_expected.h.generated'
 
 
 class CSSStyleGeneratorTest(unittest.TestCase, BaseStyleGeneratorTest):
     def setUp(self):
         self.generator = CSSStyleGenerator()
-        self.generator.AddJSONFileToModel('colors_test_palette.json5')
-        self.generator.AddJSONFileToModel('colors_test.json5')
+        self.generator.AddJSONFilesToModel(
+            ['colors_test_palette.json5', 'colors_test.json5'])
         self.expected_output_file = 'colors_test_expected.css'
 
     def testCustomDarkModeSelector(self):
@@ -64,13 +64,13 @@
 
     def testUntypedCSS(self):
         self.generator = CSSStyleGenerator()
-        self.generator.AddJSONFileToModel('untyped_css_test.json5')
+        self.generator.AddJSONFilesToModel(['untyped_css_test.json5'])
         expected_file_name = 'untyped_css_test_expected.css'
         self.assertEqualToFile(self.generator.Render(), expected_file_name)
 
     def testTypography(self):
         self.generator = CSSStyleGenerator()
-        self.generator.AddJSONFileToModel('typography_test.json5')
+        self.generator.AddJSONFilesToModel(['typography_test.json5'])
         expected_file_name = 'typography_test_expected.css'
         self.assertEqualToFile(self.generator.Render(), expected_file_name)
 
@@ -83,8 +83,8 @@
 class TSStyleGeneratorTest(unittest.TestCase, BaseStyleGeneratorTest):
     def setUp(self):
         self.generator = TSStyleGenerator()
-        self.generator.AddJSONFileToModel('colors_test_palette.json5')
-        self.generator.AddJSONFileToModel('colors_test.json5')
+        self.generator.AddJSONFilesToModel(
+            ['colors_test_palette.json5', 'colors_test.json5'])
         self.expected_output_file = 'colors_test_expected.ts'
 
     def testIncludeStyleSheet(self):
@@ -94,20 +94,20 @@
 
     def testTypography(self):
         expected_file_name = 'colors_test_typography_expected.ts'
-        self.generator.AddJSONFileToModel('typography_test.json5')
+        self.generator.AddJSONFilesToModel(['typography_test.json5'])
         self.generator.generator_options = {'include_style_sheet': 'true'}
         self.assertEqualToFile(self.generator.Render(), expected_file_name)
 
     def testUntypedCSS(self):
         expected_file_name = 'colors_test_untyped_css_expected.ts'
-        self.generator.AddJSONFileToModel('untyped_css_test.json5')
+        self.generator.AddJSONFilesToModel(['untyped_css_test.json5'])
         self.generator.generator_options = {'include_style_sheet': 'true'}
         self.assertEqualToFile(self.generator.Render(), expected_file_name)
 
     def testTypographyAndUntypedCSS(self):
         expected_file_name = 'colors_test_typography_and_untyped_css_expected.ts'
-        self.generator.AddJSONFileToModel('typography_test.json5')
-        self.generator.AddJSONFileToModel('untyped_css_test.json5')
+        self.generator.AddJSONFilesToModel(
+            ['typography_test.json5', 'untyped_css_test.json5'])
         self.generator.generator_options = {'include_style_sheet': 'true'}
         self.assertEqualToFile(self.generator.Render(), expected_file_name)
 
@@ -120,20 +120,32 @@
 class ProtoStyleGeneratorTest(unittest.TestCase, BaseStyleGeneratorTest):
     def setUp(self):
         self.generator = ProtoStyleGenerator()
-        self.generator.AddJSONFileToModel('colors_test_palette.json5')
-        self.generator.AddJSONFileToModel('colors_test.json5')
+        self.generator.AddJSONFilesToModel(
+            ['colors_test_palette.json5', 'colors_test.json5'])
         self.expected_output_file = 'colors_test_expected.proto'
 
 
 class ProtoJSONStyleGeneratorTest(unittest.TestCase, BaseStyleGeneratorTest):
     def setUp(self):
         self.generator = ProtoJSONStyleGenerator()
-        self.generator.AddJSONFileToModel('colors_test_palette.json5')
-        self.generator.AddJSONFileToModel('colors_test.json5')
-        # Add in a separate file which adds more colors to test_colors so we can
-        # confirm we do not generate duplicate fields.
-        self.generator.AddJSONFileToModel('additional_colors_test.json5')
+        paths = [
+            'colors_test_palette.json5',
+            'colors_test.json5',
+            # Add in a separate file which adds more colors to test_colors so we
+            # can confirm we do not generate duplicate fields.
+            'additional_colors_test.json5',
+        ]
+        self.generator.AddJSONFilesToModel(paths)
         self.expected_output_file = 'colors_test_expected.protojson'
 
+
+class InvertedStyleGeneratorTest(unittest.TestCase, BaseStyleGeneratorTest):
+    def setUp(self):
+        self.generator = CSSStyleGenerator()
+        self.generator.AddJSONFilesToModel(
+            ['colors_test_palette.json5', 'inverted_colors_test.json5'])
+        self.expected_output_file = 'inverted_colors_test_expected.css'
+
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/tools/style_variable_generator/suppress_sources_comment_test_expected.css b/tools/style_variable_generator/suppress_sources_comment_test_expected.css
index 3d7ddd8..377e115 100644
--- a/tools/style_variable_generator/suppress_sources_comment_test_expected.css
+++ b/tools/style_variable_generator/suppress_sources_comment_test_expected.css
@@ -12,6 +12,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), 0.1);
 
+  --cros-bg-color-elevation-1-rgb: 255, 255, 255;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-disabled-opacity: 0.38;
 
   --cros-reference-opacity: var(--cros-disabled-opacity);
@@ -25,6 +28,9 @@
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), var(--cros-disabled-opacity));
 
+  --cros-bg-color-elevation-1-rgb: 41, 42, 45;
+  --cros-bg-color-elevation-1: rgb(var(--cros-bg-color-elevation-1-rgb));
+
   --cros-reference-opacity: 1;
 }
 }
diff --git a/tools/style_variable_generator/suppress_sources_comment_test_expected.ts b/tools/style_variable_generator/suppress_sources_comment_test_expected.ts
index 4249357..eef4562 100644
--- a/tools/style_variable_generator/suppress_sources_comment_test_expected.ts
+++ b/tools/style_variable_generator/suppress_sources_comment_test_expected.ts
@@ -7,5 +7,6 @@
 export const GOOGLE_GREY_900 = css`var(--google-grey-900)`;
 export const TEXT_COLOR_PRIMARY = css`var(--cros-text-color-primary)`;
 export const TOGGLE_COLOR = css`var(--cros-toggle-color)`;
+export const BG_COLOR_ELEVATION_1 = css`var(--cros-bg-color-elevation-1)`;
 export const DISABLED_OPACITY = css`var(--cros-disabled-opacity)`;
 export const REFERENCE_OPACITY = css`var(--cros-reference-opacity)`;
diff --git a/tools/traffic_annotation/auditor/chromeos/safe_list.txt b/tools/traffic_annotation/auditor/chromeos/safe_list.txt
index faff087..17248a37 100644
--- a/tools/traffic_annotation/auditor/chromeos/safe_list.txt
+++ b/tools/traffic_annotation/auditor/chromeos/safe_list.txt
@@ -41,7 +41,7 @@
 all,chrome/browser/ash/wallpaper_handlers/wallpaper_handlers.cc
 all,chrome/browser/search/background/ntp_background_service.cc
 all,chrome/browser/ash/net/network_diagnostics/tls_prober.cc
-all,ash/components/quick_answers/result_loader.cc
+all,chromeos/components/quick_answers/result_loader.cc
 all,chrome/browser/apps/app_service/webapk/webapk_install_task.cc
 all,chrome/browser/ash/login/saml/password_sync_token_fetcher.cc
 all,chrome/browser/ash/login/screens/recommend_apps/recommend_apps_fetcher_impl.cc
diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc
index 399b6c6..7376bee6 100644
--- a/ui/accessibility/ax_node.cc
+++ b/ui/accessibility/ax_node.cc
@@ -717,48 +717,6 @@
   return false;
 }
 
-std::vector<int> AXNode::GetOrComputeLineStartOffsets() {
-  DCHECK(!tree_->GetTreeUpdateInProgressState());
-  std::vector<int> line_offsets;
-  if (GetIntListAttribute(ax::mojom::IntListAttribute::kLineStarts,
-                          &line_offsets)) {
-    return line_offsets;
-  }
-
-  int start_offset = 0;
-  ComputeLineStartOffsets(&line_offsets, &start_offset);
-  data_.AddIntListAttribute(ax::mojom::IntListAttribute::kLineStarts,
-                            line_offsets);
-  return line_offsets;
-}
-
-void AXNode::ComputeLineStartOffsets(std::vector<int>* line_offsets,
-                                     int* start_offset) const {
-  DCHECK(!tree_->GetTreeUpdateInProgressState());
-  DCHECK(line_offsets);
-  DCHECK(start_offset);
-  for (auto iter = AllChildrenCrossingTreeBoundaryBegin();
-       iter != AllChildrenCrossingTreeBoundaryEnd(); ++iter) {
-    if (iter->GetChildCountCrossingTreeBoundary()) {
-      iter->ComputeLineStartOffsets(line_offsets, start_offset);
-      continue;
-    }
-
-    // Don't report if the first piece of text starts a new line or not.
-    if (*start_offset &&
-        !iter->HasIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId)) {
-      // If there are multiple objects with an empty accessible label at the
-      // start of a line, only include a single line start offset.
-      if (line_offsets->empty() || line_offsets->back() != *start_offset)
-        line_offsets->push_back(*start_offset);
-    }
-
-    std::u16string text =
-        iter->GetString16Attribute(ax::mojom::StringAttribute::kName);
-    *start_offset += static_cast<int>(text.length());
-  }
-}
-
 SkColor AXNode::ComputeColor() const {
   return ComputeColorAttribute(ax::mojom::IntAttribute::kColor);
 }
@@ -839,6 +797,24 @@
   return base::UTF8ToUTF16(GetInheritedStringAttribute(attribute));
 }
 
+bool AXNode::HasIntListAttribute(ax::mojom::IntListAttribute attribute) const {
+  return GetComputedNodeData().HasOrCanComputeAttribute(attribute);
+}
+
+const std::vector<int32_t>& AXNode::GetIntListAttribute(
+    ax::mojom::IntListAttribute attribute) const {
+  return GetComputedNodeData().GetOrComputeAttribute(attribute);
+}
+
+bool AXNode::GetIntListAttribute(ax::mojom::IntListAttribute attribute,
+                                 std::vector<int32_t>* value) const {
+  if (GetComputedNodeData().HasOrCanComputeAttribute(attribute)) {
+    *value = GetComputedNodeData().GetOrComputeAttribute(attribute);
+    return true;
+  }
+  return false;
+}
+
 AXLanguageInfo* AXNode::GetLanguageInfo() const {
   return language_info_.get();
 }
diff --git a/ui/accessibility/ax_node.h b/ui/accessibility/ax_node.h
index 8344144..6e323b1 100644
--- a/ui/accessibility/ax_node.h
+++ b/ui/accessibility/ax_node.h
@@ -290,10 +290,6 @@
   bool IsDescendantOf(const AXNode* ancestor) const;
   bool IsDescendantOfCrossingTreeBoundary(const AXNode* ancestor) const;
 
-  // Gets the text offsets where new lines start either from the node's data or
-  // by computing them and caching the result.
-  std::vector<int> GetOrComputeLineStartOffsets();
-
   // If the color is transparent, blends with the ancestor's color.
   // Note that this is imperfect; it won't work if a node is absolute-
   // positioned outside of its ancestor. However, it handles the most
@@ -373,17 +369,11 @@
   GetIntListAttributes() const {
     return data().intlist_attributes;
   }
-  bool HasIntListAttribute(ax::mojom::IntListAttribute attribute) const {
-    return data().HasIntListAttribute(attribute);
-  }
+  bool HasIntListAttribute(ax::mojom::IntListAttribute attribute) const;
   const std::vector<int32_t>& GetIntListAttribute(
-      ax::mojom::IntListAttribute attribute) const {
-    return data().GetIntListAttribute(attribute);
-  }
+      ax::mojom::IntListAttribute attribute) const;
   bool GetIntListAttribute(ax::mojom::IntListAttribute attribute,
-                           std::vector<int32_t>* value) const {
-    return data().GetIntListAttribute(attribute, value);
-  }
+                           std::vector<int32_t>* value) const;
 
   bool HasStringListAttribute(ax::mojom::StringListAttribute attribute) const {
     return data().HasStringListAttribute(attribute);
@@ -705,10 +695,6 @@
   AXNode* GetOrderedSet() const;
 
  private:
-  // Computes the text offset where each line starts by traversing all child
-  // leaf nodes.
-  void ComputeLineStartOffsets(std::vector<int>* line_offsets,
-                               int* start_offset) const;
   AXTableInfo* GetAncestorTableInfo() const;
   void IdVectorToNodeVector(const std::vector<AXNodeID>& ids,
                             std::vector<AXNode*>* nodes) const;
diff --git a/ui/accessibility/platform/ax_platform_node_cocoa.mm b/ui/accessibility/platform/ax_platform_node_cocoa.mm
index 90ceb73..beb161a 100644
--- a/ui/accessibility/platform/ax_platform_node_cocoa.mm
+++ b/ui/accessibility/platform/ax_platform_node_cocoa.mm
@@ -800,6 +800,13 @@
     [axAttributes addObject:NSAccessibilityDetailsElementsAttribute];
   }
 
+  // Anything focusable or any control:
+  if (_node->HasIntAttribute(ax::mojom::IntAttribute::kRestriction) ||
+      _node->HasIntAttribute(ax::mojom::IntAttribute::kInvalidState) ||
+      _node->HasState(ax::mojom::State::kFocusable)) {
+    [axAttributes addObject:NSAccessibilityRequiredAttributeChrome];
+  }
+
   // Table and grid.
   if (ui::IsTableLike(role)) {
     [axAttributes addObject:NSAccessibilityColumnHeaderUIElementsAttribute];
@@ -952,6 +959,10 @@
   return [elements count] ? elements : nil;
 }
 
+- (NSNumber*)AXRequired {
+  return [self accessibilityRequired];
+}
+
 - (NSString*)AXRole {
   if (!_node)
     return nil;
@@ -1268,6 +1279,17 @@
   return [self AXValue];
 }
 
+// NSAccessibility protocol:
+- (NSNumber*)accessibilityRequired {
+  TRACE_EVENT1("accessibility", "accessibilityRequired",
+               "role=", ui::ToString([self internalRole]));
+
+  if (![self instanceActive])
+    return nil;
+
+  return _node->HasState(ax::mojom::State::kRequired) ? @YES : @NO;
+}
+
 - (NSAccessibilityRole)accessibilityRole {
   return [self AXRole];
 }
diff --git a/ui/accessibility/platform/ax_private_attributes_mac.h b/ui/accessibility/platform/ax_private_attributes_mac.h
index 001fd365..5ad6756 100644
--- a/ui/accessibility/platform/ax_private_attributes_mac.h
+++ b/ui/accessibility/platform/ax_private_attributes_mac.h
@@ -52,4 +52,18 @@
 AX_EXPORT constexpr NSString* const NSAccessibilityMathPrescriptsAttribute =
     @"AXMathPrescripts";
 
+#if defined(MAC_OS_X_VERSION_10_12) && \
+    (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12)
+#warning NSAccessibilityRequiredAttributeChrome \
+  should be removed since the deployment target is >= 10.12
+#endif
+
+// The following private WebKit accessibility attribute became public in 10.12,
+// but it can't be used on all OS because it has availability of 10.12. Instead,
+// define a similarly named constant with the "Chrome" suffix, and the same
+// string. This is used as the key to a dictionary, so string-comparison will
+// work.
+AX_EXPORT constexpr NSString* const NSAccessibilityRequiredAttributeChrome =
+    @"AXRequired";
+
 #endif  // UI_ACCESSIBILITY_PLATFORM_AX_PRIVATE_ATTRIBUTES_MAC_H_
diff --git a/ui/android/java/res/values-night/colors.xml b/ui/android/java/res/values-night/colors.xml
index 4df8d0a9..a3f1591 100644
--- a/ui/android/java/res/values-night/colors.xml
+++ b/ui/android/java/res/values-night/colors.xml
@@ -24,7 +24,9 @@
     <color name="default_icon_color_disabled_inverse">@color/default_icon_color_disabled_dark</color>
 
     <!-- Common background and branding color. -->
-    <color name="default_bg_color">@color/default_bg_color_dark</color>
+    <!-- TODO(https://crbug.com/1272001): Remove @color/default_bg_color. -->
+    <color name="default_bg_color">@color/default_bg_color_baseline</color>
+    <color name="default_bg_color_baseline">@color/default_bg_color_dark</color>
     <color name="default_bg_color_secondary">@color/default_bg_color_secondary_dark</color>
     <color name="default_bg_color_elev_0">@color/default_bg_color_dark</color>
     <color name="default_bg_color_elev_1">@color/default_bg_color_dark_elev_1</color>
diff --git a/ui/android/java/res/values/semantic_colors_adaptive.xml b/ui/android/java/res/values/semantic_colors_adaptive.xml
index 51415299..4d9ff97 100644
--- a/ui/android/java/res/values/semantic_colors_adaptive.xml
+++ b/ui/android/java/res/values/semantic_colors_adaptive.xml
@@ -35,7 +35,9 @@
     <color name="default_icon_color_disabled_inverse" tools:ignore="UnusedResources">@color/default_icon_color_disabled_light</color>
 
     <!-- Common background and branding color. -->
-    <color name="default_bg_color">@color/default_bg_color_light</color>
+    <!-- TODO(https://crbug.com/1272001): Remove @color/default_bg_color. -->
+    <color name="default_bg_color">@color/default_bg_color_baseline</color>
+    <color name="default_bg_color_baseline">@color/default_bg_color_light</color>
     <color name="default_bg_color_secondary" tools:ignore="UnusedResources">@color/default_bg_color_secondary_light</color>
 
     <color name="default_bg_color_blue" tools:ignore="UnusedResources">@color/default_bg_color_blue_dark</color>
diff --git a/ui/aura/window_event_dispatcher.h b/ui/aura/window_event_dispatcher.h
index e97dad78..96be981 100644
--- a/ui/aura/window_event_dispatcher.h
+++ b/ui/aura/window_event_dispatcher.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/ui/base/ime/input_method.h b/ui/base/ime/input_method.h
index 9ab11f2..573daa9 100644
--- a/ui/base/ime/input_method.h
+++ b/ui/base/ime/input_method.h
@@ -7,7 +7,7 @@
 
 #include <stdint.h>
 
-
+#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "ui/base/ime/text_input_mode.h"
 #include "ui/base/ime/text_input_type.h"
diff --git a/ui/base/ime/linux/input_method_auralinux.h b/ui/base/ime/linux/input_method_auralinux.h
index 6477c4c..9b0a5846 100644
--- a/ui/base/ime/linux/input_method_auralinux.h
+++ b/ui/base/ime/linux/input_method_auralinux.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/compiler_specific.h"
 #include "base/component_export.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/ime/composition_text.h"
diff --git a/ui/base/models/dialog_model.h b/ui/base/models/dialog_model.h
index c6b426a2..03842453 100644
--- a/ui/base/models/dialog_model.h
+++ b/ui/base/models/dialog_model.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/compiler_specific.h"
 #include "base/component_export.h"
 #include "base/types/pass_key.h"
 #include "ui/base/models/dialog_model_field.h"
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE.png.sha1
deleted file mode 100644
index 1d7a7808..0000000
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-848e13f48a12b5f1acf8e08366f66914133aca82
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_SINGLE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_SINGLE.png.sha1
deleted file mode 100644
index 6dba2c5..0000000
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_SINGLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-1103d69da142202431923da3129ea3c1f33b0908
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_TITLE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_TITLE.png.sha1
deleted file mode 100644
index 6dba2c5..0000000
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-1103d69da142202431923da3129ea3c1f33b0908
\ No newline at end of file
diff --git a/ui/chromeos/styles/cros_colors.json5 b/ui/chromeos/styles/cros_colors.json5
index 928911d..f95a2c6d 100644
--- a/ui/chromeos/styles/cros_colors.json5
+++ b/ui/chromeos/styles/cros_colors.json5
@@ -22,11 +22,11 @@
     /* =========================================================================
      * Core colors.
      * =======================================================================*/
-    light_color_primary: "$google_grey_900",
-    dark_color_primary: "$google_grey_200",
     color_primary: {
-      light: "$light_color_primary",
-      dark: "$dark_color_primary",
+      light: "$google_grey_900",
+      dark: "$google_grey_200",
+      generate_per_mode: true,
+      generate_inverted: true,
     },
     color_secondary: {
       light: "$google_grey_700",
@@ -41,17 +41,16 @@
       dark: "$google_blue_300",
       debug: "$google_red_600",
     },
-    light_color_alert: "$google_red_600",
-    dark_color_alert: "$google_red_300",
     color_alert: {
-      light: "$light_color_alert",
-      dark: "$dark_color_alert",
+      light: "$google_red_600",
+      dark: "$google_red_300",
+      generate_inverted: true,
     },
-    light_color_warning: "$google_yellow_600",
-    dark_color_warning: "$google_yellow_300",
     color_warning: {
-      light: "$light_color_warning",
-      dark: "$dark_color_warning",
+      light: "$google_yellow_600",
+      dark: "$google_yellow_300",
+      generate_per_mode: true,
+      generate_inverted: true,
     },
     color_positive: {
       light: "$google_green_600",
@@ -72,29 +71,28 @@
     },
     bg_color_elevation_1: {
       light: "$white",
-      dark: "#2a2a2d", /* google_grey_900 + white 4% */
+      dark: "blend(rgba($white_rgb, 0.04), $google_grey_900)",
     },
-    light_bg_color_elevation_2: "$white",
-    dark_bg_color_elevation_2: "#2e2e31", /* google_grey_900 + white 6% */
     bg_color_elevation_2: {
-      light: "$light_bg_color_elevation_2",
-      dark: "$dark_bg_color_elevation_2",
+      light: "$white",
+      dark: "blend(rgba($white_rgb, 0.06), $google_grey_900)",
+      generate_inverted: true,
     },
     bg_color_elevation_3: {
       light: "$white",
-      dark: "#333336", /* google_grey_900 + white 8% */
+      dark: "blend(rgba($white_rgb, 0.08), $google_grey_900)",
     },
     bg_color_elevation_4: {
       light: "$white",
-      dark: "#37373a", /* google_grey_900 + white 10% */
+      dark: "blend(rgba($white_rgb, 0.1), $google_grey_900)",
     },
     bg_color_elevation_5: {
       light: "$white",
-      dark: "#3c3c3e", /* google_grey_900 + white 12% */
+      dark: "blend(rgba($white_rgb, 0.12), $google_grey_900)",
     },
     bg_color_dropped_elevation_1: {
       light: "$google_grey_50",
-      dark: "#1a1a1d", /* google_grey_900 + black 20% */
+      dark: "blend(rgba($black_rgb, 0.2), $google_grey_900)",
     },
     bg_color_dropped_elevation_2: {
       light: "$google_grey_200",
@@ -141,11 +139,6 @@
     icon_color_warning: "$color_warning",
     icon_color_alert: "$color_alert",
 
-    // TODO(calamity): add attribute to allow generation of named variables for
-    // each mode.
-    dark_icon_color_primary: "$google_grey_900",
-    light_icon_color_warning: "$google_yellow_300",
-
     /*
      * App shield colors.
      */
@@ -439,26 +432,11 @@
 
     /* toast */
     /* Toast colors are inverted for contrast. */
-    toast_background_color: {
-      light:"$dark_bg_color_elevation_2",
-      dark:"$light_bg_color_elevation_2",
-    },
-    toast_text_color: {
-      light:"$dark_color_primary",
-      dark:"$light_color_primary",
-    },
-    toast_icon_color: {
-      light:"$dark_color_primary",
-      dark:"$light_color_primary",
-    },
-    toast_icon_color_warning: {
-      light:"$dark_color_warning",
-      dark:"$light_color_warning",
-    },
-    toast_icon_color_error: {
-      light:"$dark_color_alert",
-      dark:"$light_color_alert",
-    },
+    toast_background_color: "$bg_color_elevation_2_inverted",
+    toast_text_color: "$color_primary_inverted",
+    toast_icon_color: "$color_primary_inverted",
+    toast_icon_color_warning: "$color_warning_inverted",
+    toast_icon_color_error: "$color_alert_inverted",
   },
   opacities: {
     disabled_opacity: 0.38,
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index c93fd028..f13d1be 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -12,6 +12,7 @@
 #include <string>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
diff --git a/ui/compositor/test/test_utils.h b/ui/compositor/test/test_utils.h
index 8c9be60f..508f27f 100644
--- a/ui/compositor/test/test_utils.h
+++ b/ui/compositor/test/test_utils.h
@@ -5,6 +5,7 @@
 #ifndef UI_COMPOSITOR_TEST_TEST_UTILS_H_
 #define UI_COMPOSITOR_TEST_TEST_UTILS_H_
 
+#include "base/compiler_specific.h"
 #include "base/time/time.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
diff --git a/ui/display/manager/display_configurator.h b/ui/display/manager/display_configurator.h
index df09fd1..3f24af401 100644
--- a/ui/display/manager/display_configurator.h
+++ b/ui/display/manager/display_configurator.h
@@ -9,6 +9,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/timer/timer.h"
diff --git a/ui/events/event_dispatcher.h b/ui/events/event_dispatcher.h
index a87fc171..42ff35c 100644
--- a/ui/events/event_dispatcher.h
+++ b/ui/events/event_dispatcher.h
@@ -6,6 +6,7 @@
 #define UI_EVENTS_EVENT_DISPATCHER_H_
 
 #include "base/auto_reset.h"
+#include "base/compiler_specific.h"
 #include "ui/events/event.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/event_handler.h"
diff --git a/ui/events/event_rewriter.h b/ui/events/event_rewriter.h
index 23ea37e0..f538f3e1 100644
--- a/ui/events/event_rewriter.h
+++ b/ui/events/event_rewriter.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "ui/events/event_dispatcher.h"
 #include "ui/events/events_export.h"
diff --git a/ui/events/event_rewriter_continuation.h b/ui/events/event_rewriter_continuation.h
index 0a06a9d4..96fa2ae 100644
--- a/ui/events/event_rewriter_continuation.h
+++ b/ui/events/event_rewriter_continuation.h
@@ -5,6 +5,8 @@
 #ifndef UI_EVENTS_EVENT_REWRITER_CONTINUATION_H_
 #define UI_EVENTS_EVENT_REWRITER_CONTINUATION_H_
 
+#include "base/compiler_specific.h"
+
 namespace ui {
 
 struct EventDispatchDetails;
diff --git a/ui/events/event_sink.h b/ui/events/event_sink.h
index e31c1be..df8c028 100644
--- a/ui/events/event_sink.h
+++ b/ui/events/event_sink.h
@@ -5,6 +5,7 @@
 #ifndef UI_EVENTS_EVENT_SINK_H_
 #define UI_EVENTS_EVENT_SINK_H_
 
+#include "base/compiler_specific.h"
 #include "ui/events/event_dispatcher.h"
 
 namespace ui {
diff --git a/ui/events/test/events_test_utils.h b/ui/events/test/events_test_utils.h
index 4921aa3..ade5f51 100644
--- a/ui/events/test/events_test_utils.h
+++ b/ui/events/test/events_test_utils.h
@@ -5,6 +5,7 @@
 #ifndef UI_EVENTS_TEST_EVENTS_TEST_UTILS_H_
 #define UI_EVENTS_TEST_EVENTS_TEST_UTILS_H_
 
+#include "base/compiler_specific.h"
 #include "ui/events/event.h"
 #include "ui/events/event_dispatcher.h"
 #include "ui/events/event_target.h"
diff --git a/ui/gfx/buffer_format_util.h b/ui/gfx/buffer_format_util.h
index a73b264b2..362b3d77 100644
--- a/ui/gfx/buffer_format_util.h
+++ b/ui/gfx/buffer_format_util.h
@@ -9,6 +9,7 @@
 
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gfx_export.h"
diff --git a/ui/gtk/gtk_ui.cc b/ui/gtk/gtk_ui.cc
index 83e7765e..62b05ec 100644
--- a/ui/gtk/gtk_ui.cc
+++ b/ui/gtk/gtk_ui.cc
@@ -79,7 +79,7 @@
 #if BUILDFLAG(OZONE_PLATFORM_WAYLAND)
 #define USE_WAYLAND
 #endif
-#if BUILDFLAG(OZONE_PLATFORM_X11) && !defined(USE_X11)
+#if BUILDFLAG(OZONE_PLATFORM_X11)
 #define USE_X11
 #endif
 
diff --git a/ui/message_center/views/notification_view_base.h b/ui/message_center/views/notification_view_base.h
index 0115330..ddb2760 100644
--- a/ui/message_center/views/notification_view_base.h
+++ b/ui/message_center/views/notification_view_base.h
@@ -243,9 +243,13 @@
     return image_container_view_;
   }
 
+  views::View* actions_row() { return actions_row_; }
+
   views::View* action_buttons_row() { return action_buttons_row_; }
   const views::View* action_buttons_row() const { return action_buttons_row_; }
 
+  NotificationInputContainer* inline_reply() { return inline_reply_; }
+
   const views::Label* status_view() const { return status_view_; }
   const std::vector<views::View*> item_views() const { return item_views_; }
 
diff --git a/ui/views/controls/combobox/combobox.h b/ui/views/controls/combobox/combobox.h
index b7a96a6..7314536 100644
--- a/ui/views/controls/combobox/combobox.h
+++ b/ui/views/controls/combobox/combobox.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/scoped_observation.h"
 #include "base/time/time.h"
 #include "ui/base/models/combobox_model.h"
diff --git a/ui/views/controls/styled_label.h b/ui/views/controls/styled_label.h
index dafc12b0..21bdd45 100644
--- a/ui/views/controls/styled_label.h
+++ b/ui/views/controls/styled_label.h
@@ -21,6 +21,7 @@
 #include "ui/gfx/range/range.h"
 #include "ui/gfx/text_constants.h"
 #include "ui/views/controls/link.h"
+#include "ui/views/metadata/view_factory.h"
 #include "ui/views/style/typography.h"
 #include "ui/views/view.h"
 
@@ -253,6 +254,21 @@
   gfx::HorizontalAlignment horizontal_alignment_ = gfx::ALIGN_LEFT;
 };
 
+BEGIN_VIEW_BUILDER(VIEWS_EXPORT, StyledLabel, View)
+VIEW_BUILDER_PROPERTY(const std::u16string&, Text)
+VIEW_BUILDER_PROPERTY(int, TextContext)
+VIEW_BUILDER_PROPERTY(int, DefaultTextStyle)
+VIEW_BUILDER_PROPERTY(int, LineHeight)
+VIEW_BUILDER_PROPERTY(const absl::optional<SkColor>&,
+                      DisplayedOnBackgroundColor)
+VIEW_BUILDER_PROPERTY(bool, AutoColorReadabilityEnabled)
+VIEW_BUILDER_PROPERTY(gfx::HorizontalAlignment, HorizontalAlignment)
+VIEW_BUILDER_METHOD(SizeToFit, int)
+VIEW_BUILDER_METHOD(AddStyleRange, gfx::Range, StyledLabel::RangeStyleInfo)
+END_VIEW_BUILDER
+
 }  // namespace views
 
+DEFINE_VIEW_BUILDER(VIEWS_EXPORT, views::StyledLabel)
+
 #endif  // UI_VIEWS_CONTROLS_STYLED_LABEL_H_
diff --git a/ui/views/widget/root_view.h b/ui/views/widget/root_view.h
index 56561544..e09dea37 100644
--- a/ui/views/widget/root_view.h
+++ b/ui/views/widget/root_view.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "ui/events/event_processor.h"
 #include "ui/views/focus/focus_manager.h"
diff --git a/ui/views/window/dialog_delegate.h b/ui/views/window/dialog_delegate.h
index f4a3261..edfda09 100644
--- a/ui/views/window/dialog_delegate.h
+++ b/ui/views/window/dialog_delegate.h
@@ -386,8 +386,8 @@
 VIEW_BUILDER_VIEW_TYPE_PROPERTY(views::View, FootnoteView)
 VIEW_BUILDER_PROPERTY(bool, FocusTraversesOut)
 VIEW_BUILDER_PROPERTY(bool, EnableArrowKeyTraversal)
-VIEW_BUILDER_PROPERTY(const gfx::ImageSkia&, Icon)
-VIEW_BUILDER_PROPERTY(const gfx::ImageSkia&, AppIcon)
+VIEW_BUILDER_PROPERTY(gfx::ImageSkia, Icon)
+VIEW_BUILDER_PROPERTY(gfx::ImageSkia, AppIcon)
 VIEW_BUILDER_PROPERTY(ui::ModalType, ModalType)
 VIEW_BUILDER_PROPERTY(bool, OwnedByWidget)
 VIEW_BUILDER_PROPERTY(bool, ShowCloseButton)
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.js b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.js
index 9be4aec..3f470c79 100644
--- a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.js
+++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.js
@@ -64,7 +64,7 @@
     const context = this.getCanvasContext_();
     context.clearRect(0, 0, this.canvasSize_, this.canvasSize_);
     context.fillStyle = getComputedStyle(this.$.qrCodeCanvas)
-                            .getPropertyValue('--cros-dark-icon-color-primary');
+                            .getPropertyValue('--cros-icon-color-primary-dark');
     let index = 0;
     for (let x = 0; x < response.qrCode.size; x++) {
       for (let y = 0; y < response.qrCode.size; y++) {
diff --git a/url/gurl_unittest.cc b/url/gurl_unittest.cc
index eb9df13..86fcb6f 100644
--- a/url/gurl_unittest.cc
+++ b/url/gurl_unittest.cc
@@ -18,19 +18,6 @@
 
 namespace {
 
-template<typename CHAR>
-void SetupReplacement(
-    void (Replacements<CHAR>::*func)(const CHAR*, const Component&),
-    Replacements<CHAR>* replacements,
-    const CHAR* str) {
-  if (str) {
-    Component comp;
-    if (str[0])
-      comp.len = static_cast<int>(strlen(str));
-    (replacements->*func)(str, comp);
-  }
-}
-
 // Returns the canonicalized string for the given URL string for the
 // GURLTest.Types test.
 std::string TypesTestCase(const char* src) {
@@ -496,60 +483,102 @@
   // The most important thing to do here is to check that the proper
   // canonicalizer gets called based on the scheme of the input.
   struct ReplaceCase {
+    using ApplyReplacementsFunc = GURL(const GURL&);
+
     const char* base;
-    const char* scheme;
-    const char* username;
-    const char* password;
-    const char* host;
-    const char* port;
-    const char* path;
-    const char* query;
-    const char* ref;
+    ApplyReplacementsFunc* apply_replacements;
     const char* expected;
   } replace_cases[] = {
-      {"http://www.google.com/foo/bar.html?foo#bar", nullptr, nullptr, nullptr,
-       nullptr, nullptr, "/", "", "", "http://www.google.com/"},
-      {"http://www.google.com/foo/bar.html?foo#bar", "javascript", "", "", "",
-       "", "window.open('foo');", "", "", "javascript:window.open('foo');"},
-      {"file:///C:/foo/bar.txt", "http", nullptr, nullptr, "www.google.com",
-       "99", "/foo", "search", "ref",
-       "http://www.google.com:99/foo?search#ref"},
+      {.base = "http://www.google.com/foo/bar.html?foo#bar",
+       .apply_replacements =
+           +[](const GURL& url) {
+             GURL::Replacements replacements;
+             replacements.SetPathStr("/");
+             replacements.ClearQuery();
+             replacements.ClearRef();
+             return url.ReplaceComponents(replacements);
+           },
+       .expected = "http://www.google.com/"},
+      {.base = "http://www.google.com/foo/bar.html?foo#bar",
+       .apply_replacements =
+           +[](const GURL& url) {
+             GURL::Replacements replacements;
+             replacements.SetSchemeStr("javascript");
+             replacements.ClearUsername();
+             replacements.ClearPassword();
+             replacements.ClearHost();
+             replacements.ClearPort();
+             replacements.SetPathStr("window.open('foo');");
+             replacements.ClearQuery();
+             replacements.ClearRef();
+             return url.ReplaceComponents(replacements);
+           },
+       .expected = "javascript:window.open('foo');"},
+      {.base = "file:///C:/foo/bar.txt",
+       .apply_replacements =
+           +[](const GURL& url) {
+             GURL::Replacements replacements;
+             replacements.SetSchemeStr("http");
+             replacements.SetHostStr("www.google.com");
+             replacements.SetPortStr("99");
+             replacements.SetPathStr("/foo");
+             replacements.SetQueryStr("search");
+             replacements.SetRefStr("ref");
+             return url.ReplaceComponents(replacements);
+           },
+       .expected = "http://www.google.com:99/foo?search#ref"},
 #ifdef WIN32
-      {"http://www.google.com/foo/bar.html?foo#bar", "file", "", "", "", "",
-       "c:\\", "", "", "file:///C:/"},
+      {.base = "http://www.google.com/foo/bar.html?foo#bar",
+       .apply_replacements =
+           +[](const GURL& url) {
+             GURL::Replacements replacements;
+             replacements.SetSchemeStr("file");
+             replacements.ClearUsername();
+             replacements.ClearPassword();
+             replacements.ClearHost();
+             replacements.ClearPort();
+             replacements.SetPathStr("c:\\");
+             replacements.ClearQuery();
+             replacements.ClearRef();
+             return url.ReplaceComponents(replacements);
+           },
+       .expected = "file:///C:/"},
 #endif
-      {"filesystem:http://www.google.com/foo/bar.html?foo#bar", nullptr,
-       nullptr, nullptr, nullptr, nullptr, "/", "", "",
-       "filesystem:http://www.google.com/foo/"},
+      {.base = "filesystem:http://www.google.com/foo/bar.html?foo#bar",
+       .apply_replacements =
+           +[](const GURL& url) {
+             GURL::Replacements replacements;
+             replacements.SetPathStr("/");
+             replacements.ClearQuery();
+             replacements.ClearRef();
+             return url.ReplaceComponents(replacements);
+           },
+       .expected = "filesystem:http://www.google.com/foo/"},
       // Lengthen the URL instead of shortening it, to test creation of
       // inner_url.
-      {"filesystem:http://www.google.com/foo/", nullptr, nullptr, nullptr,
-       nullptr, nullptr, "bar.html", "foo", "bar",
-       "filesystem:http://www.google.com/foo/bar.html?foo#bar"},
+      {.base = "filesystem:http://www.google.com/foo/",
+       .apply_replacements =
+           +[](const GURL& url) {
+             GURL::Replacements replacements;
+             replacements.SetPathStr("bar.html");
+             replacements.SetQueryStr("foo");
+             replacements.SetRefStr("bar");
+             return url.ReplaceComponents(replacements);
+           },
+       .expected = "filesystem:http://www.google.com/foo/bar.html?foo#bar"},
   };
 
-  for (size_t i = 0; i < base::size(replace_cases); i++) {
-    const ReplaceCase& cur = replace_cases[i];
-    GURL url(cur.base);
-    GURL::Replacements repl;
-    SetupReplacement(&GURL::Replacements::SetScheme, &repl, cur.scheme);
-    SetupReplacement(&GURL::Replacements::SetUsername, &repl, cur.username);
-    SetupReplacement(&GURL::Replacements::SetPassword, &repl, cur.password);
-    SetupReplacement(&GURL::Replacements::SetHost, &repl, cur.host);
-    SetupReplacement(&GURL::Replacements::SetPort, &repl, cur.port);
-    SetupReplacement(&GURL::Replacements::SetPath, &repl, cur.path);
-    SetupReplacement(&GURL::Replacements::SetQuery, &repl, cur.query);
-    SetupReplacement(&GURL::Replacements::SetRef, &repl, cur.ref);
-    GURL output = url.ReplaceComponents(repl);
+  for (const ReplaceCase& c : replace_cases) {
+    GURL output = c.apply_replacements(GURL(c.base));
 
-    EXPECT_EQ(replace_cases[i].expected, output.spec());
+    EXPECT_EQ(c.expected, output.spec());
 
     EXPECT_EQ(output.SchemeIsFileSystem(), output.inner_url() != NULL);
     if (output.SchemeIsFileSystem()) {
       // TODO(mmenke): inner_url()->spec() is currently the same as the spec()
       // for the GURL itself.  This should be fixed.
       // See https://crbug.com/619596
-      EXPECT_EQ(replace_cases[i].expected, output.inner_url()->spec());
+      EXPECT_EQ(c.expected, output.inner_url()->spec());
     }
   }
 }
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/BackgroundFetchTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/BackgroundFetchTest.java
index 4ca6e00..fede8abe 100644
--- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/BackgroundFetchTest.java
+++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/BackgroundFetchTest.java
@@ -25,6 +25,7 @@
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.weblayer.Browser;
 import org.chromium.weblayer.OpenUrlCallback;
@@ -57,6 +58,7 @@
 
     @Test
     @LargeTest
+    @FlakyTest(message = "https://crbug.com/1272010")
     @MinAndroidSdkLevel(Build.VERSION_CODES.M)
     public void basic() throws Exception {
         Browser browser = mActivity.getBrowser();
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/DownloadCallbackTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/DownloadCallbackTest.java
index 5470b35f..bce4352 100644
--- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/DownloadCallbackTest.java
+++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/DownloadCallbackTest.java
@@ -240,8 +240,10 @@
         mCallback.waitForStarted();
         mCallback.waitForCompleted();
 
+        // Location varies depending upon version. See PathUtils.getDownloadsDirectory().
         Assert.assertTrue(mCallback.mLocation.contains(
-                "org.chromium.weblayer.shell/cache/weblayer/Downloads/"));
+                                  "org.chromium.weblayer.shell/cache/weblayer/Downloads/")
+                || mCallback.mLocation.contains("/media/"));
         Assert.assertTrue(mCallback.mFileName.contains("test"));
         Assert.assertEquals(DownloadState.COMPLETE, mCallback.mState);
         Assert.assertEquals(DownloadError.NO_ERROR, mCallback.mError);
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
index 14d7a7f..75ab2ffa 100644
--- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
+++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
@@ -1404,6 +1404,7 @@
         assertStreamContent();
     }
 
+    @DisabledTest(message = "https://crbug.com/1271989")
     @Test
     @SmallTest
     public void testWebResponseNoStore() throws Exception {
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java
index 414c9f8..663e0da0 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java
@@ -32,6 +32,7 @@
 import org.chromium.components.omnibox.SecurityButtonAnimationDelegate;
 import org.chromium.components.omnibox.SecurityStatusIcon;
 import org.chromium.components.page_info.PageInfoController;
+import org.chromium.components.page_info.PageInfoHighlight;
 import org.chromium.components.security_state.ConnectionSecurityLevel;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.weblayer_private.interfaces.IObjectWrapper;
@@ -132,7 +133,7 @@
         PageInfoController.show(mBrowserImpl.getWindowAndroid().getActivity().get(), webContents,
                 publisherUrl, PageInfoController.OpenedFromSource.TOOLBAR,
                 PageInfoControllerDelegateImpl.create(webContents),
-                PageInfoController.NO_HIGHLIGHTED_PERMISSION);
+                PageInfoHighlight.noHighlight());
     }
 
     protected class UrlBarView
diff --git a/weblayer/browser/translate_client_impl.cc b/weblayer/browser/translate_client_impl.cc
index bf3d87b..7e89545 100644
--- a/weblayer/browser/translate_client_impl.cc
+++ b/weblayer/browser/translate_client_impl.cc
@@ -57,7 +57,6 @@
     : content::WebContentsObserver(web_contents),
       content::WebContentsUserData<TranslateClientImpl>(*web_contents),
       translate_driver_(*web_contents,
-                        &web_contents->GetController(),
                         /*url_language_histogram=*/nullptr,
                         /*translate_model_service=*/nullptr),
       translate_manager_(new translate::TranslateManager(