diff --git a/.gn b/.gn
index cf571d7..1b870bc 100644
--- a/.gn
+++ b/.gn
@@ -171,7 +171,6 @@
   "//sandbox/linux:*",  # 13 errors
   "//sandbox/win:*",  # 7 errors
 
-  "//third_party/crashpad/crashpad/client:*",  # 1 error
   "//third_party/crashpad/crashpad/compat:*",  # 2 errors
   "//third_party/crashpad/crashpad/snapshot:*",  # 1 error
   "//third_party/crashpad/crashpad/test:*",  # 2 errors
diff --git a/DEPS b/DEPS
index 18600e7..d225f6d 100644
--- a/DEPS
+++ b/DEPS
@@ -211,7 +211,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '2e54a1e7fc49e1c1c659d7be659b832954112106',
+  'angle_revision': 'ad985fcdd806a26343b9b5f8408e551b515493e5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -219,7 +219,7 @@
   # 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': 'ef190fbf8b2d7df18e775953bcaea5b68d20395f',
+  'pdfium_revision': '46ff50212421a1959bc4adbe476ffeac2c6aa593',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -250,7 +250,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '0636dc8af1e502c343b126b50f3a0dbec8f3fc26',
+  'freetype_revision': 'fd7f92b6f008e0684c3eb8308aca92e20382506e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -278,7 +278,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': '6f9ad8fe398c5a2a8b17ac5edd1a7dba75442781',
+  'devtools_frontend_revision': 'a3ee39b0f50e14f6d3a4bb0103d26436c6e9d37c',
   # 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.
@@ -554,7 +554,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '73e404888d1e98e930e62b68f864b60e264c32f3',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'd0ac5f2c8396ba7c5cd278b7892330effe7aa093',
       'condition': 'checkout_ios',
   },
 
@@ -905,7 +905,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0e2aee7e979635b6086975009e21bacd6c6c2e64',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6dc9cc301f553f1a50608b579083997e63b16e14',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1270,7 +1270,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '52852a8ec96d2db2a97fffd2ea9a62e58d65845d',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '7cb370fb0a2f055e7781a0924e3a275d7adedf6b',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1348,7 +1348,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': 'E4N2C-h-D4Q8yrrjhY-MF-wOIKLW6q4A1xxR7lAY57QC'
+              'version': 'daCtImfwROvNf-7jcpyqZ6KMCGlIQv9BROkyXnulGioC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1506,7 +1506,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '66460536ee975a3e98931b7b40a661a63fd9cd57',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'e7c79fd3d66e0f6c54c027f880a8b1682ebae58a',
+    Var('webrtc_git') + '/src.git' + '@' + '14cad9fa35dd9260e83c5af261836b58a7137edd',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1578,7 +1578,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e8537ae5c80ccb9971796ac5d49a8a2c78a1faac',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@198fe4cf98e6681a0347dc8809c456501f8890f5',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 42db1c9..c4d7ea2 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -2396,7 +2396,8 @@
                      'vecore+watch-network@google.com'],
     'chromeos_tast_control': ['chromeos-engprod+watch@google.com',
                               'bpastene+watch@chromium.org',
-                              'mukai+watch@chromium.org'],
+                              'mukai+watch@chromium.org',
+                              'chrome-os-gardeners+watch@google.com'],
     'chromeos_timezone': ['alemate+watch@chromium.org'],
     'chromeos_webui': ['alemate+watch@chromium.org'],
     'chromeos_wifi_sync': ['jonmann+watch@chromium.org',
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentCaptureTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentCaptureTest.java
index 32302002..6a0caf3 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentCaptureTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentCaptureTest.java
@@ -93,6 +93,7 @@
         public static final int CONTENT_UPDATED = 2;
         public static final int CONTENT_REMOVED = 3;
         public static final int SESSION_REMOVED = 4;
+        public static final int TITLE_UPDATED = 5;
 
         public TestAwContentCaptureConsumer(WebContents webContents) {
             super(webContents);
@@ -144,6 +145,13 @@
         }
 
         @Override
+        public void onTitleUpdated(ContentCaptureFrame contentCaptureFrame) {
+            mTitleUpdatedFrame = contentCaptureFrame;
+            mCallbacks.add(TITLE_UPDATED);
+            mCallbackHelper.notifyCalled();
+        }
+
+        @Override
         public boolean shouldCapture(String[] urls) {
             if (mController == null) return true;
             return mController.shouldCapture(urls);
@@ -220,6 +228,7 @@
         private volatile FrameSession mCurrentFrameSession;
         private volatile FrameSession mRemovedSession;
         private volatile long[] mRemovedIds;
+        private volatile ContentCaptureFrame mTitleUpdatedFrame;
         private volatile ArrayList<Integer> mCallbacks = new ArrayList<Integer>();
 
         private CallbackHelper mCallbackHelper = new CallbackHelper();
@@ -316,12 +325,14 @@
     }
 
     private static void verifyFrame(
-            Long expectedId, String expectedUrl, ContentCaptureFrame result) {
+            Long expectedId, String expectedUrl, String title, ContentCaptureFrame result) {
         if (expectedId == null || expectedId.longValue() == 0) {
             Assert.assertNotEquals(0, result.getId());
         } else {
             Assert.assertEquals(expectedId.longValue(), result.getId());
         }
+        Assert.assertEquals(title, result.getTitle());
+        Assert.assertEquals(title, result.getText());
         Assert.assertEquals(expectedUrl, result.getUrl());
         Assert.assertFalse(result.getBounds().isEmpty());
     }
@@ -330,7 +341,8 @@
         if (expected == null && (result == null || result.isEmpty())) return;
         Assert.assertEquals(expected.size(), result.size());
         for (int i = 0; i < expected.size(); i++) {
-            verifyFrame(expected.get(i).getId(), expected.get(i).getUrl(), result.get(i));
+            verifyFrame(expected.get(i).getId(), expected.get(i).getUrl(),
+                    expected.get(i).getTitle(), result.get(i));
         }
     }
 
@@ -355,10 +367,17 @@
     }
 
     private static void verifyCapturedContent(FrameSession expectedParentSession,
-            Long expectedFrameId, String expectedUrl, Set<String> expectedContent,
-            Set<Long> unexpectedContentIds, FrameSession parentResult, ContentCaptureFrame result) {
+            Long expectedFrameId, String expectedUrl, String expectedTitle,
+            Set<String> expectedContent, Set<Long> unexpectedContentIds, FrameSession parentResult,
+            ContentCaptureFrame result) {
         verifyFrameSession(expectedParentSession, parentResult);
-        verifyFrame(expectedFrameId, expectedUrl, result);
+        // Title is only set to main frame.
+        if (expectedParentSession == null || expectedParentSession.isEmpty()) {
+            verifyFrame(expectedFrameId, expectedUrl, expectedTitle, result);
+        } else {
+            verifyFrame(expectedFrameId, expectedUrl, null, result);
+        }
+
         verifyContent(expectedContent, unexpectedContentIds, null, result);
     }
 
@@ -366,7 +385,7 @@
             Long expectedFrameId, String expectedUrl, Set<String> expectedContent,
             Set<Long> expectedContentIds, FrameSession parentResult, ContentCaptureFrame result) {
         verifyFrameSession(expectedParentSession, parentResult);
-        verifyFrame(expectedFrameId, expectedUrl, result);
+        verifyFrame(expectedFrameId, expectedUrl, null, result);
         verifyContent(expectedContent, null, expectedContentIds, result);
     }
 
@@ -382,7 +401,7 @@
     private static void verifyRemovedContent(Long expectedFrameId, String expectedUrl,
             Set<Long> expectedIds, FrameSession resultFrame, long[] result) {
         Assert.assertEquals(1, resultFrame.size());
-        verifyFrame(expectedFrameId, expectedUrl, resultFrame.get(0));
+        verifyFrame(expectedFrameId, expectedUrl, null, resultFrame.get(0));
         verifyRemovedIds(expectedIds, result);
     }
 
@@ -469,7 +488,7 @@
         Long frameId = null;
         Set<Long> capturedContentIds = null;
         // Verify only on-screen content is captured.
-        verifyCapturedContent(null, frameId, url, toStringSet("Hello"), capturedContentIds,
+        verifyCapturedContent(null, frameId, url, null, toStringSet("Hello"), capturedContentIds,
                 mConsumer.getParentFrame(), mConsumer.getCapturedContent());
 
         frameId = Long.valueOf(mConsumer.getCapturedContent().getId());
@@ -477,7 +496,7 @@
         runAndVerifyCallbacks(() -> {
             scrollToBottom();
         }, toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED));
-        verifyCapturedContent(null, frameId, url, toStringSet("world"), capturedContentIds,
+        verifyCapturedContent(null, frameId, url, null, toStringSet("world"), capturedContentIds,
                 mConsumer.getParentFrame(), mConsumer.getCapturedContent());
 
         final String newContentId = "new_content_id";
@@ -488,7 +507,7 @@
             insertElement(newContentId, newContent);
             scrollToTop();
         }, toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED));
-        verifyCapturedContent(null, frameId, url, toStringSet(newContent), capturedContentIds,
+        verifyCapturedContent(null, frameId, url, null, toStringSet(newContent), capturedContentIds,
                 mConsumer.getParentFrame(), mConsumer.getCapturedContent());
 
         // Changed previous added element, this will trigger remove/capture events.
@@ -501,8 +520,8 @@
                         TestAwContentCaptureConsumer.CONTENT_CAPTURED));
         verifyRemovedContent(frameId, url, toLongSet(removedContentId),
                 mConsumer.getCurrentFrameSession(), mConsumer.getRemovedIds());
-        verifyCapturedContent(null, frameId, url, toStringSet(newContent2), capturedContentIds,
-                mConsumer.getParentFrame(), mConsumer.getCapturedContent());
+        verifyCapturedContent(null, frameId, url, null, toStringSet(newContent2),
+                capturedContentIds, mConsumer.getParentFrame(), mConsumer.getCapturedContent());
 
         // Remove the element.
         removedContentId = mConsumer.getCapturedContent().getChildren().get(0).getId();
@@ -531,7 +550,7 @@
         Long frameId = null;
         Set<Long> capturedContentIds = null;
         // Verify only on-screen content is captured.
-        verifyCapturedContent(null, frameId, url, toStringSet("Hello"), capturedContentIds,
+        verifyCapturedContent(null, frameId, url, null, toStringSet("Hello"), capturedContentIds,
                 mConsumer.getParentFrame(), mConsumer.getCapturedContent());
 
         // Scrolls to the bottom, the node that became invisible is removed, and the content
@@ -543,7 +562,7 @@
                                       -> { scrollToBottom(); },
                 toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED,
                         TestAwContentCaptureConsumer.CONTENT_REMOVED));
-        verifyCapturedContent(null, frameId, url, toStringSet("world"), capturedContentIds,
+        verifyCapturedContent(null, frameId, url, null, toStringSet("world"), capturedContentIds,
                 mConsumer.getParentFrame(), mConsumer.getCapturedContent());
         verifyRemovedContent(frameId, url, toLongSet(contentHelloId),
                 mConsumer.getCurrentFrameSession(), mConsumer.getRemovedIds());
@@ -561,7 +580,7 @@
                 },
                 toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED,
                         TestAwContentCaptureConsumer.CONTENT_REMOVED));
-        verifyCapturedContent(null, frameId, url, toStringSet(newContent, "Hello"),
+        verifyCapturedContent(null, frameId, url, null, toStringSet(newContent, "Hello"),
                 capturedContentIds, mConsumer.getParentFrame(), mConsumer.getCapturedContent());
         verifyRemovedContent(frameId, url, toLongSet(contentWorldId),
                 mConsumer.getCurrentFrameSession(), mConsumer.getRemovedIds());
@@ -580,8 +599,8 @@
                         TestAwContentCaptureConsumer.CONTENT_CAPTURED));
         verifyRemovedContent(frameId, url, toLongSet(removedContentId),
                 mConsumer.getCurrentFrameSession(), mConsumer.getRemovedIds());
-        verifyCapturedContent(null, frameId, url, toStringSet(newContent2), capturedContentIds,
-                mConsumer.getParentFrame(), mConsumer.getCapturedContent());
+        verifyCapturedContent(null, frameId, url, null, toStringSet(newContent2),
+                capturedContentIds, mConsumer.getParentFrame(), mConsumer.getCapturedContent());
 
         // Remove the element.
         removedContentId = mConsumer.getCapturedContent().getChildren().get(0).getId();
@@ -608,7 +627,7 @@
         Long frameId = null;
         Set<Long> capturedContentIds = null;
         // Verify only on-screen content is captured.
-        verifyCapturedContent(null, frameId, url, toStringSet("Hello"), capturedContentIds,
+        verifyCapturedContent(null, frameId, url, null, toStringSet("Hello"), capturedContentIds,
                 mConsumer.getParentFrame(), mConsumer.getCapturedContent());
 
         // Change the content, we shall get content updated callback.
@@ -640,7 +659,7 @@
         }, toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED));
         Long frameId = null;
         Set<Long> capturedContentIds = null;
-        verifyCapturedContent(null, frameId, url, toStringSet("Hello"), capturedContentIds,
+        verifyCapturedContent(null, frameId, url, null, toStringSet("Hello"), capturedContentIds,
                 mConsumer.getParentFrame(), mConsumer.getCapturedContent());
 
         // Keep a copy of current session to verify it removed later.
@@ -649,7 +668,7 @@
         int[] expectedCallbacks = toIntArray(TestAwContentCaptureConsumer.SESSION_REMOVED,
                 TestAwContentCaptureConsumer.CONTENT_CAPTURED);
         runAndVerifyCallbacks(() -> { loadUrlSync(url2); }, expectedCallbacks);
-        verifyCapturedContent(null, frameId, url2, toStringSet("World"), capturedContentIds,
+        verifyCapturedContent(null, frameId, url2, null, toStringSet("World"), capturedContentIds,
                 mConsumer.getParentFrame(), mConsumer.getCapturedContent());
         // Verify previous session has been removed.
         verifyFrameSession(removedSession, mConsumer.getRemovedSession());
@@ -679,7 +698,7 @@
 
         FrameSession expectedParentFrameSession = createFrameSession(mainFrameUrl);
         Long frameId = null;
-        verifyCapturedContent(expectedParentFrameSession, frameId, subFrameUrl,
+        verifyCapturedContent(expectedParentFrameSession, frameId, subFrameUrl, null,
                 toStringSet("Hello"), null, mConsumer.getParentFrame(),
                 mConsumer.getCapturedContent());
 
@@ -797,4 +816,45 @@
             AwActivityTestRule.pollInstrumentationThread(() -> mAwContents.isPageVisible());
         }, toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED));
     }
+
+    @Test
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testTitle() throws Throwable {
+        final String response = "<html><head><title>Hello</title></head><body>"
+                + "<p>world</p>"
+                + "</body></html>";
+        final String url = mWebServer.setResponse(MAIN_FRAME_FILE, response, null);
+        runAndVerifyCallbacks(() -> {
+            loadUrlSync(url);
+        }, toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED));
+        Long frameId = null;
+        Set<Long> capturedContentIds = null;
+        // Verify only on-screen content is captured.
+        verifyCapturedContent(null, frameId, url, "Hello", toStringSet("world"), capturedContentIds,
+                mConsumer.getParentFrame(), mConsumer.getCapturedContent());
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testUpdateTitle() throws Throwable {
+        final String response = "<html><head><title>Hello</title></head><body>"
+                + "<p>world</p>"
+                + "</body></html>";
+        final String url = mWebServer.setResponse(MAIN_FRAME_FILE, response, null);
+        runAndVerifyCallbacks(() -> {
+            loadUrlSync(url);
+        }, toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED));
+        Long frameId = null;
+        Set<Long> capturedContentIds = null;
+        // Verify only on-screen content is captured.
+        verifyCapturedContent(null, frameId, url, "Hello", toStringSet("world"), capturedContentIds,
+                mConsumer.getParentFrame(), mConsumer.getCapturedContent());
+
+        // Update the title and verify the result.
+        runAndVerifyCallbacks(() -> {
+            runScript("document.title='hello world'");
+        }, toIntArray(TestAwContentCaptureConsumer.TITLE_UPDATED));
+    }
 }
diff --git a/ash/accelerators/accelerator_controller_impl.cc b/ash/accelerators/accelerator_controller_impl.cc
index c25419e..1187204 100644
--- a/ash/accelerators/accelerator_controller_impl.cc
+++ b/ash/accelerators/accelerator_controller_impl.cc
@@ -19,6 +19,7 @@
 #include "ash/capture_mode/capture_mode_controller.h"
 #include "ash/capture_mode/capture_mode_metrics.h"
 #include "ash/clipboard/clipboard_history_controller_impl.h"
+#include "ash/constants/ash_features.h"
 #include "ash/debug.h"
 #include "ash/display/display_configuration_controller.h"
 #include "ash/display/display_move_window_util.h"
@@ -94,7 +95,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
 #include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/devicetype.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/ui/vector_icons/vector_icons.h"
diff --git a/ash/ambient/ambient_controller.cc b/ash/ambient/ambient_controller.cc
index 075a6fa..616ed95 100644
--- a/ash/ambient/ambient_controller.cc
+++ b/ash/ambient/ambient_controller.cc
@@ -13,6 +13,7 @@
 #include "ash/ambient/ui/ambient_container_view.h"
 #include "ash/ambient/ui/ambient_view_delegate.h"
 #include "ash/ambient/util/ambient_util.h"
+#include "ash/constants/ash_features.h"
 #include "ash/login/ui/lock_screen.h"
 #include "ash/public/cpp/ambient/ambient_backend_controller.h"
 #include "ash/public/cpp/ambient/ambient_client.h"
@@ -35,7 +36,6 @@
 #include "base/timer/timer.h"
 #include "build/buildflag.h"
 #include "chromeos/assistant/buildflags.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/dbus/power_manager/backlight.pb.h"
 #include "chromeos/dbus/power_manager/idle.pb.h"
diff --git a/ash/ambient/backdrop/ambient_backend_controller_impl.cc b/ash/ambient/backdrop/ambient_backend_controller_impl.cc
index a8601c3..cdff116 100644
--- a/ash/ambient/backdrop/ambient_backend_controller_impl.cc
+++ b/ash/ambient/backdrop/ambient_backend_controller_impl.cc
@@ -11,6 +11,7 @@
 
 #include "ash/ambient/ambient_controller.h"
 #include "ash/ambient/util/ambient_util.h"
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ambient/ambient_backend_controller.h"
 #include "ash/public/cpp/ambient/ambient_client.h"
 #include "ash/public/cpp/ambient/ambient_metrics.h"
@@ -27,7 +28,6 @@
 #include "base/time/time.h"
 #include "chromeos/assistant/internal/ambient/backdrop_client_config.h"
 #include "chromeos/assistant/internal/proto/google3/backdrop/backdrop.pb.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
 #include "net/base/load_flags.h"
diff --git a/ash/ambient/util/ambient_util.cc b/ash/ambient/util/ambient_util.cc
index 243c685..e623c46 100644
--- a/ash/ambient/util/ambient_util.cc
+++ b/ash/ambient/util/ambient_util.cc
@@ -4,10 +4,10 @@
 
 #include "ash/ambient/util/ambient_util.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ambient/ambient_backend_controller.h"
 #include "ash/public/cpp/ambient/ambient_client.h"
 #include "base/no_destructor.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/shadow_value.h"
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index efab054..d9597a43 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -22,6 +22,7 @@
 #include "ash/assistant/ui/assistant_view_delegate.h"
 #include "ash/assistant/util/assistant_util.h"
 #include "ash/assistant/util/deep_link_util.h"
+#include "ash/constants/ash_features.h"
 #include "ash/home_screen/home_screen_controller.h"
 #include "ash/keyboard/ui/keyboard_ui_controller.h"
 #include "ash/public/cpp/app_list/app_list_client.h"
@@ -54,7 +55,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_change_registrar.h"
diff --git a/ash/app_list/views/app_list_view_unittest.cc b/ash/app_list/views/app_list_view_unittest.cc
index a92b9af8..6cdb2613 100644
--- a/ash/app_list/views/app_list_view_unittest.cc
+++ b/ash/app_list/views/app_list_view_unittest.cc
@@ -37,6 +37,7 @@
 #include "ash/app_list/views/search_result_view.h"
 #include "ash/app_list/views/suggestion_chip_container_view.h"
 #include "ash/app_list/views/test/apps_grid_view_test_api.h"
+#include "ash/constants/ash_features.h"
 #include "ash/keyboard/ui/keyboard_ui_controller.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
@@ -52,7 +53,6 @@
 #include "base/test/icu_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/compositor/layer_animator.h"
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 0357ee2e7..71dc3993 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -1235,6 +1235,9 @@
       <message name="IDS_ASH_STYLUS_BATTERY_PERCENT_ACCESSIBLE" desc="The message used by accessibility to show stylus battery level.">
         Stylus battery at <ph name="percentage">$1<ex>56</ex></ph> percent.
       </message>
+      <message name="IDS_ASH_STYLUS_BATTERY_STATUS_STALE_TOOLTIP" desc="Tooltip message that indicates to the user that the stylus has not been used in over a week">
+        Stylus has not been used in over a week
+      </message>
       <message name="IDS_ASH_STYLUS_TOOLS_CAPTURE_REGION_ACTION" desc="Title of the capture region action in the stylus tools (a pop-up panel next to the status tray). This causes a partial screenshot to be taken (the user selects an area of the screen to take a screenshot of).">
         Capture region
       </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_STYLUS_BATTERY_STATUS_STALE_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STYLUS_BATTERY_STATUS_STALE_TOOLTIP.png.sha1
new file mode 100644
index 0000000..7416230
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STYLUS_BATTERY_STATUS_STALE_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+96387ecdb489c0aaf02f8e784b4bd6a5338f3be3
\ No newline at end of file
diff --git a/ash/clipboard/clipboard_history_controller_unittest.cc b/ash/clipboard/clipboard_history_controller_unittest.cc
index e1336cd..51b54c7547 100644
--- a/ash/clipboard/clipboard_history_controller_unittest.cc
+++ b/ash/clipboard/clipboard_history_controller_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "ash/app_list/app_list_controller_impl.h"
 #include "ash/clipboard/clipboard_history.h"
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/clipboard_image_model_factory.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
@@ -19,7 +20,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/unguessable_token.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/clipboard/clipboard_buffer.h"
diff --git a/ash/clipboard/clipboard_history_resource_manager_unittest.cc b/ash/clipboard/clipboard_history_resource_manager_unittest.cc
index 553d68b..50e074a 100644
--- a/ash/clipboard/clipboard_history_resource_manager_unittest.cc
+++ b/ash/clipboard/clipboard_history_resource_manager_unittest.cc
@@ -11,6 +11,7 @@
 #include "ash/clipboard/clipboard_history_controller_impl.h"
 #include "ash/clipboard/clipboard_history_item.h"
 #include "ash/clipboard/test_support/clipboard_history_item_builder.h"
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/clipboard_image_model_factory.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
@@ -18,7 +19,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/icu_test_util.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
diff --git a/ash/clipboard/clipboard_history_unittest.cc b/ash/clipboard/clipboard_history_unittest.cc
index eab03a2..9624c83 100644
--- a/ash/clipboard/clipboard_history_unittest.cc
+++ b/ash/clipboard/clipboard_history_unittest.cc
@@ -11,13 +11,13 @@
 #include "ash/clipboard/clipboard_history_item.h"
 #include "ash/clipboard/clipboard_history_util.h"
 #include "ash/clipboard/scoped_clipboard_history_pause_impl.h"
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/clipboard_image_model_factory.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/clipboard/clipboard.h"
diff --git a/ash/clipboard/clipboard_nudge_controller.cc b/ash/clipboard/clipboard_nudge_controller.cc
index 99489ec6..51c2eb5 100644
--- a/ash/clipboard/clipboard_nudge_controller.cc
+++ b/ash/clipboard/clipboard_nudge_controller.cc
@@ -8,6 +8,7 @@
 #include "ash/clipboard/clipboard_history_util.h"
 #include "ash/clipboard/clipboard_nudge.h"
 #include "ash/clipboard/clipboard_nudge_constants.h"
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
@@ -16,7 +17,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
 #include "base/util/values/values_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
diff --git a/ash/clipboard/clipboard_nudge_controller_unittest.cc b/ash/clipboard/clipboard_nudge_controller_unittest.cc
index c89dd42..2c420bc5 100644
--- a/ash/clipboard/clipboard_nudge_controller_unittest.cc
+++ b/ash/clipboard/clipboard_nudge_controller_unittest.cc
@@ -7,13 +7,13 @@
 #include "ash/clipboard/clipboard_history.h"
 #include "ash/clipboard/clipboard_history_controller_impl.h"
 #include "ash/clipboard/clipboard_nudge_constants.h"
+#include "ash/constants/ash_features.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_clock.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/clipboard/clipboard_data.h"
 #include "ui/base/clipboard/clipboard_non_backed.h"
 
diff --git a/ash/constants/DEPS b/ash/constants/DEPS
new file mode 100644
index 0000000..b89541c
--- /dev/null
+++ b/ash/constants/DEPS
@@ -0,0 +1,7 @@
+noparent = True
+
+include_rules = [
+  "-ash",
+  "+ash/constants",
+  "+base",
+]
diff --git a/ash/constants/OWNERS b/ash/constants/OWNERS
new file mode 100644
index 0000000..1a79c387c
--- /dev/null
+++ b/ash/constants/OWNERS
@@ -0,0 +1,2 @@
+per-file ash_features.cc=*
+per-file ash_features.h=*
diff --git a/chromeos/constants/chromeos_features.cc b/ash/constants/ash_features.cc
similarity index 99%
rename from chromeos/constants/chromeos_features.cc
rename to ash/constants/ash_features.cc
index c591ef8..887e880 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/ash/constants/ash_features.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/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
diff --git a/chromeos/constants/chromeos_features.h b/ash/constants/ash_features.h
similarity index 98%
rename from chromeos/constants/chromeos_features.h
rename to ash/constants/ash_features.h
index 8b9dc75d..05ca402 100644
--- a/chromeos/constants/chromeos_features.h
+++ b/ash/constants/ash_features.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_CONSTANTS_CHROMEOS_FEATURES_H_
-#define CHROMEOS_CONSTANTS_CHROMEOS_FEATURES_H_
+#ifndef ASH_CONSTANTS_ASH_FEATURES_H_
+#define ASH_CONSTANTS_ASH_FEATURES_H_
 
 #include "base/component_export.h"
 #include "base/feature_list.h"
@@ -399,4 +399,4 @@
 }
 }  // namespace ash
 
-#endif  // CHROMEOS_CONSTANTS_CHROMEOS_FEATURES_H_
+#endif  // ASH_CONSTANTS_ASH_FEATURES_H_
diff --git a/ash/dbus/ash_dbus_services.cc b/ash/dbus/ash_dbus_services.cc
index 2d528c1d..63d088e 100644
--- a/ash/dbus/ash_dbus_services.cc
+++ b/ash/dbus/ash_dbus_services.cc
@@ -4,13 +4,13 @@
 
 #include "ash/dbus/ash_dbus_services.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/dbus/display_service_provider.h"
 #include "ash/dbus/gesture_properties_service_provider.h"
 #include "ash/dbus/liveness_service_provider.h"
 #include "ash/dbus/url_handler_service_provider.h"
 #include "ash/dbus/user_authentication_service_provider.h"
 #include "base/feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/services/cros_dbus_service.h"
 #include "dbus/object_path.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
diff --git a/ash/keyboard/virtual_keyboard_controller.cc b/ash/keyboard/virtual_keyboard_controller.cc
index c7f50ec9..16c2154 100644
--- a/ash/keyboard/virtual_keyboard_controller.cc
+++ b/ash/keyboard/virtual_keyboard_controller.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/ime/ime_controller_impl.h"
 #include "ash/keyboard/keyboard_controller_impl.h"
 #include "ash/keyboard/ui/keyboard_ui_controller.h"
@@ -19,7 +20,6 @@
 #include "base/callback_helpers.h"
 #include "base/feature_list.h"
 #include "base/strings/string_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/emoji/emoji_panel_helper.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc
index 04dd5b2..8604b7b3 100644
--- a/ash/login/ui/lock_contents_view.cc
+++ b/ash/login/ui/lock_contents_view.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "ash/accelerators/accelerator_controller_impl.h"
+#include "ash/constants/ash_features.h"
 #include "ash/detachable_base/detachable_base_pairing_status.h"
 #include "ash/focus_cycler.h"
 #include "ash/ime/ime_controller_impl.h"
@@ -53,7 +54,6 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/components/proximity_auth/public/mojom/auth_type.mojom.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "chromeos/ui/vector_icons/vector_icons.h"
 #include "components/user_manager/known_user.h"
diff --git a/ash/login/ui/lock_contents_view_unittest.cc b/ash/login/ui/lock_contents_view_unittest.cc
index bc358c5..614bedc43 100644
--- a/ash/login/ui/lock_contents_view_unittest.cc
+++ b/ash/login/ui/lock_contents_view_unittest.cc
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "ash/child_accounts/parent_access_controller_impl.h"
+#include "ash/constants/ash_features.h"
 #include "ash/detachable_base/detachable_base_pairing_status.h"
 #include "ash/login/login_screen_controller.h"
 #include "ash/login/mock_login_screen_client.h"
@@ -49,7 +50,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/timer/mock_timer.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "chromeos/dbus/power_manager/suspend.pb.h"
 #include "components/prefs/pref_service.h"
diff --git a/ash/login/ui/login_auth_user_view_unittest.cc b/ash/login/ui/login_auth_user_view_unittest.cc
index 78b734dd4..0d301e81 100644
--- a/ash/login/ui/login_auth_user_view_unittest.cc
+++ b/ash/login/ui/login_auth_user_view_unittest.cc
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 #include "ash/login/ui/login_auth_user_view.h"
+
+#include "ash/constants/ash_features.h"
 #include "ash/login/mock_login_screen_client.h"
 #include "ash/login/ui/login_password_view.h"
 #include "ash/login/ui/login_pin_input_view.h"
@@ -16,7 +18,6 @@
 #include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/event.h"
diff --git a/ash/login/ui/login_pin_input_view.cc b/ash/login/ui/login_pin_input_view.cc
index 8a66a8f..e7743168 100644
--- a/ash/login/ui/login_pin_input_view.cc
+++ b/ash/login/ui/login_pin_input_view.cc
@@ -4,6 +4,7 @@
 
 #include "ash/login/ui/login_pin_input_view.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/login/ui/access_code_input.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "base/bind.h"
@@ -11,7 +12,6 @@
 #include "base/callback_helpers.h"
 #include "base/optional.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/accessibility/ax_enums.mojom-shared.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/ash/public/cpp/external_arc/message_center/arc_notification_surface_impl.cc b/ash/public/cpp/external_arc/message_center/arc_notification_surface_impl.cc
index 256a720b2..c79b8f19 100644
--- a/ash/public/cpp/external_arc/message_center/arc_notification_surface_impl.cc
+++ b/ash/public/cpp/external_arc/message_center/arc_notification_surface_impl.cc
@@ -4,9 +4,9 @@
 
 #include "ash/public/cpp/external_arc/message_center/arc_notification_surface_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/check_op.h"
 #include "base/feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/exo/notification_surface.h"
 #include "components/exo/surface.h"
 #include "ui/aura/client/aura_constants.h"
diff --git a/ash/public/cpp/views_text_services_context_menu_impl.cc b/ash/public/cpp/views_text_services_context_menu_impl.cc
index 155aa07..346bc38a5 100644
--- a/ash/public/cpp/views_text_services_context_menu_impl.cc
+++ b/ash/public/cpp/views_text_services_context_menu_impl.cc
@@ -4,8 +4,8 @@
 
 #include "ash/public/cpp/views_text_services_context_menu_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/clipboard_history_controller.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/pointer/touch_editing_controller.h"
 #include "ui/strings/grit/ui_strings.h"
diff --git a/ash/quick_answers/quick_answers_controller_impl.cc b/ash/quick_answers/quick_answers_controller_impl.cc
index 2696ff74..2300679 100644
--- a/ash/quick_answers/quick_answers_controller_impl.cc
+++ b/ash/quick_answers/quick_answers_controller_impl.cc
@@ -4,13 +4,13 @@
 
 #include "ash/quick_answers/quick_answers_controller_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/new_window_delegate.h"
 #include "ash/quick_answers/quick_answers_ui_controller.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "chromeos/components/quick_answers/quick_answers_notice.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
diff --git a/ash/quick_answers/quick_answers_controller_unittest.cc b/ash/quick_answers/quick_answers_controller_unittest.cc
index 279151c..8f5d517 100644
--- a/ash/quick_answers/quick_answers_controller_unittest.cc
+++ b/ash/quick_answers/quick_answers_controller_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "ash/quick_answers/quick_answers_controller_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/quick_answers/quick_answers_ui_controller.h"
 #include "ash/quick_answers/ui/quick_answers_view.h"
 #include "ash/quick_answers/ui/user_notice_view.h"
@@ -11,7 +12,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "chromeos/components/quick_answers/quick_answers_client.h"
 #include "chromeos/components/quick_answers/quick_answers_notice.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "services/network/test/test_url_loader_factory.h"
 
 namespace ash {
diff --git a/ash/quick_answers/quick_answers_ui_controller_unittest.cc b/ash/quick_answers/quick_answers_ui_controller_unittest.cc
index 18698b1..55d15c9 100644
--- a/ash/quick_answers/quick_answers_ui_controller_unittest.cc
+++ b/ash/quick_answers/quick_answers_ui_controller_unittest.cc
@@ -4,11 +4,11 @@
 
 #include "ash/quick_answers/ui/quick_answers_view.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/quick_answers/quick_answers_controller_impl.h"
 #include "ash/quick_answers/quick_answers_ui_controller.h"
 #include "ash/test/ash_test_base.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 
 namespace ash {
 
diff --git a/ash/quick_answers/ui/quick_answers_view.cc b/ash/quick_answers/ui/quick_answers_view.cc
index c19871f..bb815b4 100644
--- a/ash/quick_answers/ui/quick_answers_view.cc
+++ b/ash/quick_answers/ui/quick_answers_view.cc
@@ -4,6 +4,7 @@
 
 #include "ash/quick_answers/ui/quick_answers_view.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/assistant/assistant_interface_binder.h"
 #include "ash/quick_answers/quick_answers_ui_controller.h"
 #include "ash/quick_answers/ui/quick_answers_pre_target_handler.h"
@@ -11,7 +12,6 @@
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "chromeos/components/quick_answers/quick_answers_model.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/ui/vector_icons/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/paint_vector_icon.h"
diff --git a/ash/quick_answers/ui/quick_answers_view_unittest.cc b/ash/quick_answers/ui/quick_answers_view_unittest.cc
index a7dc78fc..bf9514e 100644
--- a/ash/quick_answers/ui/quick_answers_view_unittest.cc
+++ b/ash/quick_answers/ui/quick_answers_view_unittest.cc
@@ -4,10 +4,10 @@
 
 #include "ash/quick_answers/ui/quick_answers_view.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/quick_answers/quick_answers_controller_impl.h"
 #include "ash/test/ash_test_base.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/menu/menu_controller.h"
diff --git a/ash/quick_answers/ui/user_notice_view.cc b/ash/quick_answers/ui/user_notice_view.cc
index c2c70cf..55a467a 100644
--- a/ash/quick_answers/ui/user_notice_view.cc
+++ b/ash/quick_answers/ui/user_notice_view.cc
@@ -5,12 +5,12 @@
 #include "ash/quick_answers/ui/user_notice_view.h"
 
 #include "ash/accessibility/accessibility_controller_impl.h"
+#include "ash/constants/ash_features.h"
 #include "ash/quick_answers/quick_answers_ui_controller.h"
 #include "ash/quick_answers/ui/quick_answers_pre_target_handler.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/ui/vector_icons/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/events/event_handler.h"
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 2029b78..23c4969c 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -201,6 +201,7 @@
     "shelf_sign_out_button.icon",
     "shelf_unlock_button.icon",
     "six_files.icon",
+    "stylus_battery_status_unknown.icon",
     "switch_access.icon",
     "switch_access_back.icon",
     "switch_access_close.icon",
diff --git a/ash/resources/vector_icons/stylus_battery_status_unknown.icon b/ash/resources/vector_icons/stylus_battery_status_unknown.icon
new file mode 100644
index 0000000..36667818
--- /dev/null
+++ b/ash/resources/vector_icons/stylus_battery_status_unknown.icon
@@ -0,0 +1,43 @@
+// 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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 16.5f, 5.34f,
+CUBIC_TO, 15.05f, 3.32f, 12.68f, 2, 10, 2,
+CUBIC_TO, 6.27f, 2, 3.14f, 4.55f, 2.25f, 8,
+H_LINE_TO, 4.34f,
+CUBIC_TO, 5.17f, 5.67f, 7.39f, 4, 10, 4,
+CUBIC_TO, 12.01f, 4, 13.78f, 4.99f, 14.87f, 6.5f,
+H_LINE_TO, 13,
+V_LINE_TO, 8,
+H_LINE_TO, 18,
+V_LINE_TO, 3,
+H_LINE_TO, 16.5f,
+V_LINE_TO, 5.34f,
+CLOSE,
+MOVE_TO, 17.75f, 12,
+CUBIC_TO, 16.86f, 15.45f, 13.73f, 18, 10, 18,
+CUBIC_TO, 7.32f, 18, 4.95f, 16.68f, 3.5f, 14.66f,
+LINE_TO, 3.5f, 17,
+H_LINE_TO, 2,
+V_LINE_TO, 12,
+H_LINE_TO, 7,
+V_LINE_TO, 13.5f,
+H_LINE_TO, 5.13f,
+CUBIC_TO, 6.22f, 15.01f, 7.99f, 16, 10, 16,
+CUBIC_TO, 12.61f, 16, 14.84f, 14.33f, 15.66f, 12,
+H_LINE_TO, 17.75f,
+CLOSE,
+MOVE_TO, 11, 6,
+V_LINE_TO, 11,
+H_LINE_TO, 9,
+V_LINE_TO, 6,
+H_LINE_TO, 11,
+CLOSE,
+MOVE_TO, 11, 14,
+V_LINE_TO, 12,
+H_LINE_TO, 9,
+V_LINE_TO, 14,
+H_LINE_TO, 11,
+CLOSE
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index db7ccd2..bff74f3 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -14,6 +14,7 @@
 #include "ash/accessibility/touch_exploration_manager.h"
 #include "ash/ambient/ambient_controller.h"
 #include "ash/app_menu/app_menu_model_adapter.h"
+#include "ash/constants/ash_features.h"
 #include "ash/focus_cycler.h"
 #include "ash/high_contrast/high_contrast_controller.h"
 #include "ash/host/ash_window_tree_host.h"
@@ -79,7 +80,6 @@
 #include "base/numerics/ranges.h"
 #include "base/stl_util.h"
 #include "base/time/time.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/drag_drop_client.h"
diff --git a/ash/shell.cc b/ash/shell.cc
index 8eb6b1e..7aa6aa18 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -27,6 +27,7 @@
 #include "ash/child_accounts/parent_access_controller_impl.h"
 #include "ash/clipboard/clipboard_history_controller_impl.h"
 #include "ash/clipboard/control_v_histogram_recorder.h"
+#include "ash/constants/ash_features.h"
 #include "ash/dbus/ash_dbus_services.h"
 #include "ash/detachable_base/detachable_base_handler.h"
 #include "ash/detachable_base/detachable_base_notification_controller.h"
@@ -178,7 +179,6 @@
 #include "base/system/sys_info.h"
 #include "base/task/post_task.h"
 #include "base/trace_event/trace_event.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/initialize_dbus_client.h"
 #include "chromeos/dbus/power/power_policy_controller.h"
 #include "chromeos/dbus/usb/usbguard_client.h"
diff --git a/ash/system/ime_menu/ime_menu_tray.cc b/ash/system/ime_menu/ime_menu_tray.cc
index 5b9d78f4..6708942 100644
--- a/ash/system/ime_menu/ime_menu_tray.cc
+++ b/ash/system/ime_menu/ime_menu_tray.cc
@@ -5,6 +5,7 @@
 #include "ash/system/ime_menu/ime_menu_tray.h"
 
 #include "ash/accessibility/accessibility_controller_impl.h"
+#include "ash/constants/ash_features.h"
 #include "ash/ime/ime_controller_impl.h"
 #include "ash/keyboard/keyboard_controller_impl.h"
 #include "ash/keyboard/ui/keyboard_ui_controller.h"
@@ -32,7 +33,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/session_manager/session_manager_types.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/ime_bridge.h"
diff --git a/ash/system/message_center/message_center_controller.cc b/ash/system/message_center/message_center_controller.cc
index 86a62679..444f53ab 100644
--- a/ash/system/message_center/message_center_controller.cc
+++ b/ash/system/message_center/message_center_controller.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/ash_switches.h"
@@ -20,7 +21,6 @@
 #include "ash/system/message_center/session_state_notification_blocker.h"
 #include "ash/system/phonehub/phone_hub_notification_controller.h"
 #include "base/command_line.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
diff --git a/ash/system/network/cellular_setup_notifier_unittest.cc b/ash/system/network/cellular_setup_notifier_unittest.cc
index ac4e4f1d..6213865f 100644
--- a/ash/system/network/cellular_setup_notifier_unittest.cc
+++ b/ash/system/network/cellular_setup_notifier_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/network/cellular_setup_notifier.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
@@ -13,7 +14,6 @@
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/timer/mock_timer.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/hermes/hermes_clients.h"
 #include "chromeos/dbus/shill/shill_clients.h"
 #include "chromeos/network/network_cert_loader.h"
diff --git a/ash/system/network/network_icon.cc b/ash/system/network/network_icon.cc
index a07c9a4b..89b27b6 100644
--- a/ash/system/network/network_icon.cc
+++ b/ash/system/network/network_icon.cc
@@ -7,6 +7,7 @@
 #include <tuple>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/network_icon_image_source.h"
 #include "ash/resources/vector_icons/vector_icons.h"
@@ -20,7 +21,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/numerics/ranges.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
 #include "components/onc/onc_constants.h"
diff --git a/ash/system/network/network_list_view.cc b/ash/system/network/network_list_view.cc
index 497e20c..592ed35 100644
--- a/ash/system/network/network_list_view.cc
+++ b/ash/system/network/network_list_view.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_view_ids.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller_impl.h"
@@ -27,7 +28,6 @@
 #include "ash/system/tray/tri_view.h"
 #include "base/i18n/number_formatting.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
 #include "components/device_event_log/device_event_log.h"
diff --git a/ash/system/network/network_section_header_view.cc b/ash/system/network/network_section_header_view.cc
index b0c77f1..c92d96e 100644
--- a/ash/system/network/network_section_header_view.cc
+++ b/ash/system/network/network_section_header_view.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/network/network_section_header_view.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/public/cpp/system_tray_client.h"
 #include "ash/session/session_controller_impl.h"
@@ -14,7 +15,6 @@
 #include "ash/system/network/tray_network_state_model.h"
 #include "ash/system/unified/top_shortcut_button.h"
 #include "base/bind.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "components/onc/onc_constants.h"
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc
index 7c22691e..40ee4aad 100644
--- a/ash/system/palette/palette_tray.cc
+++ b/ash/system/palette/palette_tray.cc
@@ -98,16 +98,24 @@
         views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), 4));
 
     SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
+    SetVisible(delegate->ShouldShowBatteryStatus());
 
     icon_ = AddChildView(std::make_unique<views::ImageView>());
-    icon_->SetImage(delegate->GetBatteryImage());
 
-    if (delegate->IsBatteryLevelLow()) {
-      label_ = AddChildView(std::make_unique<views::Label>(
-          l10n_util::GetStringUTF16(IDS_ASH_STYLUS_BATTERY_LOW_LABEL)));
-      label_->SetEnabledColor(delegate->GetColorForBatteryLevel());
-      TrayPopupUtils::SetLabelFontList(label_,
-                                       TrayPopupUtils::FontStyle::kSmallTitle);
+    if (delegate->IsBatteryStatusStale()) {
+      icon_->SetImage(delegate->GetBatteryStatusUnknownImage());
+      icon_->SetTooltipText(l10n_util::GetStringUTF16(
+          IDS_ASH_STYLUS_BATTERY_STATUS_STALE_TOOLTIP));
+    } else {
+      icon_->SetImage(delegate->GetBatteryImage());
+
+      if (delegate->IsBatteryLevelLow()) {
+        label_ = AddChildView(std::make_unique<views::Label>(
+            l10n_util::GetStringUTF16(IDS_ASH_STYLUS_BATTERY_LOW_LABEL)));
+        label_->SetEnabledColor(delegate->GetColorForBatteryLevel());
+        TrayPopupUtils::SetLabelFontList(
+            label_, TrayPopupUtils::FontStyle::kSmallTitle);
+      }
     }
   }
 
diff --git a/ash/system/palette/stylus_battery_delegate.cc b/ash/system/palette/stylus_battery_delegate.cc
index 92a27eb..bd6dc99 100644
--- a/ash/system/palette/stylus_battery_delegate.cc
+++ b/ash/system/palette/stylus_battery_delegate.cc
@@ -4,19 +4,24 @@
 
 #include "ash/system/palette/stylus_battery_delegate.h"
 
+#include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
 #include "ash/system/power/power_status.h"
 #include "ash/system/tray/tray_constants.h"
 #include "base/strings/string16.h"
+#include "base/time/time.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/color_palette.h"
+#include "ui/gfx/paint_vector_icon.h"
 
 namespace ash {
 namespace {
 // Battery percentage threshold used to label the battery level as Low.
 constexpr int kStylusLowBatteryThreshold = 24;
+constexpr base::TimeDelta kStylusBatteryStatusStaleThreshold =
+    base::TimeDelta::FromDays(14);
 }  // namespace
 
 StylusBatteryDelegate::StylusBatteryDelegate() {
@@ -46,13 +51,33 @@
                                       icon_fg_color);
 }
 
+gfx::ImageSkia StylusBatteryDelegate::GetBatteryStatusUnknownImage() const {
+  const SkColor icon_color = AshColorProvider::Get()->GetContentLayerColor(
+      AshColorProvider::ContentLayerType::kIconColorPrimary);
+
+  return gfx::CreateVectorIcon(kStylusBatteryStatusUnknownIcon, icon_color);
+}
+
 bool StylusBatteryDelegate::IsBatteryLevelLow() const {
   return battery_level_ <= kStylusLowBatteryThreshold;
 }
 
+bool StylusBatteryDelegate::ShouldShowBatteryStatus() const {
+  return last_update_timestamp_.has_value();
+}
+
+bool StylusBatteryDelegate::IsBatteryStatusStale() const {
+  if (!last_update_timestamp_.has_value())
+    return false;
+
+  return (base::TimeTicks::Now() - last_update_timestamp_.value()) >
+         kStylusBatteryStatusStaleThreshold;
+}
+
 void StylusBatteryDelegate::OnAddingBattery(
     const PeripheralBatteryListener::BatteryInfo& battery) {
   battery_level_ = battery.level;
+  last_update_timestamp_ = battery.last_update_timestamp;
 }
 
 void StylusBatteryDelegate::OnRemovingBattery(
@@ -61,6 +86,7 @@
 void StylusBatteryDelegate::OnUpdatedBatteryLevel(
     const PeripheralBatteryListener::BatteryInfo& battery) {
   battery_level_ = battery.level;
+  last_update_timestamp_ = battery.last_update_timestamp;
 }
 
 }  // namespace ash
diff --git a/ash/system/palette/stylus_battery_delegate.h b/ash/system/palette/stylus_battery_delegate.h
index 75c1145..f2f4bab6 100644
--- a/ash/system/palette/stylus_battery_delegate.h
+++ b/ash/system/palette/stylus_battery_delegate.h
@@ -9,6 +9,7 @@
 #include "ash/system/power/peripheral_battery_listener.h"
 #include "base/scoped_observation.h"
 #include "base/strings/string16.h"
+#include "base/time/time.h"
 #include "ui/gfx/image/image_skia.h"
 
 namespace ash {
@@ -23,7 +24,10 @@
 
   SkColor GetColorForBatteryLevel() const;
   gfx::ImageSkia GetBatteryImage() const;
+  gfx::ImageSkia GetBatteryStatusUnknownImage() const;
   bool IsBatteryLevelLow() const;
+  bool IsBatteryStatusStale() const;
+  bool ShouldShowBatteryStatus() const;
 
   base::Optional<uint8_t> battery_level() const { return battery_level_; }
 
@@ -37,6 +41,7 @@
       const PeripheralBatteryListener::BatteryInfo& battery) override;
 
   base::Optional<uint8_t> battery_level_;
+  base::Optional<base::TimeTicks> last_update_timestamp_;
 
   base::ScopedObservation<PeripheralBatteryListener,
                           PeripheralBatteryListener::Observer>
diff --git a/ash/system/phonehub/phone_hub_notification_controller_unittest.cc b/ash/system/phonehub/phone_hub_notification_controller_unittest.cc
index 76fccdb..1be64f05 100644
--- a/ash/system/phonehub/phone_hub_notification_controller_unittest.cc
+++ b/ash/system/phonehub/phone_hub_notification_controller_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/phonehub/phone_hub_notification_controller.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/test/test_system_tray_client.h"
 #include "ash/shell.h"
 #include "ash/system/message_center/message_center_controller.h"
@@ -16,7 +17,6 @@
 #include "chromeos/components/phonehub/fake_phone_hub_manager.h"
 #include "chromeos/components/phonehub/mutable_phone_model.h"
 #include "chromeos/components/phonehub/notification.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/events/event.h"
 #include "ui/gfx/image/image_skia.h"
diff --git a/ash/system/phonehub/phone_hub_tray_unittest.cc b/ash/system/phonehub/phone_hub_tray_unittest.cc
index 6f9dba7..6caaebc 100644
--- a/ash/system/phonehub/phone_hub_tray_unittest.cc
+++ b/ash/system/phonehub/phone_hub_tray_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/phonehub/phone_hub_tray.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/test/test_new_window_delegate.h"
 #include "ash/system/phonehub/notification_opt_in_view.h"
 #include "ash/system/phonehub/phone_hub_ui_controller.h"
@@ -16,7 +17,6 @@
 #include "chromeos/components/phonehub/fake_notification_access_manager.h"
 #include "chromeos/components/phonehub/fake_phone_hub_manager.h"
 #include "chromeos/components/phonehub/phone_model_test_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/events/event.h"
 #include "ui/views/controls/button/button.h"
diff --git a/ash/system/phonehub/phone_status_view_unittest.cc b/ash/system/phonehub/phone_status_view_unittest.cc
index cf8f888..5b97b28 100644
--- a/ash/system/phonehub/phone_status_view_unittest.cc
+++ b/ash/system/phonehub/phone_status_view_unittest.cc
@@ -4,12 +4,12 @@
 
 #include "ash/system/phonehub/phone_status_view.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/test/ash_test_base.h"
 #include "base/optional.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "chromeos/components/phonehub/mutable_phone_model.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/test/button_test_api.h"
diff --git a/ash/system/phonehub/quick_actions_view_unittest.cc b/ash/system/phonehub/quick_actions_view_unittest.cc
index b92bcd1f..f42d8a77 100644
--- a/ash/system/phonehub/quick_actions_view_unittest.cc
+++ b/ash/system/phonehub/quick_actions_view_unittest.cc
@@ -4,11 +4,11 @@
 
 #include "ash/system/phonehub/quick_actions_view.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/system/phonehub/quick_action_item.h"
 #include "ash/test/ash_test_base.h"
 #include "base/test/scoped_feature_list.h"
 #include "chromeos/components/phonehub/fake_phone_hub_manager.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/views/test/button_test_api.h"
 
 namespace ash {
diff --git a/ash/system/phonehub/task_continuation_view_unittest.cc b/ash/system/phonehub/task_continuation_view_unittest.cc
index 8c8c889..2f5c008e 100644
--- a/ash/system/phonehub/task_continuation_view_unittest.cc
+++ b/ash/system/phonehub/task_continuation_view_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/phonehub/task_continuation_view.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/test/test_new_window_delegate.h"
 #include "ash/system/phonehub/continue_browsing_chip.h"
 #include "ash/test/ash_test_base.h"
@@ -11,7 +12,6 @@
 #include "chromeos/components/phonehub/fake_user_action_recorder.h"
 #include "chromeos/components/phonehub/mutable_phone_model.h"
 #include "chromeos/components/phonehub/phone_model_test_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/views/test/button_test_api.h"
 
diff --git a/ash/system/power/power_prefs.cc b/ash/system/power/power_prefs.cc
index 5bd57222..2c9922a 100644
--- a/ash/system/power/power_prefs.cc
+++ b/ash/system/power/power_prefs.cc
@@ -7,13 +7,13 @@
 #include <string>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/time/default_tick_clock.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/power/power_policy_controller.h"
 #include "chromeos/dbus/power_manager/idle.pb.h"
 #include "chromeos/dbus/power_manager/policy.pb.h"
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc
index 11f5792..cc59c2b 100644
--- a/ash/system/status_area_widget.cc
+++ b/ash/system/status_area_widget.cc
@@ -5,6 +5,7 @@
 #include "ash/system/status_area_widget.h"
 
 #include "ash/capture_mode/stop_recording_button_tray.h"
+#include "ash/constants/ash_features.h"
 #include "ash/keyboard/ui/keyboard_ui_controller.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
@@ -34,7 +35,6 @@
 #include "base/containers/adapters.h"
 #include "base/i18n/time_formatting.h"
 #include "base/metrics/histogram_macros.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/assistant/public/cpp/features.h"
 #include "media/base/media_switches.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
diff --git a/ash/system/system_notification_controller.cc b/ash/system/system_notification_controller.cc
index 243fefc7..5885104 100644
--- a/ash/system/system_notification_controller.cc
+++ b/ash/system/system_notification_controller.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/system_notification_controller.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/system/caps_lock_notification_controller.h"
 #include "ash/system/cast/cast_notification_controller.h"
 #include "ash/system/gesture_education/gesture_education_notification_controller.h"
@@ -15,7 +16,6 @@
 #include "ash/system/session/session_limit_notification_controller.h"
 #include "ash/system/tracing_notification_controller.h"
 #include "ash/system/update/update_notification_controller.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/message_center/message_center.h"
 
 namespace ash {
diff --git a/ash/system/unified/camera_mic_tray_item_view.cc b/ash/system/unified/camera_mic_tray_item_view.cc
index 45eaf8a4..33df044e 100644
--- a/ash/system/unified/camera_mic_tray_item_view.cc
+++ b/ash/system/unified/camera_mic_tray_item_view.cc
@@ -3,8 +3,10 @@
 // found in the LICENSE file.
 
 #include "ash/system/unified/camera_mic_tray_item_view.h"
+
 #include <algorithm>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/media_controller.h"
 #include "ash/public/cpp/vm_camera_mic_constants.h"
 #include "ash/session/session_controller_impl.h"
@@ -16,7 +18,6 @@
 #include "base/feature_list.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/vector_icons/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/paint_vector_icon.h"
diff --git a/ash/system/unified/camera_mic_tray_item_view_unittest.cc b/ash/system/unified/camera_mic_tray_item_view_unittest.cc
index eec6fb2..d15c956 100644
--- a/ash/system/unified/camera_mic_tray_item_view_unittest.cc
+++ b/ash/system/unified/camera_mic_tray_item_view_unittest.cc
@@ -7,11 +7,11 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/media_controller.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/test/ash_test_base.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 
diff --git a/ash/system/unified/ime_mode_view.cc b/ash/system/unified/ime_mode_view.cc
index bfdf7cc..6d6ecf1 100644
--- a/ash/system/unified/ime_mode_view.cc
+++ b/ash/system/unified/ime_mode_view.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/unified/ime_mode_view.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/ime/ime_controller_impl.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
@@ -14,7 +15,6 @@
 #include "ash/system/tray/tray_utils.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/views/border.h"
diff --git a/ash/wm/desks/desk.h b/ash/wm/desks/desk.h
index e2d7608..b268829 100644
--- a/ash/wm/desks/desk.h
+++ b/ash/wm/desks/desk.h
@@ -58,6 +58,8 @@
 
   bool is_active() const { return is_active_; }
 
+  bool is_desk_being_removed() const { return is_desk_being_removed_; }
+
   bool should_notify_content_changed() const {
     return should_notify_content_changed_;
   }
diff --git a/ash/wm/desks/desk_mini_view.cc b/ash/wm/desks/desk_mini_view.cc
index 2c8f5c12..86ae68b 100644
--- a/ash/wm/desks/desk_mini_view.cc
+++ b/ash/wm/desks/desk_mini_view.cc
@@ -398,13 +398,13 @@
   desk_name_view_->UpdateViewAppearance();
 
   // When committing the name, do not allow an empty desk name. Revert back to
-  // the default name.
+  // the default name if the desk is not being removed.
   // TODO(afakhry): Make this more robust. What if user renames a previously
   // user-modified desk name, say from "code" to "Desk 2", and that desk
   // happened to be in the second position. Since the new name matches the
   // default one for this position, should we revert it (i.e. consider it
   // `set_by_user = false`?
-  if (desk_->name().empty()) {
+  if (!desk_->is_desk_being_removed() && desk_->name().empty()) {
     DesksController::Get()->RevertDeskNameToDefault(desk_);
     return;
   }
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index 98c7fbd..cc684ce 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -469,6 +469,29 @@
   EXPECT_TRUE(GetNewDeskButton(desks_bar_view)->GetEnabled());
 }
 
+TEST_F(DesksTest, RemoveDeskWithEmptyName) {
+  auto* controller = DesksController::Get();
+
+  auto* overview_controller = Shell::Get()->overview_controller();
+  overview_controller->StartOverview();
+  EXPECT_TRUE(overview_controller->InOverviewSession());
+
+  auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
+
+  const auto* desks_bar_view = overview_grid->desks_bar_view();
+
+  auto* event_generator = GetEventGenerator();
+
+  // Create a new desk by using button with empty name.
+  controller->NewDesk(DesksCreationRemovalSource::kButton);
+  EXPECT_EQ(2u, controller->desks().size());
+
+  // Close the newly created desk with the close button.
+  auto* mini_view = desks_bar_view->mini_views().back();
+  CloseDeskFromMiniView(mini_view, event_generator);
+  EXPECT_EQ(1u, controller->desks().size());
+}
+
 // Test that gesture taps do not reset the button state to normal when the
 // button is disabled. https://crbug.com/1084241.
 TEST_F(DesksTest, GestureTapOnNewDeskButton) {
diff --git a/base/allocator/partition_allocator/partition_alloc_check.h b/base/allocator/partition_allocator/partition_alloc_check.h
index 8b57f22..e495510e 100644
--- a/base/allocator/partition_allocator/partition_alloc_check.h
+++ b/base/allocator/partition_allocator/partition_alloc_check.h
@@ -11,6 +11,9 @@
 #include "base/debug/alias.h"
 #include "base/immediate_crash.h"
 
+#define PA_STRINGIFY_IMPL(s) #s
+#define PA_STRINGIFY(s) PA_STRINGIFY_IMPL(s)
+
 // When PartitionAlloc is used as the default allocator, we cannot use the
 // regular (D)CHECK() macros, as they allocate internally. When an assertion is
 // triggered, they format strings, leading to reentrancy in the code, which none
@@ -21,9 +24,21 @@
 // - When PartitionAlloc is not malloc(), use the regular macros
 // - Otherwise, crash immediately. This provides worse error messages though.
 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+// For official build discard log strings to reduce binary bloat.
+#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
 // See base/check.h for implementation details.
 #define PA_CHECK(condition) \
   UNLIKELY(!(condition)) ? IMMEDIATE_CRASH() : EAT_CHECK_STREAM_PARAMS()
+#else
+// PartitionAlloc uses async-signal-safe RawCheck() for error reporting.
+// Async-signal-safe functions are guaranteed to not allocate as otherwise they
+// could operate with inconsistent allocator state.
+#define PA_CHECK(condition)                                                \
+  UNLIKELY(!(condition))                                                   \
+  ? logging::RawCheck(                                                     \
+        __FILE__ "(" PA_STRINGIFY(__LINE__) ") Check failed: " #condition) \
+  : EAT_CHECK_STREAM_PARAMS()
+#endif  // defined(OFFICIAL_BUILD) && defined(NDEBUG)
 
 #if DCHECK_IS_ON()
 #define PA_DCHECK(condition) PA_CHECK(condition)
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 6a77a8b1..a14337d 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -2941,6 +2941,21 @@
   allocator.root()->FreeNoHooks(ptr2);
 }
 
+// Death tests misbehave on Android, http://crbug.com/643760.
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+#if !defined(OFFICIAL_BUILD) || !defined(NDEBUG)
+
+TEST_F(PartitionAllocDeathTest, CheckTriggered) {
+  using ::testing::ContainsRegex;
+#if DCHECK_IS_ON()
+  EXPECT_DEATH(PA_CHECK(5 == 7), ContainsRegex("Check failed.*5 == 7"));
+#endif
+  EXPECT_DEATH(PA_CHECK(5 == 7), ContainsRegex("Check failed.*5 == 7"));
+}
+
+#endif  // !defined(OFFICIAL_BUILD) && !defined(NDEBUG)
+#endif  // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+
 }  // namespace internal
 }  // namespace base
 
diff --git a/base/allocator/partition_allocator/partition_root.cc b/base/allocator/partition_allocator/partition_root.cc
index e1707d2c..47382d9 100644
--- a/base/allocator/partition_allocator/partition_root.cc
+++ b/base/allocator/partition_allocator/partition_root.cc
@@ -473,7 +473,12 @@
 }
 
 template <bool thread_safe>
-PartitionRoot<thread_safe>::~PartitionRoot() = default;
+PartitionRoot<thread_safe>::~PartitionRoot() {
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+  PA_CHECK(!with_thread_cache)
+      << "Must not destroy a partition with a thread cache";
+#endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+}
 
 template <bool thread_safe>
 bool PartitionRoot<thread_safe>::ReallocDirectMappedInPlace(
diff --git a/base/allocator/partition_allocator/partition_tls.h b/base/allocator/partition_allocator/partition_tls.h
index 8dab8f2..0f8326d 100644
--- a/base/allocator/partition_allocator/partition_tls.h
+++ b/base/allocator/partition_allocator/partition_tls.h
@@ -71,6 +71,10 @@
   BOOL ret = TlsSetValue(key, value);
   PA_DCHECK(ret);
 }
+
+// Registers a callback for DLL_PROCESS_DETACH events.
+void PartitionTlsSetOnDllProcessDetach(void (*callback)());
+
 #else
 // Not supported.
 typedef int PartitionTlsKey;
diff --git a/base/allocator/partition_allocator/partition_tls_win.cc b/base/allocator/partition_allocator/partition_tls_win.cc
index 8ffc6da5..1f55ebd5 100644
--- a/base/allocator/partition_allocator/partition_tls_win.cc
+++ b/base/allocator/partition_allocator/partition_tls_win.cc
@@ -11,6 +11,7 @@
 // Store the key as the thread destruction callback doesn't get it.
 PartitionTlsKey g_key;
 void (*g_destructor)(void*) = nullptr;
+void (*g_on_dll_process_detach)() = nullptr;
 
 // Static callback function to call with each thread termination.
 void NTAPI PartitionTlsOnThreadExit(PVOID module,
@@ -19,6 +20,9 @@
   if (reason != DLL_THREAD_DETACH && reason != DLL_PROCESS_DETACH)
     return;
 
+  if (reason == DLL_PROCESS_DETACH && g_on_dll_process_detach)
+    g_on_dll_process_detach();
+
   if (g_destructor) {
     void* per_thread_data = PartitionTlsGet(g_key);
     if (per_thread_data)
@@ -41,6 +45,10 @@
   return false;
 }
 
+void PartitionTlsSetOnDllProcessDetach(void (*callback)()) {
+  g_on_dll_process_detach = callback;
+}
+
 }  // namespace internal
 }  // namespace base
 
diff --git a/base/allocator/partition_allocator/thread_cache.cc b/base/allocator/partition_allocator/thread_cache.cc
index 030632a..c61c6b5 100644
--- a/base/allocator/partition_allocator/thread_cache.cc
+++ b/base/allocator/partition_allocator/thread_cache.cc
@@ -11,6 +11,7 @@
 #include "base/allocator/partition_allocator/partition_alloc.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
 
 namespace base {
 
@@ -27,7 +28,20 @@
 namespace {
 // Since |g_thread_cache_key| is shared, make sure that no more than one
 // PartitionRoot can use it.
-static std::atomic<bool> g_has_instance;
+static std::atomic<PartitionRoot<ThreadSafe>*> g_thread_cache_root;
+
+#if defined(OS_WIN)
+void OnDllProcessDetach() {
+  // Very late allocations do occur (see crbug.com/1159411#c7 for instance),
+  // including during CRT teardown. This is problematic for the thread cache
+  // which relies on the CRT for TLS access for instance. This cannot be
+  // mitigated inside the thread cache (since getting to it requires querying
+  // TLS), but the PartitionRoot associated wih the thread cache can be made to
+  // not use the thread cache anymore.
+  g_thread_cache_root.load(std::memory_order_relaxed)->with_thread_cache =
+      false;
+}
+#endif
 
 static bool g_thread_cache_key_created = false;
 }  // namespace
@@ -205,13 +219,17 @@
   EnsureThreadSpecificDataInitialized();
 
   // Make sure that only one PartitionRoot wants a thread cache.
-  bool expected = false;
-  if (!g_has_instance.compare_exchange_strong(expected, true,
-                                              std::memory_order_seq_cst,
-                                              std::memory_order_seq_cst)) {
+  PartitionRoot<ThreadSafe>* expected = nullptr;
+  if (!g_thread_cache_root.compare_exchange_strong(expected, nullptr,
+                                                   std::memory_order_seq_cst,
+                                                   std::memory_order_seq_cst)) {
     PA_CHECK(false)
         << "Only one PartitionRoot is allowed to have a thread cache";
   }
+
+#if defined(OS_WIN)
+  PartitionTlsSetOnDllProcessDetach(OnDllProcessDetach);
+#endif
 }
 
 // static
diff --git a/base/i18n/time_formatting.cc b/base/i18n/time_formatting.cc
index 0a74e4c7..ed40fb4 100644
--- a/base/i18n/time_formatting.cc
+++ b/base/i18n/time_formatting.cc
@@ -14,6 +14,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "build/chromeos_buildflags.h"
 #include "third_party/icu/source/common/unicode/utypes.h"
 #include "third_party/icu/source/i18n/unicode/datefmt.h"
 #include "third_party/icu/source/i18n/unicode/dtitvfmt.h"
@@ -154,7 +155,7 @@
   return TimeFormat(formatter.get(), time);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 string16 TimeFormatMonthAndYear(const Time& time,
                                 const icu::TimeZone* time_zone) {
   icu::SimpleDateFormat formatter =
@@ -169,7 +170,7 @@
       CreateSimpleDateFormatter(DateFormatToString(DATE_FORMAT_YEAR_MONTH));
   return TimeFormat(&formatter, time);
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 string16 TimeFormatFriendlyDateAndTime(const Time& time) {
   std::unique_ptr<icu::DateFormat> formatter(
diff --git a/base/i18n/time_formatting.h b/base/i18n/time_formatting.h
index 1063f6e6..8133301c 100644
--- a/base/i18n/time_formatting.h
+++ b/base/i18n/time_formatting.h
@@ -12,10 +12,11 @@
 #include "base/i18n/base_i18n_export.h"
 #include "base/strings/string16.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "third_party/icu/source/i18n/unicode/timezone.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace base {
 
@@ -77,7 +78,7 @@
 // Returns a numeric date and time such as "12/13/52 2:44:30 PM".
 BASE_I18N_EXPORT string16 TimeFormatShortDateAndTime(const Time& time);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Returns a month and year, e.g. "November 2007"
 // Note: If `time_zone` is non-null, the time will be formatted in the provided
 // time zone. Otherwise, it will default to local time.
@@ -87,7 +88,7 @@
 #else
 // Returns a month and year, e.g. "November 2007"
 BASE_I18N_EXPORT string16 TimeFormatMonthAndYear(const Time& time);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Returns a numeric date and time with time zone such as
 // "12/13/52 2:44:30 PM PST".
diff --git a/base/memory/shared_memory_security_policy.h b/base/memory/shared_memory_security_policy.h
index bf356bb..e581188 100644
--- a/base/memory/shared_memory_security_policy.h
+++ b/base/memory/shared_memory_security_policy.h
@@ -7,8 +7,15 @@
 
 #include <stddef.h>
 
+#include "base/base_export.h"
 #include "base/compiler_specific.h"
 
+namespace mojo {
+namespace core {
+class ChannelLinux;
+}  // namespace core
+}  // namespace mojo
+
 namespace base {
 
 namespace subtle {
@@ -19,10 +26,11 @@
 // mapped. This can help prevent an attacker from spraying the address space of
 // a process with shared memory mappings to bypass ASLR. For more details, see
 // https://googleprojectzero.blogspot.com/2019/04/virtually-unlimited-memory-escaping.html
-class SharedMemorySecurityPolicy {
+class BASE_EXPORT SharedMemorySecurityPolicy {
  private:
   friend class subtle::PlatformSharedMemoryRegion;
   friend class SharedMemoryMapping;
+  friend class mojo::core::ChannelLinux;
 
   // Checks that a mapping with |size| can be created. Returns false if there is
   // an overflow in internal calculations, or the max limit has been reached.
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 0faf443..6311c641 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -98,6 +98,7 @@
 // that's okay.
 
 class BrowserProcessImpl;
+class ChromeJsErrorReportProcessor;
 class ChromeNSSCryptoModuleDelegate;
 class HistogramSynchronizer;
 class KeyStorageLinux;
@@ -466,6 +467,7 @@
   friend class blink::scheduler::WorkerThread;
   friend class chrome_cleaner::ResetShortcutsComponent;
   friend class chrome_cleaner::SystemReportComponent;
+  friend class ::ChromeJsErrorReportProcessor;
   friend class content::BrowserMainLoop;
   friend class content::BrowserProcessSubThread;
   friend class content::ServiceWorkerContextClient;
diff --git a/base/win/windows_version.cc b/base/win/windows_version.cc
index 64c8aa83..d27746b 100644
--- a/base/win/windows_version.cc
+++ b/base/win/windows_version.cc
@@ -256,6 +256,8 @@
 // static
 Version OSInfo::MajorMinorBuildToVersion(int major, int minor, int build) {
   if (major == 10) {
+    if (build >= 20287)
+      return Version::WIN10_21H1;
     if (build >= 19042)
       return Version::WIN10_20H2;
     if (build >= 19041)
diff --git a/base/win/windows_version.h b/base/win/windows_version.h
index b67fbd6..6a47057 100644
--- a/base/win/windows_version.h
+++ b/base/win/windows_version.h
@@ -50,6 +50,7 @@
   WIN10_19H2 = 15,  // 19H2: Version 1909, Build 18363.
   WIN10_20H1 = 16,  // 20H1: Version 2004, Build 19041.
   WIN10_20H2 = 17,  // 20H2: Version 2009, Build 19042.
+  WIN10_21H1 = 18,  // 21H1: Version TBD
   WIN_LAST,         // Indicates error condition.
 };
 
diff --git a/base/win/windows_version_unittest.cc b/base/win/windows_version_unittest.cc
index 21bed23..90272e8 100644
--- a/base/win/windows_version_unittest.cc
+++ b/base/win/windows_version_unittest.cc
@@ -24,7 +24,9 @@
 
 TEST(OSInfo, MajorMinorBuildToVersion) {
   EXPECT_EQ(OSInfo::MajorMinorBuildToVersion(10, 0, 32767),
-            Version::WIN10_20H2);
+            Version::WIN10_21H1);
+  EXPECT_EQ(OSInfo::MajorMinorBuildToVersion(10, 0, 20287),
+            Version::WIN10_21H1);
   EXPECT_EQ(OSInfo::MajorMinorBuildToVersion(10, 0, 19042),
             Version::WIN10_20H2);
   EXPECT_EQ(OSInfo::MajorMinorBuildToVersion(10, 0, 19041),
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 64ae2c8c..9becd7c0 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20210203.1.1
+0.20210203.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 64ae2c8c..9becd7c0 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20210203.1.1
+0.20210203.2.1
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 9c44e43e..2f5ed5b 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -515,7 +515,6 @@
     "test/fake_ui_resource_layer_tree_host_impl.h",
     "test/fake_video_frame_provider.cc",
     "test/fake_video_frame_provider.h",
-    "test/geometry_test_utils.cc",
     "test/geometry_test_utils.h",
     "test/layer_test_common.cc",
     "test/layer_test_common.h",
@@ -800,7 +799,6 @@
     "animation/keyframed_animation_curve_unittest.cc",
     "animation/scroll_offset_animation_curve_unittest.cc",
     "animation/scroll_timeline_unittest.cc",
-    "animation/transform_operations_unittest.cc",
     "animation/worklet_animation_unittest.cc",
 
     # Setup.
diff --git a/cc/animation/BUILD.gn b/cc/animation/BUILD.gn
index 5bd47e6..6703d94 100644
--- a/cc/animation/BUILD.gn
+++ b/cc/animation/BUILD.gn
@@ -42,10 +42,6 @@
     "scroll_timeline.h",
     "timing_function.cc",
     "timing_function.h",
-    "transform_operation.cc",
-    "transform_operation.h",
-    "transform_operations.cc",
-    "transform_operations.h",
     "worklet_animation.cc",
     "worklet_animation.h",
   ]
diff --git a/cc/animation/animation.cc b/cc/animation/animation.cc
index e47af5cd..0b8d96cd 100644
--- a/cc/animation/animation.cc
+++ b/cc/animation/animation.cc
@@ -18,7 +18,6 @@
 #include "cc/animation/keyframe_effect.h"
 #include "cc/animation/scroll_offset_animation_curve.h"
 #include "cc/animation/scroll_timeline.h"
-#include "cc/animation/transform_operations.h"
 #include "cc/trees/property_animation_state.h"
 
 namespace cc {
diff --git a/cc/animation/animation_curve.h b/cc/animation/animation_curve.h
index a7d0e8a3..d7dbc993d 100644
--- a/cc/animation/animation_curve.h
+++ b/cc/animation/animation_curve.h
@@ -13,6 +13,10 @@
 #include "ui/gfx/geometry/size_f.h"
 #include "ui/gfx/transform.h"
 
+namespace gfx {
+class TransformOperations;
+}  // namespace gfx
+
 namespace cc {
 
 class ColorAnimationCurve;
@@ -21,7 +25,6 @@
 class ScrollOffsetAnimationCurve;
 class SizeAnimationCurve;
 class TransformAnimationCurve;
-class TransformOperations;
 
 // An animation curve is a function that returns a value given a time.
 class CC_ANIMATION_EXPORT AnimationCurve {
@@ -75,7 +78,7 @@
  public:
   ~TransformAnimationCurve() override {}
 
-  virtual TransformOperations GetValue(base::TimeDelta t) const = 0;
+  virtual gfx::TransformOperations GetValue(base::TimeDelta t) const = 0;
 
   // Returns true if this animation preserves axis alignment.
   virtual bool PreservesAxisAlignment() const = 0;
diff --git a/cc/animation/animation_target.h b/cc/animation/animation_target.h
index 16e99e39..8d19f25 100644
--- a/cc/animation/animation_target.h
+++ b/cc/animation/animation_target.h
@@ -11,13 +11,13 @@
 namespace gfx {
 class ScrollOffset;
 class SizeF;
+class TransformOperations;
 }  // namespace gfx
 
 namespace cc {
 
 class FilterOperations;
 class KeyframeModel;
-class TransformOperations;
 
 // An AnimationTarget is an entity that can be affected by a ticking
 // cc:KeyframeModel. Any object that expects to have an opacity update, for
@@ -38,7 +38,7 @@
                                          int target_property_id,
                                          KeyframeModel* keyframe_model) = 0;
   virtual void NotifyClientTransformOperationsAnimated(
-      const TransformOperations& operations,
+      const gfx::TransformOperations& operations,
       int target_property_id,
       KeyframeModel* keyframe_model) = 0;
   virtual void NotifyClientScrollOffsetAnimated(
diff --git a/cc/animation/element_animations.cc b/cc/animation/element_animations.cc
index 04c6d59..4607f2e5 100644
--- a/cc/animation/element_animations.cc
+++ b/cc/animation/element_animations.cc
@@ -15,10 +15,10 @@
 #include "cc/animation/animation_host.h"
 #include "cc/animation/keyframe_effect.h"
 #include "cc/animation/keyframed_animation_curve.h"
-#include "cc/animation/transform_operations.h"
 #include "cc/paint/filter_operations.h"
 #include "cc/trees/mutator_host_client.h"
 #include "ui/gfx/geometry/box_f.h"
+#include "ui/gfx/transform_operations.h"
 
 namespace cc {
 
@@ -268,7 +268,7 @@
 }
 
 void ElementAnimations::NotifyClientTransformOperationsAnimated(
-    const TransformOperations& operations,
+    const gfx::TransformOperations& operations,
     int target_property_id,
     KeyframeModel* keyframe_model) {
   gfx::Transform transform = operations.Apply();
diff --git a/cc/animation/element_animations.h b/cc/animation/element_animations.h
index 941094a6..1586167 100644
--- a/cc/animation/element_animations.h
+++ b/cc/animation/element_animations.h
@@ -19,12 +19,15 @@
 #include "ui/gfx/geometry/scroll_offset.h"
 #include "ui/gfx/transform.h"
 
+namespace gfx {
+class TransformOperations;
+}  // namespace gfx
+
 namespace cc {
 
 class AnimationHost;
 class FilterOperations;
 class KeyframeEffect;
-class TransformOperations;
 enum class ElementListType;
 
 // An ElementAnimations owns a list of all KeyframeEffects attached to a single
@@ -137,7 +140,7 @@
                                  int target_property_id,
                                  KeyframeModel* keyframe_model) override;
   void NotifyClientTransformOperationsAnimated(
-      const TransformOperations& operations,
+      const gfx::TransformOperations& operations,
       int target_property_id,
       KeyframeModel* keyframe_model) override;
   void NotifyClientScrollOffsetAnimated(const gfx::ScrollOffset& scroll_offset,
diff --git a/cc/animation/element_animations_unittest.cc b/cc/animation/element_animations_unittest.cc
index c27c9c76..8a32c452 100644
--- a/cc/animation/element_animations_unittest.cc
+++ b/cc/animation/element_animations_unittest.cc
@@ -18,10 +18,10 @@
 #include "cc/animation/keyframed_animation_curve.h"
 #include "cc/animation/scroll_offset_animation_curve.h"
 #include "cc/animation/scroll_offset_animation_curve_factory.h"
-#include "cc/animation/transform_operations.h"
 #include "cc/test/animation_test_common.h"
 #include "cc/test/animation_timelines_test_common.h"
 #include "ui/gfx/geometry/box_f.h"
+#include "ui/gfx/transform_operations.h"
 
 namespace cc {
 namespace {
@@ -2242,7 +2242,7 @@
   std::unique_ptr<KeyframedTransformAnimationCurve> curve1(
       KeyframedTransformAnimationCurve::Create());
 
-  TransformOperations operations1;
+  gfx::TransformOperations operations1;
   curve1->AddKeyframe(
       TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
   operations1.AppendTranslate(10.0, 15.0, 0.0);
@@ -2269,7 +2269,7 @@
   std::unique_ptr<KeyframedTransformAnimationCurve> curve1(
       KeyframedTransformAnimationCurve::Create());
 
-  TransformOperations operations1;
+  gfx::TransformOperations operations1;
   operations1.AppendScale(2.0, 2.0, 2.0);
   operations1.AppendPerspective(100);
   curve1->AddKeyframe(
@@ -2299,7 +2299,7 @@
   std::unique_ptr<KeyframedTransformAnimationCurve> curve1(
       KeyframedTransformAnimationCurve::Create());
 
-  TransformOperations operations1;
+  gfx::TransformOperations operations1;
   operations1.AppendScale(2.0, 2.0, 2.0);
   curve1->AddKeyframe(
       TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
@@ -2328,11 +2328,11 @@
   std::unique_ptr<KeyframedTransformAnimationCurve> curve1(
       KeyframedTransformAnimationCurve::Create());
 
-  TransformOperations operations1a;
+  gfx::TransformOperations operations1a;
   operations1a.AppendScale(2.0, 3.0, 4.0);
   curve1->AddKeyframe(
       TransformKeyframe::Create(base::TimeDelta(), operations1a, nullptr));
-  TransformOperations operations1b;
+  gfx::TransformOperations operations1b;
   operations1b.AppendScale(5.0, 4.0, 3.0);
   curve1->AddKeyframe(TransformKeyframe::Create(
       base::TimeDelta::FromSecondsD(1.0), operations1b, nullptr));
@@ -2356,11 +2356,11 @@
   std::unique_ptr<KeyframedTransformAnimationCurve> curve2(
       KeyframedTransformAnimationCurve::Create());
 
-  TransformOperations operations2a;
+  gfx::TransformOperations operations2a;
   operations2a.AppendScale(1.0, 2.0, 3.0);
   curve2->AddKeyframe(
       TransformKeyframe::Create(base::TimeDelta(), operations2a, nullptr));
-  TransformOperations operations2b;
+  gfx::TransformOperations operations2b;
   operations2b.AppendScale(6.0, 5.0, 4.0);
   curve2->AddKeyframe(TransformKeyframe::Create(
       base::TimeDelta::FromSecondsD(1.0), operations2b, nullptr));
@@ -2378,11 +2378,11 @@
   std::unique_ptr<KeyframedTransformAnimationCurve> curve3(
       KeyframedTransformAnimationCurve::Create());
 
-  TransformOperations operations3a;
+  gfx::TransformOperations operations3a;
   operations3a.AppendScale(5.0, 3.0, 1.0);
   curve3->AddKeyframe(
       TransformKeyframe::Create(base::TimeDelta(), operations3a, nullptr));
-  TransformOperations operations3b;
+  gfx::TransformOperations operations3b;
   operations3b.AppendScale(1.5, 2.5, 3.5);
   curve3->AddKeyframe(TransformKeyframe::Create(
       base::TimeDelta::FromSecondsD(1.0), operations3b, nullptr));
@@ -2421,11 +2421,11 @@
 
   std::unique_ptr<KeyframedTransformAnimationCurve> curve1(
       KeyframedTransformAnimationCurve::Create());
-  TransformOperations operations1;
+  gfx::TransformOperations operations1;
   operations1.AppendScale(1.0, 2.0, 3.0);
   curve1->AddKeyframe(
       TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
-  TransformOperations operations2;
+  gfx::TransformOperations operations2;
   operations2.AppendScale(4.0, 5.0, 6.0);
   curve1->AddKeyframe(TransformKeyframe::Create(
       base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
diff --git a/cc/animation/keyframe_effect.cc b/cc/animation/keyframe_effect.cc
index ad80629..1719eba8 100644
--- a/cc/animation/keyframe_effect.cc
+++ b/cc/animation/keyframe_effect.cc
@@ -17,8 +17,8 @@
 #include "cc/animation/animation_timeline.h"
 #include "cc/animation/keyframe_model.h"
 #include "cc/animation/scroll_offset_animation_curve.h"
-#include "cc/animation/transform_operations.h"
 #include "cc/trees/property_animation_state.h"
+#include "ui/gfx//transform_operations.h"
 
 namespace cc {
 
diff --git a/cc/animation/keyframed_animation_curve.cc b/cc/animation/keyframed_animation_curve.cc
index 48069b4d..98f61d2 100644
--- a/cc/animation/keyframed_animation_curve.cc
+++ b/cc/animation/keyframed_animation_curve.cc
@@ -164,7 +164,7 @@
 
 std::unique_ptr<TransformKeyframe> TransformKeyframe::Create(
     base::TimeDelta time,
-    const TransformOperations& value,
+    const gfx::TransformOperations& value,
     std::unique_ptr<TimingFunction> timing_function) {
   return base::WrapUnique(
       new TransformKeyframe(time, value, std::move(timing_function)));
@@ -172,13 +172,13 @@
 
 TransformKeyframe::TransformKeyframe(
     base::TimeDelta time,
-    const TransformOperations& value,
+    const gfx::TransformOperations& value,
     std::unique_ptr<TimingFunction> timing_function)
     : Keyframe(time, std::move(timing_function)), value_(value) {}
 
 TransformKeyframe::~TransformKeyframe() = default;
 
-const TransformOperations& TransformKeyframe::Value() const {
+const gfx::TransformOperations& TransformKeyframe::Value() const {
   return value_;
 }
 
@@ -378,7 +378,7 @@
   return std::move(to_return);
 }
 
-TransformOperations KeyframedTransformAnimationCurve::GetValue(
+gfx::TransformOperations KeyframedTransformAnimationCurve::GetValue(
     base::TimeDelta t) const {
   if (t <= (keyframes_.front()->Time() * scaled_duration()))
     return keyframes_.front()->Value();
diff --git a/cc/animation/keyframed_animation_curve.h b/cc/animation/keyframed_animation_curve.h
index 7813672..45f95772 100644
--- a/cc/animation/keyframed_animation_curve.h
+++ b/cc/animation/keyframed_animation_curve.h
@@ -13,8 +13,8 @@
 #include "cc/animation/animation_curve.h"
 #include "cc/animation/animation_export.h"
 #include "cc/animation/timing_function.h"
-#include "cc/animation/transform_operations.h"
 #include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/transform_operations.h"
 
 namespace cc {
 
@@ -82,20 +82,20 @@
  public:
   static std::unique_ptr<TransformKeyframe> Create(
       base::TimeDelta time,
-      const TransformOperations& value,
+      const gfx::TransformOperations& value,
       std::unique_ptr<TimingFunction> timing_function);
   ~TransformKeyframe() override;
 
-  const TransformOperations& Value() const;
+  const gfx::TransformOperations& Value() const;
 
   std::unique_ptr<TransformKeyframe> Clone() const;
 
  private:
   TransformKeyframe(base::TimeDelta time,
-                    const TransformOperations& value,
+                    const gfx::TransformOperations& value,
                     std::unique_ptr<TimingFunction> timing_function);
 
-  TransformOperations value_;
+  gfx::TransformOperations value_;
 };
 
 class CC_ANIMATION_EXPORT FilterKeyframe : public Keyframe {
@@ -251,7 +251,7 @@
   std::unique_ptr<AnimationCurve> Clone() const override;
 
   // TransformAnimationCurve implementation
-  TransformOperations GetValue(base::TimeDelta t) const override;
+  gfx::TransformOperations GetValue(base::TimeDelta t) const override;
   bool PreservesAxisAlignment() const override;
   bool MaximumScale(float* max_scale) const override;
 
diff --git a/cc/animation/keyframed_animation_curve_unittest.cc b/cc/animation/keyframed_animation_curve_unittest.cc
index c043f42..c87d2e8 100644
--- a/cc/animation/keyframed_animation_curve_unittest.cc
+++ b/cc/animation/keyframed_animation_curve_unittest.cc
@@ -6,19 +6,19 @@
 
 #include <memory>
 
-#include "cc/animation/transform_operations.h"
 #include "cc/test/geometry_test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/animation/tween.h"
 #include "ui/gfx/geometry/box_f.h"
 #include "ui/gfx/test/gfx_util.h"
+#include "ui/gfx/transform_operations.h"
 
 namespace cc {
 namespace {
 
 void ExpectTranslateX(SkScalar translate_x,
-                      const TransformOperations& operations) {
+                      const gfx::TransformOperations& operations) {
   EXPECT_FLOAT_EQ(translate_x, operations.Apply().matrix().get(0, 3));
 }
 
@@ -212,7 +212,7 @@
 TEST(KeyframedAnimationCurveTest, OneTransformKeyframe) {
   std::unique_ptr<KeyframedTransformAnimationCurve> curve(
       KeyframedTransformAnimationCurve::Create());
-  TransformOperations operations;
+  gfx::TransformOperations operations;
   operations.AppendTranslate(2.f, 0.f, 0.f);
   curve->AddKeyframe(
       TransformKeyframe::Create(base::TimeDelta(), operations, nullptr));
@@ -228,9 +228,9 @@
 TEST(KeyframedAnimationCurveTest, TwoTransformKeyframe) {
   std::unique_ptr<KeyframedTransformAnimationCurve> curve(
       KeyframedTransformAnimationCurve::Create());
-  TransformOperations operations1;
+  gfx::TransformOperations operations1;
   operations1.AppendTranslate(2.f, 0.f, 0.f);
-  TransformOperations operations2;
+  gfx::TransformOperations operations2;
   operations2.AppendTranslate(4.f, 0.f, 0.f);
 
   curve->AddKeyframe(
@@ -248,11 +248,11 @@
 TEST(KeyframedAnimationCurveTest, ThreeTransformKeyframe) {
   std::unique_ptr<KeyframedTransformAnimationCurve> curve(
       KeyframedTransformAnimationCurve::Create());
-  TransformOperations operations1;
+  gfx::TransformOperations operations1;
   operations1.AppendTranslate(2.f, 0.f, 0.f);
-  TransformOperations operations2;
+  gfx::TransformOperations operations2;
   operations2.AppendTranslate(4.f, 0.f, 0.f);
-  TransformOperations operations3;
+  gfx::TransformOperations operations3;
   operations3.AppendTranslate(8.f, 0.f, 0.f);
   curve->AddKeyframe(
       TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
@@ -275,13 +275,13 @@
   std::unique_ptr<KeyframedTransformAnimationCurve> curve(
       KeyframedTransformAnimationCurve::Create());
   // A step function.
-  TransformOperations operations1;
+  gfx::TransformOperations operations1;
   operations1.AppendTranslate(4.f, 0.f, 0.f);
-  TransformOperations operations2;
+  gfx::TransformOperations operations2;
   operations2.AppendTranslate(4.f, 0.f, 0.f);
-  TransformOperations operations3;
+  gfx::TransformOperations operations3;
   operations3.AppendTranslate(6.f, 0.f, 0.f);
-  TransformOperations operations4;
+  gfx::TransformOperations operations4;
   operations4.AppendTranslate(6.f, 0.f, 0.f);
   curve->AddKeyframe(
       TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
@@ -315,11 +315,11 @@
 
   std::unique_ptr<KeyframedTransformAnimationCurve> curve(
       KeyframedTransformAnimationCurve::Create());
-  TransformOperations operations1;
+  gfx::TransformOperations operations1;
   operations1.AppendMatrix(non_invertible_matrix);
-  TransformOperations operations2;
+  gfx::TransformOperations operations2;
   operations2.AppendMatrix(identity_matrix);
-  TransformOperations operations3;
+  gfx::TransformOperations operations3;
   operations3.AppendMatrix(non_invertible_matrix);
 
   curve->AddKeyframe(
@@ -329,7 +329,7 @@
   curve->AddKeyframe(TransformKeyframe::Create(
       base::TimeDelta::FromSecondsD(2.0), operations3, nullptr));
 
-  TransformOperations result;
+  gfx::TransformOperations result;
 
   // Between 0 and 0.5 seconds, the first keyframe should be returned.
   result = curve->GetValue(base::TimeDelta::FromSecondsD(0.01f));
@@ -359,11 +359,11 @@
 
   std::unique_ptr<KeyframedTransformAnimationCurve> curve(
       KeyframedTransformAnimationCurve::Create());
-  TransformOperations operations1;
+  gfx::TransformOperations operations1;
   operations1.AppendMatrix(non_invertible_matrix);
-  TransformOperations operations2;
+  gfx::TransformOperations operations2;
   operations2.AppendMatrix(identity_matrix);
-  TransformOperations operations3;
+  gfx::TransformOperations operations3;
   operations3.AppendMatrix(non_invertible_matrix);
 
   // The cubic-bezier here is a nice fairly strong ease-in curve, where 50%
@@ -378,7 +378,7 @@
       base::TimeDelta::FromSecondsD(2.0), operations3,
       CubicBezierTimingFunction::Create(0.75f, 0.25f, 0.9f, 0.4f)));
 
-  TransformOperations result;
+  gfx::TransformOperations result;
 
   // Due to the cubic-bezier, the first keyframe is returned almost all the way
   // to 1 second.
@@ -622,7 +622,7 @@
   std::unique_ptr<KeyframedTransformAnimationCurve> curve(
       KeyframedTransformAnimationCurve::Create());
 
-  TransformOperations operations1;
+  gfx::TransformOperations operations1;
   curve->AddKeyframe(
       TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
   operations1.AppendScale(2.f, -3.f, 1.f);
@@ -636,7 +636,7 @@
   EXPECT_TRUE(curve->MaximumScale(&maximum_scale));
   EXPECT_EQ(3.f, maximum_scale);
 
-  TransformOperations operations2;
+  gfx::TransformOperations operations2;
   operations2.AppendScale(6.f, 3.f, 2.f);
   curve->AddKeyframe(TransformKeyframe::Create(
       base::TimeDelta::FromSecondsD(2.f), operations2,
@@ -647,7 +647,7 @@
   EXPECT_TRUE(curve->MaximumScale(&maximum_scale));
   EXPECT_EQ(6.f, maximum_scale);
 
-  TransformOperations operations3;
+  gfx::TransformOperations operations3;
   operations3.AppendRotate(1.f, 0.f, 0.f, 90.f);
   curve->AddKeyframe(TransformKeyframe::Create(
       base::TimeDelta::FromSecondsD(3.f), operations3,
@@ -662,13 +662,13 @@
   std::unique_ptr<KeyframedTransformAnimationCurve> curve2(
       KeyframedTransformAnimationCurve::Create());
 
-  TransformOperations operations5;
+  gfx::TransformOperations operations5;
   operations5.AppendScale(0.4f, 0.2f, 0.6f);
   curve2->AddKeyframe(TransformKeyframe::Create(
       base::TimeDelta(), operations5,
       CubicBezierTimingFunction::CreatePreset(
           CubicBezierTimingFunction::EaseType::EASE)));
-  TransformOperations operations6;
+  gfx::TransformOperations operations6;
   operations6.AppendScale(0.5f, 0.3f, -0.8f);
   curve2->AddKeyframe(TransformKeyframe::Create(
       base::TimeDelta::FromSecondsD(1.f), operations6,
@@ -682,7 +682,7 @@
 
 TEST(KeyframeAnimationCurveTest, NonCalculatableMaximumScale) {
   auto curve = KeyframedTransformAnimationCurve::Create();
-  TransformOperations operations4;
+  gfx::TransformOperations operations4;
   operations4.AppendPerspective(3.f);
   curve->AddKeyframe(TransformKeyframe::Create(
       base::TimeDelta::FromSecondsD(1.f), operations4,
@@ -699,7 +699,7 @@
 
   // If the scale of any keyframe can be calculated, the keyframes with
   // non-calculatable scale will be ignored.
-  TransformOperations operations;
+  gfx::TransformOperations operations;
   operations.AppendScale(0.4f, 0.2f, 0.6f);
   curve->AddKeyframe(TransformKeyframe::Create(
       base::TimeDelta(), operations,
diff --git a/cc/base/math_util.cc b/cc/base/math_util.cc
index b3875af..6af60ed1 100644
--- a/cc/base/math_util.cc
+++ b/cc/base/math_util.cc
@@ -577,42 +577,6 @@
   return output_inner_rect;
 }
 
-static inline bool NearlyZero(double value) {
-  return std::abs(value) < std::numeric_limits<double>::epsilon();
-}
-
-static inline float ScaleOnAxis(double a, double b, double c) {
-  if (NearlyZero(b) && NearlyZero(c))
-    return std::abs(a);
-  if (NearlyZero(a) && NearlyZero(c))
-    return std::abs(b);
-  if (NearlyZero(a) && NearlyZero(b))
-    return std::abs(c);
-
-  // Do the sqrt as a double to not lose precision.
-  return static_cast<float>(std::sqrt(a * a + b * b + c * c));
-}
-
-gfx::Vector2dF MathUtil::ComputeTransform2dScaleComponents(
-    const gfx::Transform& transform,
-    float fallback_value) {
-  if (transform.HasPerspective())
-    return gfx::Vector2dF(fallback_value, fallback_value);
-  float x_scale = ScaleOnAxis(transform.matrix().getDouble(0, 0),
-                              transform.matrix().getDouble(1, 0),
-                              transform.matrix().getDouble(2, 0));
-  float y_scale = ScaleOnAxis(transform.matrix().getDouble(0, 1),
-                              transform.matrix().getDouble(1, 1),
-                              transform.matrix().getDouble(2, 1));
-  return gfx::Vector2dF(x_scale, y_scale);
-}
-
-float MathUtil::ComputeApproximateMaxScale(const gfx::Transform& transform) {
-  gfx::RectF unit(0.f, 0.f, 1.f, 1.f);
-  transform.TransformRect(&unit);
-  return std::max(unit.width(), unit.height());
-}
-
 float MathUtil::SmallestAngleBetweenVectors(const gfx::Vector2dF& v1,
                                             const gfx::Vector2dF& v2) {
   double dot_product = gfx::DotProduct(v1, v2) / v1.Length() / v2.Length();
diff --git a/cc/base/math_util.h b/cc/base/math_util.h
index 1633d53..e6940430 100644
--- a/cc/base/math_util.h
+++ b/cc/base/math_util.h
@@ -235,13 +235,6 @@
                                      const gfx::PointF& point,
                                      bool* clipped);
 
-  static gfx::Vector2dF ComputeTransform2dScaleComponents(const gfx::Transform&,
-                                                          float fallbackValue);
-  // Returns an approximate max scale value of the transform even if it has
-  // perspective. Prefer to use ComputeTransform2dScaleComponents if there is no
-  // perspective, since it can produce more accurate results.
-  static float ComputeApproximateMaxScale(const gfx::Transform& transform);
-
   // Makes a rect that has the same relationship to input_outer_rect as
   // scale_inner_rect has to scale_outer_rect. scale_inner_rect should be
   // contained within scale_outer_rect, and likewise the rectangle that is
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 920a3f5..a8c46ec 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -42,6 +42,7 @@
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
+#include "ui/gfx/transform_util.h"
 
 namespace cc {
 LayerImpl::LayerImpl(LayerTreeImpl* tree_impl,
@@ -798,7 +799,7 @@
 
   const auto& transform = ScreenSpaceTransform();
   if (transform.HasPerspective()) {
-    float scale = MathUtil::ComputeApproximateMaxScale(transform);
+    float scale = gfx::ComputeApproximateMaxScale(transform);
 
     const int kMaxTilesToCoverLayerDimension = 5;
     // Cap the scale in a way that it should be covered by at most
@@ -828,7 +829,7 @@
   }
 
   gfx::Vector2dF transform_scales =
-      MathUtil::ComputeTransform2dScaleComponents(transform, default_scale);
+      gfx::ComputeTransform2dScaleComponents(transform, default_scale);
 
   return GetPreferredRasterScale(transform_scales);
 }
diff --git a/cc/layers/painted_scrollbar_layer.cc b/cc/layers/painted_scrollbar_layer.cc
index b1835826..3e0b802 100644
--- a/cc/layers/painted_scrollbar_layer.cc
+++ b/cc/layers/painted_scrollbar_layer.cc
@@ -14,6 +14,7 @@
 #include "cc/trees/draw_property_utils.h"
 #include "cc/trees/layer_tree_host.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/transform_util.h"
 
 namespace cc {
 
@@ -141,7 +142,7 @@
   transform = draw_property_utils::ScreenSpaceTransform(
       this, layer_tree_host()->property_trees()->transform_tree);
 
-  gfx::Vector2dF transform_scales = MathUtil::ComputeTransform2dScaleComponents(
+  gfx::Vector2dF transform_scales = gfx::ComputeTransform2dScaleComponents(
       transform, layer_tree_host()->device_scale_factor());
   float scale = std::max(transform_scales.x(), transform_scales.y());
   // Clamp minimum scale to 1 to avoid too low scale during scale animation.
diff --git a/cc/test/animation_test_common.cc b/cc/test/animation_test_common.cc
index f117d14..5d8984a 100644
--- a/cc/test/animation_test_common.cc
+++ b/cc/test/animation_test_common.cc
@@ -18,7 +18,6 @@
 #include "cc/animation/scroll_offset_animation_curve.h"
 #include "cc/animation/scroll_offset_animation_curve_factory.h"
 #include "cc/animation/timing_function.h"
-#include "cc/animation/transform_operations.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_impl.h"
 
@@ -63,8 +62,8 @@
 
 int AddAnimatedTransform(Animation* target,
                          double duration,
-                         TransformOperations start_operations,
-                         TransformOperations operations) {
+                         gfx::TransformOperations start_operations,
+                         gfx::TransformOperations operations) {
   std::unique_ptr<KeyframedTransformAnimationCurve> curve(
       KeyframedTransformAnimationCurve::Create());
 
@@ -91,12 +90,12 @@
                          double duration,
                          int delta_x,
                          int delta_y) {
-  TransformOperations start_operations;
+  gfx::TransformOperations start_operations;
   if (duration > 0.0) {
     start_operations.AppendTranslate(0, 0, 0.0);
   }
 
-  TransformOperations operations;
+  gfx::TransformOperations operations;
   operations.AppendTranslate(delta_x, delta_y, 0.0);
   return AddAnimatedTransform(target, duration, start_operations, operations);
 }
@@ -194,9 +193,9 @@
   return duration_;
 }
 
-TransformOperations FakeTransformTransition::GetValue(
+gfx::TransformOperations FakeTransformTransition::GetValue(
     base::TimeDelta time) const {
-  return TransformOperations();
+  return gfx::TransformOperations();
 }
 
 bool FakeTransformTransition::PreservesAxisAlignment() const {
@@ -260,8 +259,8 @@
 
 int AddAnimatedTransformToAnimation(Animation* animation,
                                     double duration,
-                                    TransformOperations start_operations,
-                                    TransformOperations operations) {
+                                    gfx::TransformOperations start_operations,
+                                    gfx::TransformOperations operations) {
   return AddAnimatedTransform(animation, duration, start_operations,
                               operations);
 }
@@ -403,8 +402,8 @@
     ElementId element_id,
     scoped_refptr<AnimationTimeline> timeline,
     double duration,
-    TransformOperations start_operations,
-    TransformOperations operations) {
+    gfx::TransformOperations start_operations,
+    gfx::TransformOperations operations) {
   scoped_refptr<Animation> animation =
       Animation::Create(AnimationIdProvider::NextAnimationId());
   timeline->AttachAnimation(animation);
diff --git a/cc/test/animation_test_common.h b/cc/test/animation_test_common.h
index 21ae3ef2..edd604a 100644
--- a/cc/test/animation_test_common.h
+++ b/cc/test/animation_test_common.h
@@ -10,10 +10,10 @@
 #include "cc/animation/animation_curve.h"
 #include "cc/animation/animation_timeline.h"
 #include "cc/animation/keyframe_model.h"
-#include "cc/animation/transform_operations.h"
 #include "cc/paint/element_id.h"
 #include "cc/paint/filter_operations.h"
 #include "cc/test/geometry_test_utils.h"
+#include "ui/gfx/transform_operations.h"
 
 namespace gfx {
 class ScrollOffset;
@@ -41,7 +41,7 @@
   ~FakeTransformTransition() override;
 
   base::TimeDelta Duration() const override;
-  TransformOperations GetValue(base::TimeDelta time) const override;
+  gfx::TransformOperations GetValue(base::TimeDelta time) const override;
   bool PreservesAxisAlignment() const override;
   bool MaximumScale(float* max_scale) const override;
 
@@ -78,8 +78,8 @@
 
 int AddAnimatedTransformToAnimation(Animation* animation,
                                     double duration,
-                                    TransformOperations start_operations,
-                                    TransformOperations operations);
+                                    gfx::TransformOperations start_operations,
+                                    gfx::TransformOperations operations);
 
 int AddOpacityTransitionToAnimation(Animation* animation,
                                     double duration,
@@ -140,8 +140,8 @@
     ElementId element_id,
     scoped_refptr<AnimationTimeline> timeline,
     double duration,
-    TransformOperations start_operations,
-    TransformOperations operations);
+    gfx::TransformOperations start_operations,
+    gfx::TransformOperations operations);
 
 int AddOpacityTransitionToElementWithAnimation(
     ElementId element_id,
diff --git a/cc/test/geometry_test_utils.h b/cc/test/geometry_test_utils.h
index 48a58e76..5bc12dd7 100644
--- a/cc/test/geometry_test_utils.h
+++ b/cc/test/geometry_test_utils.h
@@ -5,11 +5,7 @@
 #ifndef CC_TEST_GEOMETRY_TEST_UTILS_H_
 #define CC_TEST_GEOMETRY_TEST_UTILS_H_
 
-#include "cc/cc_export.h"
-
-namespace gfx {
-class Transform;
-}
+#include "ui/gfx/geometry/test/transform_test_util.h"
 
 namespace cc {
 
@@ -98,32 +94,16 @@
     EXPECT_EQ((expected).height(), (actual).height()); \
   } while (false)
 
-// This is a function rather than a macro because when this is included as a
-// macro in bulk, it causes a significant slow-down in compilation time. This
-// problem exists with both gcc and clang, and bugs have been filed at
-// http://llvm.org/bugs/show_bug.cgi?id=13651
-// and http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54337
-void ExpectTransformationMatrixEq(const gfx::Transform& expected,
-                                  const gfx::Transform& actual);
-
 #define EXPECT_TRANSFORMATION_MATRIX_EQ(expected, actual) \
   do {                                                    \
-    ExpectTransformationMatrixEq(expected, actual);       \
+    gfx::ExpectTransformationMatrixEq(expected, actual);  \
   } while (false)
 
-void ExpectTransformationMatrixNear(const gfx::Transform& expected,
-                                    const gfx::Transform& actual,
-                                    float abs_error);
-
 #define EXPECT_TRANSFORMATION_MATRIX_NEAR(expected, actual, abs_error) \
   do {                                                                 \
-    ExpectTransformationMatrixNear(expected, actual, abs_error);       \
+    gfx::ExpectTransformationMatrixNear(expected, actual, abs_error);  \
   } while (false)
 
-// Should be used in test code only, for convenience. Production code should use
-// the gfx::Transform::GetInverse() API.
-gfx::Transform Inverse(const gfx::Transform& transform);
-
 }  // namespace cc
 
 #endif  // CC_TEST_GEOMETRY_TEST_UTILS_H_
diff --git a/cc/trees/draw_properties_unittest.cc b/cc/trees/draw_properties_unittest.cc
index cac65443..7eb51c23 100644
--- a/cc/trees/draw_properties_unittest.cc
+++ b/cc/trees/draw_properties_unittest.cc
@@ -16,8 +16,6 @@
 #include "cc/animation/animation_host.h"
 #include "cc/animation/animation_id_provider.h"
 #include "cc/animation/keyframed_animation_curve.h"
-#include "cc/animation/transform_operations.h"
-#include "cc/base/math_util.h"
 #include "cc/layers/content_layer_client.h"
 #include "cc/layers/effect_tree_layer_list_iterator.h"
 #include "cc/layers/layer.h"
@@ -43,6 +41,8 @@
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
 #include "ui/gfx/transform.h"
+#include "ui/gfx/transform_operations.h"
+#include "ui/gfx/transform_util.h"
 
 namespace cc {
 namespace {
@@ -286,8 +286,8 @@
   // Case 5: The layer transform should occur with respect to the anchor point.
   gfx::Transform translation_to_anchor;
   translation_to_anchor.Translate(5.0, 0.0);
-  gfx::Transform expected_result =
-      translation_to_anchor * layer_transform * Inverse(translation_to_anchor);
+  gfx::Transform expected_result = translation_to_anchor * layer_transform *
+                                   gfx::InvertAndCheck(translation_to_anchor);
   SetTransformOrigin(layer, gfx::Point3F(5.f, 0.f, 0.f));
   UpdateActiveTreeDrawProperties();
   EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -301,7 +301,8 @@
   // current implementation of CalculateDrawProperties does this implicitly, but
   // it is still worth testing to detect accidental regressions.
   expected_result = position_transform * translation_to_anchor *
-                    layer_transform * Inverse(translation_to_anchor);
+                    layer_transform *
+                    gfx::InvertAndCheck(translation_to_anchor);
   SetPostTranslation(layer, gfx::Vector2dF(0.f, 1.2f));
   UpdateActiveTreeDrawProperties();
   EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -460,7 +461,7 @@
   parent_translation_to_anchor.Translate(2.5, 3.0);
   gfx::Transform parent_composite_transform =
       parent_translation_to_anchor * parent_layer_transform *
-      Inverse(parent_translation_to_anchor);
+      gfx::InvertAndCheck(parent_translation_to_anchor);
   SetTransform(parent, parent_layer_transform);
   SetPostTranslation(parent, gfx::Vector2dF());
   UpdateActiveTreeDrawProperties();
@@ -492,15 +493,15 @@
 
   gfx::Transform parent_composite_transform =
       parent_translation_to_anchor * parent_layer_transform *
-      Inverse(parent_translation_to_anchor);
+      gfx::InvertAndCheck(parent_translation_to_anchor);
   gfx::Vector2dF parent_composite_scale =
-      MathUtil::ComputeTransform2dScaleComponents(parent_composite_transform,
-                                                  1.f);
+      gfx::ComputeTransform2dScaleComponents(parent_composite_transform, 1.f);
   gfx::Transform surface_sublayer_transform;
   surface_sublayer_transform.Scale(parent_composite_scale.x(),
                                    parent_composite_scale.y());
   gfx::Transform surface_sublayer_composite_transform =
-      parent_composite_transform * Inverse(surface_sublayer_transform);
+      parent_composite_transform *
+      gfx::InvertAndCheck(surface_sublayer_transform);
 
   root->SetBounds(gfx::Size(1, 2));
   parent->SetBounds(gfx::Size(100, 120));
@@ -581,11 +582,11 @@
   gfx::Transform layer_transform;
   layer_transform.Translate(1.0, 1.0);
 
-  gfx::Transform A =
-      translation_to_anchor * layer_transform * Inverse(translation_to_anchor);
+  gfx::Transform A = translation_to_anchor * layer_transform *
+                     gfx::InvertAndCheck(translation_to_anchor);
 
   gfx::Vector2dF surface1_parent_transform_scale =
-      MathUtil::ComputeTransform2dScaleComponents(A, 1.f);
+      gfx::ComputeTransform2dScaleComponents(A, 1.f);
   gfx::Transform surface1_sublayer_transform;
   surface1_sublayer_transform.Scale(surface1_parent_transform_scale.x(),
                                     surface1_parent_transform_scale.y());
@@ -594,10 +595,10 @@
   gfx::Transform SS1 = surface1_sublayer_transform;
   // S1 = transform to move from render_surface1 pixels to the layer space of
   // the owning layer
-  gfx::Transform S1 = Inverse(surface1_sublayer_transform);
+  gfx::Transform S1 = gfx::InvertAndCheck(surface1_sublayer_transform);
 
   gfx::Vector2dF surface2_parent_transform_scale =
-      MathUtil::ComputeTransform2dScaleComponents(SS1 * A, 1.f);
+      gfx::ComputeTransform2dScaleComponents(SS1 * A, 1.f);
   gfx::Transform surface2_sublayer_transform;
   surface2_sublayer_transform.Scale(surface2_parent_transform_scale.x(),
                                     surface2_parent_transform_scale.y());
@@ -606,7 +607,7 @@
   gfx::Transform SS2 = surface2_sublayer_transform;
   // S2 = transform to move from render_surface2 pixels to the layer space of
   // the owning layer
-  gfx::Transform S2 = Inverse(surface2_sublayer_transform);
+  gfx::Transform S2 = gfx::InvertAndCheck(surface2_sublayer_transform);
 
   root->SetBounds(gfx::Size(1, 2));
   parent->SetBounds(gfx::Size(10, 10));
@@ -2021,7 +2022,7 @@
 
 static bool ProjectionClips(const gfx::Transform& map_transform,
                             const gfx::RectF& mapped_rect) {
-  gfx::Transform inverse(Inverse(map_transform));
+  gfx::Transform inverse(gfx::InvertAndCheck(map_transform));
   bool clipped = false;
   if (!clipped)
     MathUtil::ProjectPoint(inverse, mapped_rect.top_right(), &clipped);
@@ -3232,14 +3233,14 @@
   transform.Scale(device_scale_factor * page_scale_factor,
                   device_scale_factor * page_scale_factor);
   gfx::Vector2dF scales =
-      MathUtil::ComputeTransform2dScaleComponents(transform, 0.f);
+      gfx::ComputeTransform2dScaleComponents(transform, 0.f);
   float max_2d_scale = std::max(scales.x(), scales.y());
   EXPECT_FLOAT_EQ(max_2d_scale, scale_surface->GetIdealContentsScale());
 
   // The ideal scale will draw 1:1 with its render target space along
   // the larger-scale axis.
   gfx::Vector2dF target_space_transform_scales =
-      MathUtil::ComputeTransform2dScaleComponents(
+      gfx::ComputeTransform2dScaleComponents(
           scale_surface->draw_properties().target_space_transform, 0.f);
   EXPECT_FLOAT_EQ(max_2d_scale, std::max(target_space_transform_scales.x(),
                                          target_space_transform_scales.y()));
@@ -4633,9 +4634,9 @@
 
   gfx::Transform end_scale;
   end_scale.Scale(2.f, 2.f);
-  TransformOperations start_operations;
+  gfx::TransformOperations start_operations;
   start_operations.AppendMatrix(start_scale);
-  TransformOperations end_operations;
+  gfx::TransformOperations end_operations;
   end_operations.AppendMatrix(end_scale);
 
   AddAnimatedTransformToElementWithAnimation(animated_layer->element_id(),
@@ -5487,7 +5488,7 @@
   EXPECT_FALSE(AnimationAffectedByInvalidScale(parent));
   EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
 
-  TransformOperations translation;
+  gfx::TransformOperations translation;
   translation.AppendTranslate(1.f, 2.f, 3.f);
 
   scoped_refptr<Animation> grand_parent_animation =
@@ -5511,7 +5512,7 @@
   grand_child_animation->AttachElement(grand_child->element_id());
 
   AddAnimatedTransformToAnimation(parent_animation.get(), 1.0,
-                                  TransformOperations(), translation);
+                                  gfx::TransformOperations(), translation);
 
   // No layers have scale-affecting animations.
   EXPECT_EQ(1.f, MaximumAnimationToScreenScale(grand_child));
@@ -5524,11 +5525,11 @@
   EXPECT_FALSE(AnimationAffectedByInvalidScale(parent));
   EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
 
-  TransformOperations scale;
+  gfx::TransformOperations scale;
   scale.AppendScale(5.f, 4.f, 3.f);
 
   AddAnimatedTransformToAnimation(child_animation.get(), 1.0,
-                                  TransformOperations(), scale);
+                                  gfx::TransformOperations(), scale);
   UpdateActiveTreeDrawProperties();
 
   // Only |child| has a scale-affecting animation.
@@ -5543,7 +5544,7 @@
   EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
 
   AddAnimatedTransformToAnimation(grand_parent_animation.get(), 1.0,
-                                  TransformOperations(), scale);
+                                  gfx::TransformOperations(), scale);
   UpdateActiveTreeDrawProperties();
 
   // |grand_parent| and |child| have scale-affecting animations.
@@ -5560,7 +5561,7 @@
   EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
 
   AddAnimatedTransformToAnimation(parent_animation.get(), 1.0,
-                                  TransformOperations(), scale);
+                                  gfx::TransformOperations(), scale);
   UpdateActiveTreeDrawProperties();
 
   // |grand_parent|, |parent|, and |child| have scale-affecting animations.
@@ -5589,7 +5590,7 @@
   timeline_impl()->AttachAnimation(child_animation);
   child_animation->AttachElement(child->element_id());
 
-  TransformOperations perspective;
+  gfx::TransformOperations perspective;
   perspective.AppendPerspective(10.f);
 
   AddAnimatedTransformToAnimation(child_animation.get(), 1.0, perspective,
@@ -5618,7 +5619,7 @@
   SetTransform(child, scale_matrix);
 
   AddAnimatedTransformToAnimation(parent_animation.get(), 1.0,
-                                  TransformOperations(), scale);
+                                  gfx::TransformOperations(), scale);
   UpdateActiveTreeDrawProperties();
 
   // |grand_parent|, |parent| and |child| each has scale 2.f. |parent| has a
@@ -5923,14 +5924,14 @@
   host()->SetRootLayer(root);
   host()->SetElementIdsForTesting();
 
-  TransformOperations scale;
+  gfx::TransformOperations scale;
   scale.AppendScale(5.f, 8.f, 3.f);
 
   child2->SetTransform(scale_transform_child2);
   child2->SetBounds(gfx::Size(1, 1));
   child2->SetIsDrawable(true);
-  AddAnimatedTransformToElementWithAnimation(child2->element_id(), timeline(),
-                                             1.0, TransformOperations(), scale);
+  AddAnimatedTransformToElementWithAnimation(
+      child2->element_id(), timeline(), 1.0, gfx::TransformOperations(), scale);
 
   CommitAndActivate();
 
@@ -5995,11 +5996,11 @@
       page_scale->transform_tree_index();
   host()->RegisterViewportPropertyIds(viewport_property_ids);
 
-  TransformOperations scale;
+  gfx::TransformOperations scale;
   scale.AppendScale(5.f, 8.f, 3.f);
 
-  AddAnimatedTransformToElementWithAnimation(child2->element_id(), timeline(),
-                                             1.0, TransformOperations(), scale);
+  AddAnimatedTransformToElementWithAnimation(
+      child2->element_id(), timeline(), 1.0, gfx::TransformOperations(), scale);
 
   CommitAndActivate();
 
@@ -6066,11 +6067,12 @@
   CopyProperties(child1, child2);
   CreateTransformNode(child2).local = scale_transform_child2;
 
-  TransformOperations scale;
+  gfx::TransformOperations scale;
   scale.AppendScale(5.f, 8.f, 3.f);
 
-  AddAnimatedTransformToElementWithAnimation(
-      child2->element_id(), timeline_impl(), 1.0, TransformOperations(), scale);
+  AddAnimatedTransformToElementWithAnimation(child2->element_id(),
+                                             timeline_impl(), 1.0,
+                                             gfx::TransformOperations(), scale);
   UpdateActiveTreeDrawProperties();
 
   EXPECT_FLOAT_EQ(24.f, MaximumAnimationToScreenScale(child2));
@@ -6121,9 +6123,9 @@
   CopyProperties(child, grandchild);
   CreateTransformNode(grandchild).local = small_scale;
 
-  TransformOperations small_scale_operations;
+  gfx::TransformOperations small_scale_operations;
   small_scale_operations.AppendMatrix(small_scale);
-  TransformOperations scale_one_operations;
+  gfx::TransformOperations scale_one_operations;
 
   // Both child and grandchild animate scale from 0.1x0.2 to 1.
   AddAnimatedTransformToElementWithAnimation(
@@ -6265,9 +6267,9 @@
   CreateEffectNode(surface).render_surface_reason = RenderSurfaceReason::kTest;
   CopyProperties(surface, descendant_of_keyframe_model);
 
-  TransformOperations start_transform_operations;
+  gfx::TransformOperations start_transform_operations;
   start_transform_operations.AppendMatrix(uninvertible_matrix);
-  TransformOperations end_transform_operations;
+  gfx::TransformOperations end_transform_operations;
 
   AddAnimatedTransformToElementWithAnimation(
       animated->element_id(), timeline_impl(), 10.0, start_transform_operations,
@@ -6599,11 +6601,11 @@
 
   std::unique_ptr<KeyframedTransformAnimationCurve> curve(
       KeyframedTransformAnimationCurve::Create());
-  TransformOperations start;
+  gfx::TransformOperations start;
   start.AppendTranslate(1.f, 2.f, 3.f);
   gfx::Transform transform;
   transform.Scale3d(1.0, 2.0, 3.0);
-  TransformOperations operation;
+  gfx::TransformOperations operation;
   operation.AppendMatrix(transform);
   curve->AddKeyframe(
       TransformKeyframe::Create(base::TimeDelta(), start, nullptr));
@@ -6632,11 +6634,11 @@
   // Set up a transform animation
   std::unique_ptr<KeyframedTransformAnimationCurve> curve(
       KeyframedTransformAnimationCurve::Create());
-  TransformOperations start;
+  gfx::TransformOperations start;
   start.AppendTranslate(1.f, 2.f, 3.f);
   gfx::Transform transform;
   transform.Scale3d(1.0, 2.0, 3.0);
-  TransformOperations operation;
+  gfx::TransformOperations operation;
   operation.AppendMatrix(transform);
   curve->AddKeyframe(
       TransformKeyframe::Create(base::TimeDelta(), start, nullptr));
@@ -7609,11 +7611,11 @@
 
   std::unique_ptr<KeyframedTransformAnimationCurve> curve(
       KeyframedTransformAnimationCurve::Create());
-  TransformOperations start;
+  gfx::TransformOperations start;
   start.AppendTranslate(1.f, 2.f, 3.f);
   gfx::Transform transform;
   transform.Scale3d(1.0, 2.0, 3.0);
-  TransformOperations operation;
+  gfx::TransformOperations operation;
   operation.AppendMatrix(transform);
   curve->AddKeyframe(
       TransformKeyframe::Create(base::TimeDelta(), start, nullptr));
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 474803d..1aed3b0 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -26,7 +26,6 @@
 #include "build/build_config.h"
 #include "cc/animation/animation_host.h"
 #include "cc/animation/animation_id_provider.h"
-#include "cc/animation/transform_operations.h"
 #include "cc/base/features.h"
 #include "cc/base/histograms.h"
 #include "cc/document_transition/document_transition_request.h"
@@ -101,6 +100,7 @@
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
+#include "ui/gfx/transform_operations.h"
 
 #define EXPECT_SCOPED(statements) \
   {                               \
@@ -3274,9 +3274,9 @@
   CreateTransformNode(child);
 
   // Add a translate from 6,7 to 8,9.
-  TransformOperations start;
+  gfx::TransformOperations start;
   start.AppendTranslate(6, 7, 0);
-  TransformOperations end;
+  gfx::TransformOperations end;
   end.AppendTranslate(8, 9, 0);
   AddAnimatedTransformToElementWithAnimation(child->element_id(), timeline(),
                                              4.0, start, end);
@@ -3369,9 +3369,9 @@
   CreateTransformNode(child);
 
   // Add a translate animation.
-  TransformOperations start;
+  gfx::TransformOperations start;
   start.AppendTranslate(6, 7, 0);
-  TransformOperations end;
+  gfx::TransformOperations end;
   end.AppendTranslate(8, 9, 0);
   AddAnimatedTransformToElementWithAnimation(child->element_id(), timeline(),
                                              4.0, start, end);
@@ -16407,9 +16407,9 @@
   // Now add a transform animation to this layer. While we don't drawn layers
   // with non-invertible transforms, we still raster them if there is a
   // transform animation.
-  TransformOperations start_transform_operations;
+  gfx::TransformOperations start_transform_operations;
   start_transform_operations.AppendMatrix(singular);
-  TransformOperations end_transform_operations;
+  gfx::TransformOperations end_transform_operations;
   AddAnimatedTransformToElementWithAnimation(
       animated_transform_layer->element_id(), timeline(), 10.0,
       start_transform_operations, end_transform_operations);
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index 895e0bc..b240cdb 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -20,7 +20,6 @@
 #include "cc/animation/scroll_offset_animation_curve_factory.h"
 #include "cc/animation/scroll_offset_animations.h"
 #include "cc/animation/timing_function.h"
-#include "cc/animation/transform_operations.h"
 #include "cc/base/completion_event.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_impl.h"
@@ -33,6 +32,7 @@
 #include "cc/trees/target_property.h"
 #include "cc/trees/transform_node.h"
 #include "components/viz/common/quads/compositor_frame.h"
+#include "ui/gfx/transform_operations.h"
 
 namespace cc {
 namespace {
@@ -1421,9 +1421,9 @@
 
   void BeginTest() override {
     // Add a translate from 6,7 to 8,9.
-    TransformOperations start;
+    gfx::TransformOperations start;
     start.AppendTranslate(6.f, 7.f, 0.f);
-    TransformOperations end;
+    gfx::TransformOperations end;
     end.AppendTranslate(8.f, 9.f, 0.f);
     AddAnimatedTransformToAnimation(animation_.get(), 4.0, start, end);
 
@@ -2262,9 +2262,9 @@
     timeline_->DetachAnimation(animation_child_.get());
     animation_->AttachElement(layer_->element_id());
 
-    TransformOperations start;
+    gfx::TransformOperations start;
     start.AppendTranslate(5.f, 5.f, 0.f);
-    TransformOperations end;
+    gfx::TransformOperations end;
     end.AppendTranslate(5.f, 5.f, 0.f);
     AddAnimatedTransformToAnimation(animation_.get(), 1.0, start, end);
   }
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index d8d0cd532..4f50d28 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -24,6 +24,7 @@
 #include "cc/trees/transform_node.h"
 #include "components/viz/common/frame_sinks/copy_output_request.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
+#include "ui/gfx/transform_util.h"
 
 namespace cc {
 
@@ -574,7 +575,7 @@
     const gfx::Transform& device_transform) {
   device_scale_factor_ = device_scale_factor;
   gfx::Vector2dF device_transform_scale_components =
-      MathUtil::ComputeTransform2dScaleComponents(device_transform, 1.f);
+      gfx::ComputeTransform2dScaleComponents(device_transform, 1.f);
 
   // Not handling the rare case of different x and y device scale.
   device_transform_scale_factor_ =
@@ -589,8 +590,7 @@
   gfx::Transform transform = device_transform;
   transform.Scale(device_scale_factor, device_scale_factor);
   gfx::Vector2dF screen_space_scale =
-      MathUtil::ComputeTransform2dScaleComponents(transform,
-                                                  device_scale_factor);
+      gfx::ComputeTransform2dScaleComponents(transform, device_scale_factor);
   DCHECK_NE(screen_space_scale.x(), 0.f);
   DCHECK_NE(screen_space_scale.y(), 0.f);
 
@@ -818,9 +818,8 @@
     layer_scale_factor *= transform_tree.page_scale_factor();
 
   const gfx::Vector2dF old_scale = effect_node->surface_contents_scale;
-  effect_node->surface_contents_scale =
-      MathUtil::ComputeTransform2dScaleComponents(
-          transform_tree.ToScreen(transform_node->id), layer_scale_factor);
+  effect_node->surface_contents_scale = gfx::ComputeTransform2dScaleComponents(
+      transform_tree.ToScreen(transform_node->id), layer_scale_factor);
 
   // If surface contents scale changes, draw transforms are no longer valid.
   // Invalidates the draw transform cache and updates the clip for the surface.
@@ -2093,15 +2092,14 @@
     // Will use the parent's maximum_to_screen_scale.
   } else if (!node->to_screen_is_potentially_animated) {
     // No transform animations. Calculate the current to_screen scale.
-    gfx::Vector2dF to_screen_scales =
-        MathUtil::ComputeTransform2dScaleComponents(
-            transform_tree.ToScreen(transform_id), kInvalidScale);
+    gfx::Vector2dF to_screen_scales = gfx::ComputeTransform2dScaleComponents(
+        transform_tree.ToScreen(transform_id), kInvalidScale);
     animation_scale.maximum_to_screen_scale =
         std::max(to_screen_scales.x(), to_screen_scales.y());
     return animation_scale;
   } else if (!node->has_potential_animation) {
     gfx::Vector2dF local_scales =
-        MathUtil::ComputeTransform2dScaleComponents(node->local, 1.0f);
+        gfx::ComputeTransform2dScaleComponents(node->local, 1.0f);
     local_maximum_scale = std::max(local_scales.x(), local_scales.y());
   } else {
     DCHECK_NE(node->maximum_animation_scale, kInvalidScale);
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStream.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStream.java
index 32f0b97..b198b8d 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStream.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStream.java
@@ -80,6 +80,7 @@
 
     @Override
     public void onHide() {
+        mAccumulatedDySinceLastLoadMore = 0;
         mScrollStateToRestore = null;
         if (mFeedStreamSurface.isOpened()) {
             mScrollStateToRestore = getSavedInstanceStateString();
@@ -263,6 +264,9 @@
         if (!mFeedStreamSurface.isOpened()) return;
 
         mAccumulatedDySinceLastLoadMore += dy;
+        if (mAccumulatedDySinceLastLoadMore < 0) {
+            mAccumulatedDySinceLastLoadMore = 0;
+        }
         if (mAccumulatedDySinceLastLoadMore < TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                     LOAD_MORE_TRIGGER_SCROLL_DISTANCE_DP,
                     mRecyclerView.getResources().getDisplayMetrics())) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionProcessor.java
index 86a7b6b..dbcc18d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionProcessor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionProcessor.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.omnibox.suggestions.editurl;
 
 import android.content.Context;
-import android.text.TextUtils;
 
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.Supplier;
@@ -20,7 +19,6 @@
 import org.chromium.chrome.browser.omnibox.suggestions.base.SuggestionDrawableState;
 import org.chromium.chrome.browser.omnibox.suggestions.base.SuggestionSpannable;
 import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewProperties;
-import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.share.ShareDelegate;
 import org.chromium.chrome.browser.share.ShareDelegateImpl.ShareOrigin;
 import org.chromium.chrome.browser.tab.SadTab;
@@ -94,7 +92,8 @@
             return false;
         }
 
-        if (!isSuggestionEquivalentToCurrentPage(suggestion, activeTab.getUrl())) {
+        if (suggestion.getType() != OmniboxSuggestionType.URL_WHAT_YOU_TYPED
+                || !suggestion.getUrl().equals(activeTab.getUrl())) {
             return false;
         }
 
@@ -199,22 +198,4 @@
         RecordUserAction.record("Omnibox.EditUrlSuggestion.Edit");
         mUrlBarDelegate.setOmniboxEditingText(mLastProcessedSuggestionURL.getSpec());
     }
-
-    /**
-     * @return true if the suggestion is effectively the same as the current page, either because:
-     * 1. It's a search suggestion for the same search terms as the current SERP.
-     * 2. It's a URL suggestion for the current URL.
-     */
-    private boolean isSuggestionEquivalentToCurrentPage(
-            AutocompleteMatch suggestion, GURL pageUrl) {
-        switch (suggestion.getType()) {
-            case OmniboxSuggestionType.SEARCH_WHAT_YOU_TYPED:
-                return TextUtils.equals(suggestion.getFillIntoEdit(),
-                        TemplateUrlServiceFactory.get().getSearchQueryForUrl(pageUrl));
-            case OmniboxSuggestionType.URL_WHAT_YOU_TYPED:
-                return suggestion.getUrl().equals(pageUrl);
-            default:
-                return false;
-        }
-    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarTest.java
index 00ba639..946313d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarTest.java
@@ -373,9 +373,9 @@
     @Test
     @MediumTest
     @Restriction(UiRestriction.RESTRICTION_TYPE_TABLET)
-    @DisabledTest(message = "https://crbug.com/1173711")
     public void testFocusLogic_buttonVisibilityTablet() {
         startActivityNormally();
+        doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
         String url = mActivityTestRule.getEmbeddedTestServerRule().getServer().getURLWithHostName(
                 HOSTNAME, "/");
         mActivityTestRule.loadUrl(url);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionUnitTest.java
index 4b56706c..be2423f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionUnitTest.java
@@ -371,7 +371,7 @@
         when(mTemplateUrlService.getSearchQueryForUrl(mBarbazSearchUrl))
                 .thenReturn(BARBAZ_SEARCH_TERMS);
 
-        Assert.assertTrue(mProcessor.doesProcessSuggestion(mSearchSuggestion, 0));
+        Assert.assertFalse(mProcessor.doesProcessSuggestion(mSearchSuggestion, 0));
         Assert.assertFalse(mProcessor.doesProcessSuggestion(mSearchSuggestion, 1));
 
         when(mSearchSuggestion.getUrl()).thenReturn(mBarbazSearchUrl);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamTest.java
index d2e4947..8255f63 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamTest.java
@@ -235,6 +235,32 @@
     }
 
     @Test
+    public void testCheckScrollingForLoadMore_LoadMoreAfterHide() {
+        mFeedStream.onShow();
+        mFeedStream.setStreamContentVisibility(true);
+        final int triggerDistance = getLoadMoreTriggerScrollDistance();
+        final int itemCount = 10;
+
+        // loadMore triggered.
+        mLayoutManager.setLastVisiblePosition(itemCount - LOAD_MORE_TRIGGER_LOOKAHEAD + 1);
+        mLayoutManager.setItemCount(itemCount);
+        mFeedStream.checkScrollingForLoadMore(triggerDistance);
+        verify(mFeedStreamSurfaceJniMock)
+                .loadMore(anyLong(), any(FeedStreamSurface.class), any(Callback.class));
+
+        // loadMore triggered again after hide&show.
+        mFeedStream.checkScrollingForLoadMore(-triggerDistance);
+        mFeedStream.onHide();
+        mFeedStream.onShow();
+
+        mLayoutManager.setLastVisiblePosition(itemCount - LOAD_MORE_TRIGGER_LOOKAHEAD + 1);
+        mLayoutManager.setItemCount(itemCount);
+        mFeedStream.checkScrollingForLoadMore(triggerDistance);
+        verify(mFeedStreamSurfaceJniMock)
+                .loadMore(anyLong(), any(FeedStreamSurface.class), any(Callback.class));
+    }
+
+    @Test
     public void testSerializeScrollState() {
         FeedStream.ScrollState state = new FeedStream.ScrollState();
         state.position = 2;
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index e69342a..915645a 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1982,6 +1982,7 @@
     "//chrome/browser/ui/webui/bluetooth_internals:mojo_bindings",
     "//chrome/browser/ui/webui/downloads:mojo_bindings",
     "//chrome/browser/ui/webui/internals/web_app:mojo_bindings",
+    "//chrome/browser/ui/webui/memories:mojo_bindings",
     "//chrome/browser/ui/webui/new_tab_page:mojo_bindings",
     "//chrome/browser/ui/webui/omnibox:mojo_bindings",
     "//chrome/browser/ui/webui/read_later:mojo_bindings",
@@ -2285,6 +2286,7 @@
     "//media/mojo/services",
     "//media/webrtc",
     "//mojo/core/embedder",
+    "//mojo/core/embedder:features",
     "//mojo/public/cpp/bindings",
     "//net",
     "//net:extras",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 953753e..b243e76 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -176,6 +176,7 @@
   "+components/login",
   "+components/media_message_center",
   "+components/media_router/browser",
+  "+components/memories/common",
   "+components/messages/android",
   "+components/metal_util",
   "+components/metrics",
@@ -415,6 +416,7 @@
   # Code under //ash should be accessed via its public API. See //ash/README.md.
   "-ash",
   "+ash/components",
+  "+ash/constants",
   "+ash/public",
   "+ash/keyboard/ui/grit",
   "+ash/keyboard/ui/resources",
@@ -537,4 +539,7 @@
   "chrome_content_browser_client\.cc" : [
     "+content/public/browser/tts_controller.h",
   ],
+  "about_flags\.cc" : [
+    "+mojo/core/embedder/features.h",
+  ]
 }
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 2de52ed8..bd4e059 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -157,6 +157,7 @@
 #include "media/media_buildflags.h"
 #include "media/midi/midi_switches.h"
 #include "media/webrtc/webrtc_switches.h"
+#include "mojo/core/embedder/features.h"
 #include "net/base/features.h"
 #include "net/net_buildflags.h"
 #include "net/nqe/effective_connection_type.h"
@@ -210,10 +211,10 @@
 #endif  // OS_ANDROID
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "chrome/browser/chromeos/crosapi/browser_util.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_features.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/services/assistant/public/cpp/features.h"
 #include "components/arc/arc_features.h"
@@ -727,20 +728,33 @@
      switches::kForceDirectionRTL},
 };
 
-const FeatureEntry::Choice kDesktopPWAsAttentionBadgingCrOSChoices[] = {
-    {flags_ui::kGenericExperimentChoiceDefault, "", ""},
-    {flag_descriptions::kDesktopPWAsAttentionBadgingCrOSApiAndNotifications,
-     switches::kDesktopPWAsAttentionBadgingCrOS,
-     switches::kDesktopPWAsAttentionBadgingCrOSApiAndNotifications},
-    {flag_descriptions::kDesktopPWAsAttentionBadgingCrOSApiOnly,
-     switches::kDesktopPWAsAttentionBadgingCrOS,
-     switches::kDesktopPWAsAttentionBadgingCrOSApiOnly},
-    {flag_descriptions::kDesktopPWAsAttentionBadgingCrOSNotificationsOnly,
-     switches::kDesktopPWAsAttentionBadgingCrOS,
-     switches::kDesktopPWAsAttentionBadgingCrOSNotificationsOnly},
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+const FeatureEntry::FeatureParam
+    kDesktopPWAsAttentionBadgingCrOSApiAndNotifications[] = {
+        {"badge-source",
+         switches::kDesktopPWAsAttentionBadgingCrOSApiAndNotifications}};
+const FeatureEntry::FeatureParam kDesktopPWAsAttentionBadgingCrOSApiOnly[] = {
+    {"badge-source", switches::kDesktopPWAsAttentionBadgingCrOSApiOnly}};
+const FeatureEntry::FeatureParam
+    kDesktopPWAsAttentionBadgingCrOSNotificationsOnly[] = {
+        {"badge-source",
+         switches::kDesktopPWAsAttentionBadgingCrOSNotificationsOnly}};
+
+const FeatureEntry::FeatureVariation
+    kDesktopPWAsAttentionBadgingCrOSVariations[] = {
+        {flag_descriptions::kDesktopPWAsAttentionBadgingCrOSApiAndNotifications,
+         kDesktopPWAsAttentionBadgingCrOSApiAndNotifications,
+         base::size(kDesktopPWAsAttentionBadgingCrOSApiAndNotifications),
+         nullptr},
+        {flag_descriptions::kDesktopPWAsAttentionBadgingCrOSApiOnly,
+         kDesktopPWAsAttentionBadgingCrOSApiOnly,
+         base::size(kDesktopPWAsAttentionBadgingCrOSApiOnly), nullptr},
+        {flag_descriptions::kDesktopPWAsAttentionBadgingCrOSNotificationsOnly,
+         kDesktopPWAsAttentionBadgingCrOSNotificationsOnly,
+         base::size(kDesktopPWAsAttentionBadgingCrOSNotificationsOnly),
+         nullptr},
 };
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
 const FeatureEntry::Choice kSchedulerConfigurationChoices[] = {
     {flags_ui::kGenericExperimentChoiceDefault, "", ""},
     {flag_descriptions::kSchedulerConfigurationConservative,
@@ -3244,6 +3258,13 @@
      FEATURE_VALUE_TYPE(performance_manager::features::kDynamicTcmallocTuning)},
 #endif  // BUILDFLAG(USE_TCMALLOC)
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#if (defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_ANDROID)) && \
+    !defined(OS_NACL)
+    {"mojo-linux-sharedmem", flag_descriptions::kMojoLinuxChannelSharedMemName,
+     flag_descriptions::kMojoLinuxChannelSharedMemDescription,
+     kOsCrOS | kOsLinux | kOsAndroid,
+     FEATURE_VALUE_TYPE(mojo::core::kMojoLinuxChannelSharedMem)},
+#endif
 #if defined(OS_ANDROID)
     {"enable-site-isolation-for-password-sites",
      flag_descriptions::kSiteIsolationForPasswordSitesName,
@@ -3346,10 +3367,14 @@
      flag_descriptions::kDesktopPWAsAppIconShortcutsMenuName,
      flag_descriptions::kDesktopPWAsAppIconShortcutsMenuDescription, kOsWin,
      FEATURE_VALUE_TYPE(features::kDesktopPWAsAppIconShortcutsMenu)},
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     {"enable-desktop-pwas-attention-badging-cros",
      flag_descriptions::kDesktopPWAsAttentionBadgingCrOSName,
      flag_descriptions::kDesktopPWAsAttentionBadgingCrOSDescription, kOsCrOS,
-     MULTI_VALUE_TYPE(kDesktopPWAsAttentionBadgingCrOSChoices)},
+     FEATURE_WITH_PARAMS_VALUE_TYPE(features::kDesktopPWAsAttentionBadgingCrOS,
+                                    kDesktopPWAsAttentionBadgingCrOSVariations,
+                                    "DesktopPWAsAttentionBadgingCrOS")},
+#endif
     {"enable-desktop-pwas-remove-status-bar",
      flag_descriptions::kDesktopPWAsRemoveStatusBarName,
      flag_descriptions::kDesktopPWAsRemoveStatusBarDescription, kOsDesktop,
@@ -3810,6 +3835,13 @@
      flag_descriptions::kSwitchAccessPointScanningName,
      flag_descriptions::kSwitchAccessPointScanningDescription, kOsCrOS,
      SINGLE_VALUE_TYPE(::switches::kEnableSwitchAccessPointScanning)},
+    {"enable-experimental-accessibility-switch-access-setup-guide",
+     flag_descriptions::kExperimentalAccessibilitySwitchAccessSetupGuideName,
+     flag_descriptions::
+         kExperimentalAccessibilitySwitchAccessSetupGuideDescription,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(
+         ::switches::kEnableExperimentalAccessibilitySwitchAccessSetupGuide)},
     {"enable-experimental-accessibility-chromevox-annotations",
      flag_descriptions::kExperimentalAccessibilityChromeVoxAnnotationsName,
      flag_descriptions::
diff --git a/chrome/browser/apps/app_service/notifications_browsertest.cc b/chrome/browser/apps/app_service/notifications_browsertest.cc
index 43acefb..8681a1f 100644
--- a/chrome/browser/apps/app_service/notifications_browsertest.cc
+++ b/chrome/browser/apps/app_service/notifications_browsertest.cc
@@ -27,7 +27,7 @@
 #include "chrome/browser/notifications/profile_notification.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
-#include "chrome/common/chrome_switches.h"
+#include "chrome/common/chrome_features.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/session/arc_bridge_service.h"
@@ -258,6 +258,13 @@
   AppNotificationsWebNotificationTest() = default;
   ~AppNotificationsWebNotificationTest() override = default;
 
+  void SetUp() override {
+    base::test::ScopedFeatureList scoped_feature_list_;
+    scoped_feature_list_.InitAndDisableFeature(
+        features::kDesktopPWAsAttentionBadgingCrOS);
+    extensions::PlatformAppBrowserTest::SetUp();
+  }
+
   // extensions::PlatformAppBrowserTest:
   void SetUpOnMainThread() override {
     extensions::PlatformAppBrowserTest::SetUpOnMainThread();
@@ -266,13 +273,6 @@
     ASSERT_TRUE(https_server_.Start());
   }
 
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    extensions::PlatformAppBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitchASCII(
-        switches::kDesktopPWAsAttentionBadgingCrOS,
-        switches::kDesktopPWAsAttentionBadgingCrOSApiAndNotifications);
-  }
-
   std::string CreateWebApp(const GURL& url, const GURL& scope) const {
     auto web_app_info = std::make_unique<WebApplicationInfo>();
     web_app_info->start_url = url;
diff --git a/chrome/browser/apps/app_service/web_apps_chromeos.cc b/chrome/browser/apps/app_service/web_apps_chromeos.cc
index 28c61cf..941c344 100644
--- a/chrome/browser/apps/app_service/web_apps_chromeos.cc
+++ b/chrome/browser/apps/app_service/web_apps_chromeos.cc
@@ -64,19 +64,6 @@
 #include "ui/message_center/public/cpp/notification.h"
 #include "url/origin.h"
 
-namespace {
-
-std::string GetDesktopPWAsAttentionBadgingFlag() {
-  const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
-  if (cmdline->HasSwitch(switches::kDesktopPWAsAttentionBadgingCrOS)) {
-    return cmdline->GetSwitchValueASCII(
-        switches::kDesktopPWAsAttentionBadgingCrOS);
-  }
-  return switches::kDesktopPWAsAttentionBadgingCrOSApiOnly;
-}
-
-}  // namespace
-
 namespace apps {
 
 WebAppsChromeOs::BadgeManagerDelegate::BadgeManagerDelegate(
@@ -643,22 +630,25 @@
 apps::mojom::OptionalBool WebAppsChromeOs::ShouldShowBadge(
     const std::string& app_id,
     apps::mojom::OptionalBool has_notification) {
-  std::string flag = GetDesktopPWAsAttentionBadgingFlag();
+  bool enabled =
+      base::FeatureList::IsEnabled(features::kDesktopPWAsAttentionBadgingCrOS);
+  std::string flag =
+      enabled ? features::kDesktopPWAsAttentionBadgingCrOSParam.Get() : "";
   if (flag == switches::kDesktopPWAsAttentionBadgingCrOSApiOnly) {
     // Show a badge based only on the Web Badging API.
     return badge_manager_ && badge_manager_->GetBadgeValue(app_id).has_value()
                ? apps::mojom::OptionalBool::kTrue
                : apps::mojom::OptionalBool::kFalse;
   } else if (flag ==
-             switches::kDesktopPWAsAttentionBadgingCrOSNotificationsOnly) {
-    // Show a badge only if a notification is showing.
-    return has_notification;
-  } else {
+             switches::kDesktopPWAsAttentionBadgingCrOSApiAndNotifications) {
     // When the flag is set to "api-and-notifications" we show a badge if either
     // a notification is showing or the Web Badging API has a badge set.
     return badge_manager_ && badge_manager_->GetBadgeValue(app_id).has_value()
                ? apps::mojom::OptionalBool::kTrue
                : has_notification;
+  } else {
+    // Show a badge only if a notification is showing.
+    return has_notification;
   }
 }
 }  // namespace apps
diff --git a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc
index 06f9d59d..76094bdf 100644
--- a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc
+++ b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include <queue>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/accelerators.h"
 #include "ash/public/cpp/accessibility_controller.h"
 #include "ash/public/cpp/event_rewriter_controller.h"
@@ -42,7 +43,6 @@
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/user_manager/user_names.h"
 #include "content/public/browser/browser_task_traits.h"
diff --git a/chrome/browser/badging/badge_manager_delegate_mac.cc b/chrome/browser/badging/badge_manager_delegate_mac.cc
index 9da7bac..85e3c46 100644
--- a/chrome/browser/badging/badge_manager_delegate_mac.cc
+++ b/chrome/browser/badging/badge_manager_delegate_mac.cc
@@ -12,26 +12,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/common/mac/app_shim.mojom.h"
 
-namespace {
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused.
-enum class UpdateAppBadgeResult : int {
-  kSuccess = 0,
-  kNoShimManager = 1,
-  kNoShimHost = 2,
-  kNoAppShim = 3,
-  kMaxValue = kNoAppShim
-};
-
-constexpr const char* kBadgeMetricName = "Badging.AppBadgeUpdate.Mac.Result";
-
-// Records UMA metric for updating app badge.
-void RecordUpdateAppBadge(const UpdateAppBadgeResult result) {
-  UMA_HISTOGRAM_ENUMERATION(kBadgeMetricName, result);
-}
-
-}  // namespace
-
 namespace badging {
 
 BadgeManagerDelegateMac::BadgeManagerDelegateMac(Profile* profile,
@@ -47,25 +27,22 @@
 void BadgeManagerDelegateMac::SetAppBadgeLabel(const std::string& app_id,
                                                const std::string& badge_label) {
   auto* shim_manager = apps::AppShimManager::Get();
-  if (!shim_manager) {
-    RecordUpdateAppBadge(UpdateAppBadgeResult::kNoShimManager);
+  if (!shim_manager)
     return;
-  }
 
   // On macOS all app instances share a dock icon, so we only need to set the
   // badge label once.
+  // We only get the app shim host when the app is running. If Badging API is
+  // called when the app is not running this will fail as expected.
   AppShimHost* shim_host = shim_manager->FindHost(profile(), app_id);
-  if (!shim_host) {
-    RecordUpdateAppBadge(UpdateAppBadgeResult::kNoShimHost);
+  if (!shim_host)
     return;
-  }
+
   chrome::mojom::AppShim* shim = shim_host->GetAppShim();
-  if (!shim) {
-    RecordUpdateAppBadge(UpdateAppBadgeResult::kNoAppShim);
+  if (!shim)
     return;
-  }
+
   shim->SetBadgeLabel(badge_label);
-  RecordUpdateAppBadge(UpdateAppBadgeResult::kSuccess);
 }
 
 }  // namespace badging
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index a70d7f5..ae6e16a 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -37,7 +38,6 @@
 #include "chrome/browser/ui/webui/usb_internals/usb_internals_ui.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/contextual_search/buildflags.h"
 #include "components/dom_distiller/content/browser/distillability_driver.h"
 #include "components/dom_distiller/content/browser/distiller_javascript_service_impl.h"
@@ -121,6 +121,8 @@
 #include "chrome/browser/ui/webui/new_tab_page/foo/foo.mojom.h"  // nogncheck crbug.com/1125897
 #endif
 #include "chrome/browser/ui/webui/media/media_feeds_ui.h"
+#include "chrome/browser/ui/webui/memories/memories.mojom.h"
+#include "chrome/browser/ui/webui/memories/memories_ui.h"
 #include "chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom.h"
 #include "chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h"
 #include "chrome/browser/ui/webui/read_later/read_later.mojom.h"
@@ -634,6 +636,9 @@
   RegisterWebUIControllerInterfaceBinder<
       new_tab_page::mojom::PageHandlerFactory, NewTabPageUI>(map);
 
+  RegisterWebUIControllerInterfaceBinder<memories::mojom::PageHandler,
+                                         MemoriesUI>(map);
+
   RegisterWebUIControllerInterfaceBinder<
       promo_browser_command::mojom::CommandHandler, NewTabPageUI>(map);
 
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc
index 1865719..67dd47d 100644
--- a/chrome/browser/chrome_content_browser_client_unittest.cc
+++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -64,6 +64,7 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service.h"
@@ -72,7 +73,6 @@
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/components/scanning/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/policy/core/common/policy_pref_names.h"
 #include "components/user_manager/scoped_user_manager.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/chromeos/DEPS b/chrome/browser/chromeos/DEPS
index dcb3c17..43e516d5 100644
--- a/chrome/browser/chromeos/DEPS
+++ b/chrome/browser/chromeos/DEPS
@@ -32,6 +32,7 @@
   ],
   ".*test.*": [
    "!ash",
+   "+ash/constants",
    "+ash/public",
   ],
   "assistant_util_unittest\.cc": [
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl_unittest.cc b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl_unittest.cc
index 5a476fb..1a69078 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl_unittest.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl_unittest.cc
@@ -9,6 +9,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/path_service.h"
@@ -18,7 +19,6 @@
 #include "chrome/browser/chromeos/android_sms/android_sms_urls.h"
 #include "chrome/browser/chromeos/android_sms/fake_android_sms_app_setup_controller.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/chromeos/android_sms/android_sms_urls.cc b/chrome/browser/chromeos/android_sms/android_sms_urls.cc
index ef58298e..150c0db 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_urls.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_urls.cc
@@ -6,10 +6,10 @@
 
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "base/command_line.h"
 #include "base/strings/strcat.h"
 #include "chrome/browser/chromeos/android_sms/android_sms_switches.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "url/gurl.h"
 
 namespace chromeos {
diff --git a/chrome/browser/chromeos/arc/arc_util.cc b/chrome/browser/chromeos/arc/arc_util.cc
index cf02910..9290d9a 100644
--- a/chrome/browser/chromeos/arc/arc_util.cc
+++ b/chrome/browser/chromeos/arc/arc_util.cc
@@ -11,6 +11,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/files/file_path.h"
@@ -43,7 +44,6 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/simple_message_box.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/arc/arc_features.h"
 #include "components/arc/arc_prefs.h"
diff --git a/chrome/browser/chromeos/arc/arc_util_unittest.cc b/chrome/browser/chromeos/arc/arc_util_unittest.cc
index adb8a309..aa47dd9 100644
--- a/chrome/browser/chromeos/arc/arc_util_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_util_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/system/sys_info.h"
@@ -30,7 +31,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/constants/chromeos_features.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_oobe_configuration_client.h"
 #include "chromeos/tpm/stub_install_attributes.h"
diff --git a/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc b/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc
index 445d3ad..3d1ead3 100644
--- a/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc
+++ b/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/strings/string_util.h"
@@ -11,7 +12,6 @@
 #include "chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper.pb.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/common/extensions/api/wallpaper_private.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/constants/devicetype.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/chromeos/bluetooth/debug_logs_manager.cc b/chrome/browser/chromeos/bluetooth/debug_logs_manager.cc
index 75eb71e..d2b95cd 100644
--- a/chrome/browser/chromeos/bluetooth/debug_logs_manager.cc
+++ b/chrome/browser/chromeos/bluetooth/debug_logs_manager.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/browser/chromeos/bluetooth/debug_logs_manager.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "device/bluetooth/dbus/bluetooth_debug_manager_client.h"
diff --git a/chrome/browser/chromeos/bluetooth/debug_logs_manager_unittest.cc b/chrome/browser/chromeos/bluetooth/debug_logs_manager_unittest.cc
index d41611e..0658f7e 100644
--- a/chrome/browser/chromeos/bluetooth/debug_logs_manager_unittest.cc
+++ b/chrome/browser/chromeos/bluetooth/debug_logs_manager_unittest.cc
@@ -6,9 +6,9 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/testing_pref_service.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
 #include "device/bluetooth/dbus/fake_bluetooth_debug_manager_client.h"
diff --git a/chrome/browser/chromeos/borealis/borealis_task.cc b/chrome/browser/chromeos/borealis/borealis_task.cc
index dfc92f5..193e3a1 100644
--- a/chrome/browser/chromeos/borealis/borealis_task.cc
+++ b/chrome/browser/chromeos/borealis/borealis_task.cc
@@ -3,8 +3,10 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/chromeos/borealis/borealis_task.h"
+
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
@@ -13,7 +15,6 @@
 #include "chrome/browser/chromeos/borealis/borealis_util.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/concierge/concierge_service.pb.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 
diff --git a/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager.cc b/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager.cc
index e943bbe2..6801424 100644
--- a/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager.cc
+++ b/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager.cc
@@ -7,6 +7,7 @@
 #include <tuple>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/notification_utils.h"
 #include "ash/public/cpp/vm_camera_mic_constants.h"
 #include "base/bind.h"
@@ -25,7 +26,6 @@
 #include "chrome/browser/ui/webui/settings/chromeos/app_management/app_management_uma.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom-forward.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/vector_icons/vector_icons.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager_unittest.cc b/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager_unittest.cc
index d99e38f..0510b3d 100644
--- a/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager_unittest.cc
+++ b/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager_unittest.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/vm_camera_mic_constants.h"
 #include "base/bind.h"
 #include "base/containers/flat_map.h"
@@ -17,7 +18,6 @@
 #include "chrome/browser/notifications/notification_display_service.h"
 #include "chrome/browser/notifications/notification_display_service_factory.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "components/user_manager/user.h"
 #include "content/public/test/browser_task_environment.h"
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index dfea457..52fb3cf 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -10,6 +10,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/keyboard/ui/resources/keyboard_resource_util.h"
 #include "ash/public/ash_interfaces.h"
 #include "ash/public/cpp/event_rewriter_controller.h"
@@ -153,7 +154,6 @@
 #include "chromeos/components/local_search_service/public/cpp/local_search_service_proxy_factory.h"
 #include "chromeos/components/power/dark_resume_controller.h"
 #include "chromeos/components/sensors/sensor_hal_dispatcher.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/cryptohome/homedir_methods.h"
diff --git a/chrome/browser/chromeos/crosapi/browser_util.cc b/chrome/browser/chromeos/crosapi/browser_util.cc
index 94cb551..485d95d8 100644
--- a/chrome/browser/chromeos/crosapi/browser_util.cc
+++ b/chrome/browser/chromeos/crosapi/browser_util.cc
@@ -10,6 +10,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/callback.h"
 #include "base/containers/flat_map.h"
 #include "base/feature_list.h"
@@ -27,7 +28,6 @@
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/crosapi/cpp/crosapi_constants.h"
 #include "chromeos/crosapi/mojom/cert_database.mojom.h"
 #include "chromeos/crosapi/mojom/crosapi.mojom.h"
diff --git a/chrome/browser/chromeos/crosapi/browser_util_unittest.cc b/chrome/browser/chromeos/crosapi/browser_util_unittest.cc
index 4a639995..c2d3aeb 100644
--- a/chrome/browser/chromeos/crosapi/browser_util_unittest.cc
+++ b/chrome/browser/chromeos/crosapi/browser_util_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/crosapi/browser_util.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
@@ -14,7 +15,6 @@
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/crosapi/mojom/crosapi.mojom.h"
 #include "components/account_id/account_id.h"
 #include "components/user_manager/scoped_user_manager.h"
diff --git a/chrome/browser/chromeos/crostini/crostini_features.cc b/chrome/browser/chromeos/crostini/crostini_features.cc
index cb387a8..cefa9ef 100644
--- a/chrome/browser/chromeos/crostini/crostini_features.cc
+++ b/chrome/browser/chromeos/crostini/crostini_features.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/crostini/crostini_features.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
@@ -17,7 +18,6 @@
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_features.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/crostini/crostini_features_unittest.cc b/chrome/browser/chromeos/crostini/crostini_features_unittest.cc
index 3c6067f..1e81fda 100644
--- a/chrome/browser/chromeos/crostini/crostini_features_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_features_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/crostini/crostini_features.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/callback.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
@@ -13,7 +14,6 @@
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index a175d6db8..9ca0269 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -51,7 +52,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/anomaly_detector_client.h"
 #include "chromeos/dbus/concierge_client.h"
 #include "chromeos/dbus/cros_disks_client.h"
diff --git a/chrome/browser/chromeos/crostini/termina_installer.cc b/chrome/browser/chromeos/crostini/termina_installer.cc
index 7a37f262..67cf2b1 100644
--- a/chrome/browser/chromeos/crostini/termina_installer.cc
+++ b/chrome/browser/chromeos/crostini/termina_installer.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/callback.h"
@@ -17,7 +18,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/browser/network_service_instance.h"
 #include "services/network/public/cpp/network_connection_tracker.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
diff --git a/chrome/browser/chromeos/crostini/termina_installer_unittest.cc b/chrome/browser/chromeos/crostini/termina_installer_unittest.cc
index b212fd7e..12b9dae9 100644
--- a/chrome/browser/chromeos/crostini/termina_installer_unittest.cc
+++ b/chrome/browser/chromeos/crostini/termina_installer_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/crostini/termina_installer.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
@@ -12,7 +13,6 @@
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/component_updater/fake_cros_component_manager.h"
 #include "chrome/test/base/browser_process_platform_part_test_api_chromeos.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/dlcservice/dlcservice_client.h"
 #include "chromeos/dbus/dlcservice/fake_dlcservice_client.h"
 #include "services/network/test/test_network_connection_tracker.h"
diff --git a/chrome/browser/chromeos/cryptauth/client_app_metadata_provider_service.cc b/chrome/browser/chromeos/cryptauth/client_app_metadata_provider_service.cc
index 141fa2f..ab36be3 100644
--- a/chrome/browser/chromeos/cryptauth/client_app_metadata_provider_service.cc
+++ b/chrome/browser/chromeos/cryptauth/client_app_metadata_provider_service.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "base/callback.h"
 #include "base/feature_list.h"
@@ -21,7 +22,6 @@
 #include "chrome/browser/chromeos/cryptauth/cryptauth_device_id_provider_impl.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/components/multidevice/logging/logging.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/network/network_state_handler.h"
 #include "chromeos/network/network_type_pattern.h"
 #include "chromeos/services/device_sync/proto/cryptauth_better_together_feature_metadata.pb.h"
diff --git a/chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.cc b/chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.cc
index 267fa6b..e6120dd8f 100644
--- a/chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.cc
+++ b/chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.cc
@@ -8,6 +8,7 @@
 #include <stdint.h>
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "base/hash/md5.h"
 #include "base/linux_util.h"
 #include "base/no_destructor.h"
@@ -15,7 +16,6 @@
 #include "base/version.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/chromeos/cryptauth/cryptauth_device_id_provider_impl.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/version_info/version_info.h"
 
 namespace chromeos {
diff --git a/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc b/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc
index 7a9fabff..2e89c89 100644
--- a/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc
+++ b/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc
@@ -9,6 +9,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "chrome/browser/browser_process.h"
@@ -18,7 +19,6 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_features.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/arc/arc_features.h"
 #include "components/prefs/pref_service.h"
 #include "dbus/bus.h"
diff --git a/chrome/browser/chromeos/dbus/vm/vm_permission_service_provider.cc b/chrome/browser/chromeos/dbus/vm/vm_permission_service_provider.cc
index 687de89b..a4d958d 100644
--- a/chrome/browser/chromeos/dbus/vm/vm_permission_service_provider.cc
+++ b/chrome/browser/chromeos/dbus/vm/vm_permission_service_provider.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
@@ -17,7 +18,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/vm_permission_service/vm_permission_service.pb.h"
 #include "components/prefs/pref_service.h"
 #include "dbus/message.h"
diff --git a/chrome/browser/chromeos/drive/drivefs_native_message_host.cc b/chrome/browser/chromeos/drive/drivefs_native_message_host.cc
index 146ded8..71a4c56 100644
--- a/chrome/browser/chromeos/drive/drivefs_native_message_host.cc
+++ b/chrome/browser/chromeos/drive/drivefs_native_message_host.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/drive/drivefs_native_message_host.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/logging.h"
@@ -13,7 +14,6 @@
 #include "chrome/browser/extensions/api/messaging/native_message_port.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/drive/file_errors.h"
 #include "extensions/browser/api/messaging/channel_endpoint.h"
 #include "extensions/browser/api/messaging/message_service.h"
diff --git a/chrome/browser/chromeos/drive/drivefs_native_message_host_unittest.cc b/chrome/browser/chromeos/drive/drivefs_native_message_host_unittest.cc
index 3b45624..e50a8b5 100644
--- a/chrome/browser/chromeos/drive/drivefs_native_message_host_unittest.cc
+++ b/chrome/browser/chromeos/drive/drivefs_native_message_host_unittest.cc
@@ -6,13 +6,13 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/run_loop.h"
 #include "base/test/gmock_callback_support.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "chromeos/components/drivefs/mojom/drivefs.mojom-test-utils.h"
 #include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "extensions/browser/api/messaging/native_message_host.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
diff --git a/chrome/browser/chromeos/events/event_rewriter_unittest.cc b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
index 167588c..d46666d 100644
--- a/chrome/browser/chromeos/events/event_rewriter_unittest.cc
+++ b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/shell.h"
 #include "ash/sticky_keys/sticky_keys_controller.h"
 #include "ash/sticky_keys/sticky_keys_overlay.h"
@@ -19,7 +20,6 @@
 #include "chrome/browser/chromeos/preferences.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/chrome_ash_test_base.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/prefs/pref_member.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
index 5e8b14e..2b18be2f7 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "base/base64.h"
 #include "base/bind.h"
@@ -30,7 +31,6 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/concierge/concierge_service.pb.h"
 #include "chromeos/dbus/cros_disks_client.h"
 #include "chromeos/disks/disk.h"
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
index c85a9641..d5d9c96 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
@@ -9,6 +9,7 @@
 #include <set>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -46,7 +47,6 @@
 #include "chrome/common/extensions/api/file_manager_private_internal.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chromeos/components/drivefs/drivefs_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_state_handler.h"
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc
index 30a048c8..87435426 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc
@@ -18,6 +18,7 @@
 #include "base/task/post_task.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
+#include "chrome/browser/chromeos/file_manager/file_tasks_notifier.h"
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
 #include "chrome/browser/chromeos/smb_client/smb_service.h"
@@ -28,6 +29,7 @@
 #include "components/drive/event_logger.h"
 #include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/task_util.h"
+#include "storage/browser/file_system/file_system_url.h"
 #include "ui/shell_dialogs/selected_file_info.h"
 
 namespace extensions {
@@ -59,6 +61,21 @@
   if (path.empty())
     return RespondNow(Error("Invalid path"));
 
+  if (auto* notifier =
+          file_manager::file_tasks::FileTasksNotifier::GetForProfile(
+              chrome_details_.GetProfile())) {
+    const scoped_refptr<storage::FileSystemContext> file_system_context =
+        file_manager::util::GetFileSystemContextForRenderFrameHost(
+            chrome_details_.GetProfile(), render_frame_host());
+
+    std::vector<storage::FileSystemURL> urls;
+    const storage::FileSystemURL url =
+        file_system_context->CrackURL(GURL(params->source));
+    urls.push_back(url);
+
+    notifier->NotifyFileTasks(urls);
+  }
+
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   std::vector<std::string> options;
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
index b954396f..63d2ec7 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
@@ -11,6 +11,7 @@
 #include <string>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
@@ -25,7 +26,6 @@
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/extensions/api/file_manager_private.h"
 #include "chrome/common/extensions/api/file_manager_private_internal.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_switches.h"
 #include "extensions/browser/api/file_handlers/directory_util.h"
diff --git a/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc b/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc
index 630e415..fcc375a 100644
--- a/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc
+++ b/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -36,7 +37,6 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile_manager.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/cryptohome/mock_homedir_methods.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
 #include "chromeos/dbus/cryptohome/fake_cryptohome_client.h"
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
index 185e49cb..43d3963 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -33,7 +34,6 @@
 #include "chrome/browser/ui/webui/settings/chromeos/pref_names.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
diff --git a/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc b/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc
index b5eb735..e24c09be 100644
--- a/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc
+++ b/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc
@@ -4,6 +4,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -27,7 +28,6 @@
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/media_router/browser/test/mock_media_router.h"
 #include "components/session_manager/core/session_manager.h"
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
index 12c02d7..072dfda4 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -10,6 +10,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/test/shell_test_api.h"
 #include "base/bind.h"
@@ -72,7 +73,6 @@
 #include "chromeos/components/drivefs/fake_drivefs.h"
 #include "chromeos/components/smbfs/smbfs_host.h"
 #include "chromeos/components/smbfs/smbfs_mounter.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/concierge/concierge_service.pb.h"
 #include "chromeos/dbus/constants/dbus_switches.h"
diff --git a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
index 9306260..0503f5b 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/file_manager/file_manager_string_util.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "base/feature_list.h"
 #include "base/logging.h"
@@ -16,7 +17,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/arc/arc_features.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc
index 9b8ccb3b..a2daeff6 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -11,6 +11,7 @@
 #include <utility>
 
 #include "apps/launcher.h"
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/containers/contains.h"
 #include "base/feature_list.h"
@@ -47,7 +48,6 @@
 #include "chrome/common/extensions/api/file_manager_private.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/drive/drive_api_util.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/file_manager/file_tasks_browsertest.cc b/chrome/browser/chromeos/file_manager/file_tasks_browsertest.cc
index 974fd3c..7f88e79a 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks_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/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/test/bind.h"
 #include "chrome/browser/chromeos/file_manager/app_id.h"
@@ -17,7 +18,6 @@
 #include "chrome/browser/web_applications/test/profile_test_helper.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/test/browser_test.h"
 #include "extensions/browser/api/file_handlers/mime_util.h"
 #include "extensions/browser/entry_info.h"
diff --git a/chrome/browser/chromeos/file_manager/url_util.cc b/chrome/browser/chromeos/file_manager/url_util.cc
index 36b4ccf..5b4ebfa5 100644
--- a/chrome/browser/chromeos/file_manager/url_util.cc
+++ b/chrome/browser/chromeos/file_manager/url_util.cc
@@ -9,10 +9,10 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/json/json_writer.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/file_manager/app_id.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "net/base/escape.h"
 
 namespace file_manager {
diff --git a/chrome/browser/chromeos/file_manager/url_util_unittest.cc b/chrome/browser/chromeos/file_manager/url_util_unittest.cc
index e88f9f2..0810093e 100644
--- a/chrome/browser/chromeos/file_manager/url_util_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/url_util_unittest.cc
@@ -6,13 +6,13 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/files/file_path.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "extensions/common/constants.h"
 #include "net/base/escape.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc b/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc
index d581cc28..7430fd9 100644
--- a/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc
+++ b/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/full_restore/full_restore_service.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/json/json_string_value_serializer.h"
@@ -16,7 +17,6 @@
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/account_id/account_id.h"
 #include "components/full_restore/full_restore_info.h"
 #include "components/full_restore/full_restore_utils.h"
diff --git a/chrome/browser/chromeos/full_restore/new_user_restore_pref_handler.cc b/chrome/browser/chromeos/full_restore/new_user_restore_pref_handler.cc
index 4354c09..c8793151 100644
--- a/chrome/browser/chromeos/full_restore/new_user_restore_pref_handler.cc
+++ b/chrome/browser/chromeos/full_restore/new_user_restore_pref_handler.cc
@@ -4,11 +4,11 @@
 
 #include "chrome/browser/chromeos/full_restore/new_user_restore_pref_handler.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "chrome/browser/chromeos/full_restore/full_restore_prefs.h"
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chromeos/constants/chromeos_features.h"
 
 namespace chromeos {
 namespace full_restore {
diff --git a/chrome/browser/chromeos/input_method/assistive_suggester.cc b/chrome/browser/chromeos/input_method/assistive_suggester.cc
index c9e57dd..5176e59 100644
--- a/chrome/browser/chromeos/input_method/assistive_suggester.cc
+++ b/chrome/browser/chromeos/input_method/assistive_suggester.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/input_method/assistive_suggester.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/window_properties.h"
 #include "base/feature_list.h"
 #include "base/hash/hash.h"
@@ -13,7 +14,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/exo/wm_helper.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/input_method/assistive_suggester_unittest.cc b/chrome/browser/chromeos/input_method/assistive_suggester_unittest.cc
index 78aa0f9..cb1dd95 100644
--- a/chrome/browser/chromeos/input_method/assistive_suggester_unittest.cc
+++ b/chrome/browser/chromeos/input_method/assistive_suggester_unittest.cc
@@ -5,10 +5,10 @@
 #include "chrome/browser/chromeos/input_method/assistive_suggester.h"
 #include "chrome/browser/chromeos/input_method/personal_info_suggester.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "content/public/test/browser_task_environment.h"
diff --git a/chrome/browser/chromeos/input_method/component_extension_ime_manager_delegate_impl.cc b/chrome/browser/chromeos/input_method/component_extension_ime_manager_delegate_impl.cc
index 89779a8..27366c58 100644
--- a/chrome/browser/chromeos/input_method/component_extension_ime_manager_delegate_impl.cc
+++ b/chrome/browser/chromeos/input_method/component_extension_ime_manager_delegate_impl.cc
@@ -8,6 +8,7 @@
 
 #include <algorithm>
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/files/file_util.h"
 #include "base/json/json_string_value_serializer.h"
@@ -25,7 +26,6 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/grit/browser_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/ime/input_methods.h"
 #include "extensions/browser/extension_pref_value_map.h"
 #include "extensions/browser/extension_pref_value_map_factory.h"
diff --git a/chrome/browser/chromeos/input_method/emoji_suggester.cc b/chrome/browser/chromeos/input_method/emoji_suggester.cc
index f46c0e7..b966e63 100644
--- a/chrome/browser/chromeos/input_method/emoji_suggester.cc
+++ b/chrome/browser/chromeos/input_method/emoji_suggester.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/input_method/emoji_suggester.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/files/file_util.h"
 #include "base/i18n/number_formatting.h"
 #include "base/metrics/field_trial_params.h"
@@ -19,7 +20,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "chromeos/services/ime/constants.h"
 #include "components/prefs/scoped_user_pref_update.h"
diff --git a/chrome/browser/chromeos/input_method/input_method_syncer.cc b/chrome/browser/chromeos/input_method/input_method_syncer.cc
index 1e28baff..c5bd2fea 100644
--- a/chrome/browser/chromeos/input_method/input_method_syncer.cc
+++ b/chrome/browser/chromeos/input_method/input_method_syncer.cc
@@ -8,6 +8,7 @@
 #include <set>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
@@ -17,7 +18,6 @@
 #include "base/task_runner.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/sync_preferences/pref_service_syncable.h"
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine.cc b/chrome/browser/chromeos/input_method/native_input_method_engine.cc
index 151cc55..56ea201 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/input_method/native_input_method_engine.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/i18n/i18n_constants.h"
 #include "base/i18n/icu_string_conversions.h"
@@ -16,7 +17,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "third_party/icu/source/common/unicode/unistr.h"
 #include "third_party/icu/source/common/unicode/urename.h"
 #include "third_party/icu/source/common/unicode/ustring.h"
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc b/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc
index 25c82e0b..ab492e9 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/input_method/native_input_method_engine.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/guid.h"
 #include "base/scoped_observation.h"
 #include "base/strings/utf_string_conversions.h"
@@ -24,7 +25,6 @@
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine_unittest.cc b/chrome/browser/chromeos/input_method/native_input_method_engine_unittest.cc
index 183fd8e..b26f7ba 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine_unittest.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine_unittest.cc
@@ -4,11 +4,11 @@
 
 #include "chrome/browser/chromeos/input_method/native_input_method_engine.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "chrome/browser/chromeos/input_method/stub_input_method_engine_observer.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client_test_helper.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/ime/mock_input_channel.h"
 #include "chromeos/services/ime/public/mojom/input_engine.mojom.h"
 #include "content/public/test/browser_task_environment.h"
diff --git a/chrome/browser/chromeos/input_method/personal_info_suggester.cc b/chrome/browser/chromeos/input_method/personal_info_suggester.cc
index 24201b454..34c71b6 100644
--- a/chrome/browser/chromeos/input_method/personal_info_suggester.cc
+++ b/chrome/browser/chromeos/input_method/personal_info_suggester.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/input_method/personal_info_suggester.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
@@ -17,7 +18,6 @@
 #include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
diff --git a/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc b/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc
index 0adcc9b..e6ced98 100644
--- a/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc
+++ b/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/input_method/personal_info_suggester.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "base/guid.h"
 #include "base/strings/utf_string_conversions.h"
@@ -12,7 +13,6 @@
 #include "chrome/browser/chromeos/input_method/ui/suggestion_details.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
diff --git a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
index e78e384e..c44cc44 100644
--- a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
+++ b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -22,7 +23,6 @@
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/webui_url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/kerberos/kerberos_client.h"
 #include "chromeos/dbus/kerberos/kerberos_service.pb.h"
 #include "chromeos/network/onc/variable_expander.h"
diff --git a/chrome/browser/chromeos/login/app_mode/kiosk_browsertest.cc b/chrome/browser/chromeos/login/app_mode/kiosk_browsertest.cc
index 3c18df05..3508285 100644
--- a/chrome/browser/chromeos/login/app_mode/kiosk_browsertest.cc
+++ b/chrome/browser/chromeos/login/app_mode/kiosk_browsertest.cc
@@ -6,6 +6,7 @@
 #include <vector>
 
 #include "apps/test/app_window_waiter.h"
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/keyboard/keyboard_controller.h"
 #include "ash/public/cpp/keyboard/keyboard_switches.h"
@@ -87,7 +88,6 @@
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/cryptohome/cryptohome_client.h"
 #include "chromeos/disks/disk_mount_manager.h"
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index 1feed77..ac3b1e0 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -7,6 +7,7 @@
 #include <sys/socket.h>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
@@ -30,7 +31,6 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/constants/dbus_switches.h"
diff --git a/chrome/browser/chromeos/login/device_family_link_allowed_policy_browsertest.cc b/chrome/browser/chromeos/login/device_family_link_allowed_policy_browsertest.cc
index 37ec4e1..4849f8e 100644
--- a/chrome/browser/chromeos/login/device_family_link_allowed_policy_browsertest.cc
+++ b/chrome/browser/chromeos/login/device_family_link_allowed_policy_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/login_screen_test_api.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -16,7 +17,6 @@
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/login/auth/stub_authenticator_builder.h"
 #include "chromeos/login/auth/user_context.h"
 #include "chromeos/settings/cros_settings_names.h"
diff --git a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
index 7b82ed0..8ecd25f 100644
--- a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_ui_keyboard_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/constants/ash_features.h"
 #include "ash/public/cpp/login_screen_test_api.h"
 #include "base/command_line.h"
 #include "base/location.h"
@@ -30,7 +31,6 @@
 #include "chrome/browser/ui/ash/login_screen_shown_observer.h"
 #include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/login/auth/user_context.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
index c3ef7cb..825eca7 100644
--- a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
+++ b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
@@ -4,6 +4,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/ash_switches.h"
@@ -55,7 +56,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h"
 #include "chromeos/assistant/buildflags.h"
 #include "chromeos/attestation/attestation_flow_utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/update_engine_client.h"
 #include "chromeos/system/fake_statistics_provider.h"
diff --git a/chrome/browser/chromeos/login/quick_unlock/pin_backend.cc b/chrome/browser/chromeos/login/quick_unlock/pin_backend.cc
index e037b612..3a47cce 100644
--- a/chrome/browser/chromeos/login/quick_unlock/pin_backend.cc
+++ b/chrome/browser/chromeos/login/quick_unlock/pin_backend.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/login/quick_unlock/pin_backend.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/logging.h"
@@ -18,7 +19,6 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/account_id/account_id.h"
 #include "components/keep_alive_registry/keep_alive_types.h"
 #include "components/keep_alive_registry/scoped_keep_alive.h"
diff --git a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
index f88bc74..48a3ecb0 100644
--- a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
+++ b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/time/time.h"
@@ -15,7 +16,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
index c92a8d0..0c75ecc 100644
--- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc
+++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/login_screen_test_api.h"
 #include "base/base64.h"
 #include "base/bind.h"
@@ -71,7 +72,6 @@
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/attestation/mock_attestation_flow.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
 #include "chromeos/dbus/attestation/fake_attestation_client.h"
diff --git a/chrome/browser/chromeos/login/screens/family_link_notice_browsertest.cc b/chrome/browser/chromeos/login/screens/family_link_notice_browsertest.cc
index dae11650..9b360c5 100644
--- a/chrome/browser/chromeos/login/screens/family_link_notice_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/family_link_notice_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 #include "chrome/browser/chromeos/login/screens/family_link_notice_screen.h"
 
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/chromeos/login/oobe_screen.h"
 #include "chrome/browser/chromeos/login/test/fake_gaia_mixin.h"
 #include "chrome/browser/chromeos/login/test/js_checker.h"
@@ -18,7 +19,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/family_link_notice_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/login/auth/stub_authenticator_builder.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/chromeos/login/screens/family_link_notice_screen.cc b/chrome/browser/chromeos/login/screens/family_link_notice_screen.cc
index 8215cc4..8b85b12 100644
--- a/chrome/browser/chromeos/login/screens/family_link_notice_screen.cc
+++ b/chrome/browser/chromeos/login/screens/family_link_notice_screen.cc
@@ -4,11 +4,11 @@
 
 #include "chrome/browser/chromeos/login/screens/family_link_notice_screen.h"
 
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/chromeos/login/wizard_context.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/webui/chromeos/login/family_link_notice_screen_handler.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/user_manager/user_manager.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 
diff --git a/chrome/browser/chromeos/login/screens/gaia_screen.cc b/chrome/browser/chromeos/login/screens/gaia_screen.cc
index 46452f0..b941ad1 100644
--- a/chrome/browser/chromeos/login/screens/gaia_screen.cc
+++ b/chrome/browser/chromeos/login/screens/gaia_screen.cc
@@ -4,10 +4,10 @@
 
 #include "chrome/browser/chromeos/login/screens/gaia_screen.h"
 
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_context.h"
 #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/account_id/account_id.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
diff --git a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.cc b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.cc
index b7be7ed..b5d085a 100644
--- a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.cc
+++ b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <unordered_set>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/login_screen.h"
@@ -31,7 +32,6 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync_preferences/pref_service_syncable.h"
diff --git a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen_browsertest.cc
index 111cd00..f0c44a5 100644
--- a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen_browsertest.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/shelf_test_api.h"
@@ -39,7 +40,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/test/browser_test.h"
 #include "mojo/public/c/system/trap.h"
diff --git a/chrome/browser/chromeos/login/screens/parental_handoff_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/parental_handoff_screen_browsertest.cc
index 37299765..157f6ad 100644
--- a/chrome/browser/chromeos/login/screens/parental_handoff_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/parental_handoff_screen_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/auto_reset.h"
 #include "base/callback.h"
 #include "base/optional.h"
@@ -33,7 +34,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/account_id/account_id.h"
 #include "content/public/test/browser_test.h"
 
diff --git a/chrome/browser/chromeos/login/screens/pin_setup_screen.cc b/chrome/browser/chromeos/login/screens/pin_setup_screen.cc
index 288035e..82543d0 100644
--- a/chrome/browser/chromeos/login/screens/pin_setup_screen.cc
+++ b/chrome/browser/chromeos/login/screens/pin_setup_screen.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/tablet_mode.h"
 #include "base/check.h"
 #include "base/metrics/histogram_functions.h"
@@ -18,7 +19,6 @@
 #include "chrome/browser/chromeos/login/wizard_context.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/webui/chromeos/login/pin_setup_screen_handler.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/login/auth/user_context.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/login/screens/pin_setup_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/pin_setup_screen_browsertest.cc
index dfdd30b..2f176df 100644
--- a/chrome/browser/chromeos/login/screens/pin_setup_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/pin_setup_screen_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/login/screens/pin_setup_screen.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/test/shell_test_api.h"
 #include "base/bind.h"
 #include "base/run_loop.h"
@@ -20,7 +21,6 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/ui/webui/chromeos/login/pin_setup_screen_handler.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/cryptohome/cryptohome_client.h"
 #include "chromeos/dbus/cryptohome/fake_cryptohome_client.h"
 #include "chromeos/login/auth/stub_authenticator_builder.h"
diff --git a/chrome/browser/chromeos/login/screens/sync_consent_browsertest.cc b/chrome/browser/chromeos/login/screens/sync_consent_browsertest.cc
index 4e42e86..512f627 100644
--- a/chrome/browser/chromeos/login/screens/sync_consent_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/sync_consent_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/constants/ash_features.h"
 #include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/macros.h"
@@ -35,7 +36,6 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_profile_manager.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/login/screens/sync_consent_screen.cc b/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
index fe37e6401f..576305a 100644
--- a/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
+++ b/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/check.h"
 #include "base/metrics/histogram_functions.h"
@@ -19,7 +20,6 @@
 #include "chrome/browser/unified_consent/unified_consent_service_factory.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/webui_url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/consent_auditor/consent_auditor.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/login/screens/update_screen.cc b/chrome/browser/chromeos/login/screens/update_screen.cc
index e884f713..8f2d9f5 100644
--- a/chrome/browser/chromeos/login/screens/update_screen.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/i18n/number_formatting.h"
@@ -23,7 +24,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/update_screen_handler.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/network/network_state.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/strings/grit/ui_strings.h"
diff --git a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
index f4bb21a7..5b3aca3f 100644
--- a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
 #include "base/optional.h"
@@ -30,7 +31,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/update_screen_handler.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_update_engine_client.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
diff --git a/chrome/browser/chromeos/login/screens/user_creation_screen.cc b/chrome/browser/chromeos/login/screens/user_creation_screen.cc
index 986c0f9..0b61bb7 100644
--- a/chrome/browser/chromeos/login/screens/user_creation_screen.cc
+++ b/chrome/browser/chromeos/login/screens/user_creation_screen.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/login/screens/user_creation_screen.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/login_screen.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
@@ -12,7 +13,6 @@
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
 
diff --git a/chrome/browser/chromeos/login/screens/user_creation_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/user_creation_screen_browsertest.cc
index 0a9f34a..f1dd0bd 100644
--- a/chrome/browser/chromeos/login/screens/user_creation_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/user_creation_screen_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 #include "chrome/browser/chromeos/login/screens/user_creation_screen.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/login_screen_test_api.h"
 #include "chrome/browser/chromeos/login/enrollment/enrollment_screen_view.h"
 #include "chrome/browser/chromeos/login/oobe_screen.h"
@@ -20,7 +21,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/offline_login_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/test/browser_test.h"
 
 namespace chromeos {
diff --git a/chrome/browser/chromeos/login/screens/welcome_screen.cc b/chrome/browser/chromeos/login/screens/welcome_screen.cc
index f463d28..dffe229 100644
--- a/chrome/browser/chromeos/login/screens/welcome_screen.cc
+++ b/chrome/browser/chromeos/login/screens/welcome_screen.cc
@@ -7,6 +7,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/containers/contains.h"
@@ -33,7 +34,6 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/login/session/chrome_session_manager.cc b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
index 4eeeff8..bc4fe00a 100644
--- a/chrome/browser/chromeos/login/session/chrome_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/logging.h"
@@ -47,7 +48,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
diff --git a/chrome/browser/chromeos/login/session/user_session_initializer.cc b/chrome/browser/chromeos/login/session/user_session_initializer.cc
index 177476e..6396bb4b 100644
--- a/chrome/browser/chromeos/login/session/user_session_initializer.cc
+++ b/chrome/browser/chromeos/login/session/user_session_initializer.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/login/session/user_session_initializer.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
 #include "base/system/sys_info.h"
@@ -36,7 +37,6 @@
 #include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.h"
 #include "chrome/browser/ui/ash/media_client_impl.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/network/network_cert_loader.h"
 #include "chromeos/tpm/install_attributes.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 5bab4ff7..45ae5bfd 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -16,6 +16,7 @@
 
 #include "ash/components/account_manager/account_manager.h"
 #include "ash/components/account_manager/account_manager_factory.h"
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "base/base_paths.h"
 #include "base/bind.h"
@@ -105,7 +106,6 @@
 #include "chrome/common/logging_chrome.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/assistant/buildflags.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/cryptohome/cryptohome_client.h"
diff --git a/chrome/browser/chromeos/login/test/oobe_base_test.cc b/chrome/browser/chromeos/login/test/oobe_base_test.cc
index 3f47c42f..3c724ad4 100644
--- a/chrome/browser/chromeos/login/test/oobe_base_test.cc
+++ b/chrome/browser/chromeos/login/test/oobe_base_test.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/login/test/oobe_base_test.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -29,7 +30,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h"
 #include "chrome/browser/ui/webui/signin/signin_utils.h"
 #include "chrome/common/chrome_switches.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_update_engine_client.h"
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_common.cc b/chrome/browser/chromeos/login/ui/login_display_host_common.cc
index de1c08c..74ad45d 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_common.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_common.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/login/ui/login_display_host_common.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_types.h"
@@ -32,7 +33,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/locale_switch_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/keep_alive_registry/keep_alive_types.h"
 #include "content/public/browser/notification_service.h"
 #include "extensions/common/features/feature_session_type.h"
diff --git a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
index 924f20f..2819d76 100644
--- a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
+++ b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/login_accelerators.h"
 #include "ash/public/cpp/login_screen.h"
 #include "ash/public/cpp/login_screen_model.h"
@@ -24,7 +25,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/aura/window.h"
diff --git a/chrome/browser/chromeos/login/ui/user_adding_screen.cc b/chrome/browser/chromeos/login/ui/user_adding_screen.cc
index 3a228f4..c44e534 100644
--- a/chrome/browser/chromeos/login/ui/user_adding_screen.cc
+++ b/chrome/browser/chromeos/login/ui/user_adding_screen.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/memory/singleton.h"
 #include "base/metrics/histogram_functions.h"
@@ -15,7 +16,6 @@
 #include "chrome/browser/chromeos/login/ui/user_adding_screen_input_methods_controller.h"
 #include "chrome/browser/ui/ash/login_screen_client.h"
 #include "chrome/browser/ui/ash/wallpaper_controller_client.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/user_manager.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/chrome/browser/chromeos/login/ui/user_adding_screen_browsertest.cc b/chrome/browser/chromeos/login/ui/user_adding_screen_browsertest.cc
index 79280650..447a94e 100644
--- a/chrome/browser/chromeos/login/ui/user_adding_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/ui/user_adding_screen_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/constants/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/login_screen_test_api.h"
 #include "base/run_loop.h"
@@ -24,7 +25,6 @@
 #include "chrome/browser/ui/ash/login_screen_client.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/user_manager.h"
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.cc b/chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.cc
index 5f0cc306..9f4df9cf 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/users/avatar/user_image_manager.h"
@@ -12,7 +13,6 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/sync_preferences/pref_service_syncable.h"
diff --git a/chrome/browser/chromeos/login/version_info_updater.cc b/chrome/browser/chromeos/login/version_info_updater.cc
index f9912f36..edca02c 100644
--- a/chrome/browser/chromeos/login/version_info_updater.cc
+++ b/chrome/browser/chromeos/login/version_info_updater.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/feature_list.h"
@@ -21,7 +22,6 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/util/version_loader.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
diff --git a/chrome/browser/chromeos/login/webview_login_browsertest.cc b/chrome/browser/chromeos/login/webview_login_browsertest.cc
index 2bad78e..f83246a 100644
--- a/chrome/browser/chromeos/login/webview_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/webview_login_browsertest.cc
@@ -6,6 +6,7 @@
 #include <iterator>
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/login_screen_test_api.h"
 #include "base/bind.h"
 #include "base/callback.h"
@@ -62,7 +63,6 @@
 #include "chrome/browser/ui/webui/signin/signin_utils.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/dbus/tpm_manager/fake_tpm_manager_client.h"
diff --git a/chrome/browser/chromeos/phonehub/phone_hub_manager_factory.cc b/chrome/browser/chromeos/phonehub/phone_hub_manager_factory.cc
index a96ff7a..68ad494 100644
--- a/chrome/browser/chromeos/phonehub/phone_hub_manager_factory.cc
+++ b/chrome/browser/chromeos/phonehub/phone_hub_manager_factory.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/phonehub/phone_hub_manager_factory.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/system_tray.h"
 #include "chrome/browser/chromeos/device_sync/device_sync_client_factory.h"
 #include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h"
@@ -22,7 +23,6 @@
 #include "chromeos/components/phonehub/onboarding_ui_tracker_impl.h"
 #include "chromeos/components/phonehub/phone_hub_manager_impl.h"
 #include "chromeos/components/phonehub/user_action_recorder_impl.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/pref_registry/pref_registry_syncable.h"
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_manager_impl.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_manager_impl.cc
index b263f78..9a8a50cc 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_manager_impl.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_manager_impl.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/plugin_vm/plugin_vm_manager_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "chrome/app/vector_icons/vector_icons.h"
@@ -21,7 +22,6 @@
 #include "chrome/browser/ui/ash/launcher/shelf_spinner_item_controller.h"
 #include "chrome/browser/ui/simple_message_box.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/debug_daemon/debug_daemon_client.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
diff --git a/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler.cc b/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler.cc
index b67ecd8f..3333262 100644
--- a/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler.cc
+++ b/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/optional.h"
@@ -17,7 +18,6 @@
 #include "chrome/browser/chromeos/login/screens/reset_screen.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "chromeos/settings/cros_settings_provider.h"
diff --git a/chrome/browser/chromeos/policy/minimum_version_policy_handler.cc b/chrome/browser/chromeos/policy/minimum_version_policy_handler.cc
index 3a946758..1c2a00a 100644
--- a/chrome/browser/chromeos/policy/minimum_version_policy_handler.cc
+++ b/chrome/browser/chromeos/policy/minimum_version_policy_handler.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/system_tray.h"
 #include "base/bind.h"
 #include "base/logging.h"
@@ -26,7 +27,6 @@
 #include "chrome/browser/upgrade_detector/build_state.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/network/network_handler.h"
diff --git a/chrome/browser/chromeos/policy/minimum_version_policy_handler_browsertest.cc b/chrome/browser/chromeos/policy/minimum_version_policy_handler_browsertest.cc
index efd0e204..2f4b97c 100644
--- a/chrome/browser/chromeos/policy/minimum_version_policy_handler_browsertest.cc
+++ b/chrome/browser/chromeos/policy/minimum_version_policy_handler_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/login_screen_test_api.h"
 #include "ash/public/cpp/system_tray_test_api.h"
 #include "base/json/json_writer.h"
@@ -48,7 +49,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
diff --git a/chrome/browser/chromeos/policy/minimum_version_policy_handler_unittest.cc b/chrome/browser/chromeos/policy/minimum_version_policy_handler_unittest.cc
index 9b18805..8392af874 100644
--- a/chrome/browser/chromeos/policy/minimum_version_policy_handler_unittest.cc
+++ b/chrome/browser/chromeos/policy/minimum_version_policy_handler_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/policy/minimum_version_policy_handler.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
@@ -16,7 +17,6 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_update_engine_client.h"
 #include "chromeos/dbus/shill/shill_service_client.h"
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
index 706c26f..0104d9ef 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "base/bind.h"
 #include "base/logging.h"
@@ -18,7 +19,6 @@
 #include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/dbus/power_manager/backlight.pb.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc
index f61d450..2d34226 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc
@@ -8,6 +8,7 @@
 #include <numeric>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ptr_util.h"
@@ -26,7 +27,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/constants/chromeos_features.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "chromeos/dbus/power_manager/backlight.pb.h"
 #include "components/pref_registry/pref_registry_syncable.h"
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl.cc b/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl.cc
index edbefeb..c950f44 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl.cc
@@ -6,6 +6,7 @@
 
 #include <cmath>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/check_op.h"
 #include "base/memory/ptr_util.h"
@@ -15,7 +16,6 @@
 #include "base/numerics/ranges.h"
 #include "base/task/post_task.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/dbus/power_manager/backlight.pb.h"
 
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl_unittest.cc
index 242e677d..08892992 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl_unittest.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl_unittest.cc
@@ -4,13 +4,13 @@
 
 #include "chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/memory/ptr_util.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/threading/sequenced_task_runner_handle.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "chromeos/dbus/power_manager/backlight.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.cc b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.cc
index 37cdbd6..e51348a9 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.cc
@@ -8,6 +8,7 @@
 #include <cmath>
 #include <limits>
 
+#include "ash/constants/ash_features.h"
 #include "base/logging.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
@@ -15,7 +16,6 @@
 #include "base/numerics/ranges.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
-#include "chromeos/constants/chromeos_features.h"
 
 namespace chromeos {
 namespace power {
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer_unittest.cc
index 7a50aba5..ec3227b 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer_unittest.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer_unittest.cc
@@ -4,13 +4,13 @@
 
 #include "chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/monotone_cubic_spline.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/model_config_loader_impl.cc b/chrome/browser/chromeos/power/auto_screen_brightness/model_config_loader_impl.cc
index 26f6b18..b355c43 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/model_config_loader_impl.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/model_config_loader_impl.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/check_op.h"
 #include "base/files/file_util.h"
@@ -20,7 +21,6 @@
 #include "base/task/thread_pool.h"
 #include "base/task_runner_util.h"
 #include "base/values.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace chromeos {
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/model_config_loader_impl_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/model_config_loader_impl_unittest.cc
index f8a20ef..2a5bf779 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/model_config_loader_impl_unittest.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/model_config_loader_impl_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "chrome/browser/chromeos/power/auto_screen_brightness/model_config_loader_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
@@ -17,7 +18,6 @@
 #include "base/test/task_environment.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/threading/sequenced_task_runner_handle.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc
index 9831bfc..39b794f 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc
@@ -6,6 +6,7 @@
 
 #include <cmath>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -24,7 +25,6 @@
 #include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/events/event.h"
 #include "ui/events/event_constants.h"
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc
index c03680e..c2fb3008 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/important_file_writer.h"
@@ -22,7 +23,6 @@
 #include "chrome/browser/chromeos/power/auto_screen_brightness/trainer.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/user_activity/user_activity_detector.h"
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/builtin_worker.cc b/chrome/browser/chromeos/power/ml/smart_dim/builtin_worker.cc
index cdfd2ec..d22a832 100644
--- a/chrome/browser/chromeos/power/ml/smart_dim/builtin_worker.cc
+++ b/chrome/browser/chromeos/power/ml/smart_dim/builtin_worker.cc
@@ -4,12 +4,12 @@
 
 #include "chrome/browser/chromeos/power/ml/smart_dim/builtin_worker.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/memory/ref_counted_memory.h"
 #include "chrome/browser/chromeos/power/ml/smart_dim/ml_agent_util.h"
 #include "chrome/grit/browser_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
 #include "components/assist_ranker/proto/example_preprocessor.pb.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/ml_agent.cc b/chrome/browser/chromeos/power/ml/smart_dim/ml_agent.cc
index 41d68c9..b1afd60 100644
--- a/chrome/browser/chromeos/power/ml/smart_dim/ml_agent.cc
+++ b/chrome/browser/chromeos/power/ml/smart_dim/ml_agent.cc
@@ -7,12 +7,12 @@
 #include <cstddef>
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/callback_forward.h"
 #include "base/containers/flat_map.h"
 #include "base/metrics/field_trial_params.h"
 #include "chrome/browser/chromeos/power/ml/smart_dim/metrics.h"
 #include "chrome/browser/chromeos/power/ml/user_activity_ukm_logger_helpers.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/machine_learning/public/mojom/graph_executor.mojom.h"
 #include "chromeos/services/machine_learning/public/mojom/model.mojom.h"
 #include "chromeos/services/machine_learning/public/mojom/tensor.mojom.h"
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/ml_agent_unittest.cc b/chrome/browser/chromeos/power/ml/smart_dim/ml_agent_unittest.cc
index f99c126..8358569 100644
--- a/chrome/browser/chromeos/power/ml/smart_dim/ml_agent_unittest.cc
+++ b/chrome/browser/chromeos/power/ml/smart_dim/ml_agent_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/containers/flat_map.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -13,7 +14,6 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/machine_learning/machine_learning_client.h"
 #include "chromeos/services/machine_learning/public/cpp/fake_service_connection.h"
 #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/ml_service_client.cc b/chrome/browser/chromeos/power/ml/smart_dim/ml_service_client.cc
index 2337d11..5fd7f9b 100644
--- a/chrome/browser/chromeos/power/ml/smart_dim/ml_service_client.cc
+++ b/chrome/browser/chromeos/power/ml/smart_dim/ml_service_client.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/containers/flat_map.h"
 #include "base/feature_list.h"
@@ -14,7 +15,6 @@
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/power/ml/smart_dim/metrics.h"
 #include "chrome/browser/chromeos/power/ml/smart_dim/model_impl.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
 #include "chromeos/services/machine_learning/public/mojom/graph_executor.mojom.h"
 #include "chromeos/services/machine_learning/public/mojom/model.mojom.h"
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager.cc b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
index 406dfcb5..8e4f826f 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_manager.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
@@ -6,6 +6,7 @@
 
 #include <cmath>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "base/bind.h"
 #include "base/metrics/field_trial_params.h"
@@ -20,7 +21,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/devicetype.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc b/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc
index 8ebc286..7d7e4f0 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/cancelable_callback.h"
 #include "base/sequenced_task_runner.h"
@@ -28,7 +29,6 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/test_browser_window_aura.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "chromeos/dbus/power_manager/idle.pb.h"
 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 332bd0f..20c85073 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -7,6 +7,7 @@
 #include <limits>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/ash_interfaces.h"
 #include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_pref_names.h"
@@ -45,7 +46,6 @@
 #include "chrome/browser/ui/ash/system_tray_client.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/settings/cros_settings_names.h"
diff --git a/chrome/browser/chromeos/preferences_chromeos_browsertest.cc b/chrome/browser/chromeos/preferences_chromeos_browsertest.cc
index 6d9a3c3..40fa896 100644
--- a/chrome/browser/chromeos/preferences_chromeos_browsertest.cc
+++ b/chrome/browser/chromeos/preferences_chromeos_browsertest.cc
@@ -5,6 +5,7 @@
 #include <stddef.h>
 #include <sys/types.h>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "base/command_line.h"
 #include "base/stl_util.h"
@@ -20,7 +21,6 @@
 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
 #include "chrome/browser/chromeos/system/fake_input_device_settings.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/feedback/tracing_manager.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
diff --git a/chrome/browser/chromeos/preferences_unittest.cc b/chrome/browser/chromeos/preferences_unittest.cc
index dcd6aa4..7d69037 100644
--- a/chrome/browser/chromeos/preferences_unittest.cc
+++ b/chrome/browser/chromeos/preferences_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/json/json_string_value_serializer.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
@@ -20,7 +21,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/constants/chromeos_features.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/prefs/pref_member.h"
 #include "components/sync/base/model_type.h"
diff --git a/chrome/browser/chromeos/printing/print_servers_manager_unittest.cc b/chrome/browser/chromeos/printing/print_servers_manager_unittest.cc
index e9d59e93..43be6077 100644
--- a/chrome/browser/chromeos/printing/print_servers_manager_unittest.cc
+++ b/chrome/browser/chromeos/printing/print_servers_manager_unittest.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
 #include "base/sequenced_task_runner.h"
@@ -18,7 +19,6 @@
 #include "chrome/browser/chromeos/printing/server_printers_provider.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "content/public/test/browser_task_environment.h"
diff --git a/chrome/browser/chromeos/printing/print_servers_policy_provider.cc b/chrome/browser/chromeos/printing/print_servers_policy_provider.cc
index 1b2c42f..932eb8d 100644
--- a/chrome/browser/chromeos/printing/print_servers_policy_provider.cc
+++ b/chrome/browser/chromeos/printing/print_servers_policy_provider.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/printing/print_servers_policy_provider.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "chrome/browser/browser_process.h"
@@ -11,7 +12,6 @@
 #include "chrome/browser/chromeos/printing/print_servers_provider_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 
 namespace chromeos {
 
diff --git a/chrome/browser/chromeos/release_notes/release_notes_notification_unittest.cc b/chrome/browser/chromeos/release_notes/release_notes_notification_unittest.cc
index 2402563..d47f565 100644
--- a/chrome/browser/chromeos/release_notes/release_notes_notification_unittest.cc
+++ b/chrome/browser/chromeos/release_notes/release_notes_notification_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/release_notes/release_notes_notification.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
@@ -16,7 +17,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/constants/chromeos_features.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/version_info/version_info.h"
 #include "ui/chromeos/devicetype_utils.h"
diff --git a/chrome/browser/chromeos/release_notes/release_notes_storage.cc b/chrome/browser/chromeos/release_notes/release_notes_storage.cc
index c5434488..74b0e31 100644
--- a/chrome/browser/chromeos/release_notes/release_notes_storage.cc
+++ b/chrome/browser/chromeos/release_notes/release_notes_storage.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/release_notes/release_notes_storage.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/command_line.h"
 #include "base/version.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -13,7 +14,6 @@
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/release_notes/release_notes_storage_unittest.cc b/chrome/browser/chromeos/release_notes/release_notes_storage_unittest.cc
index 785c8cb..706d73f 100644
--- a/chrome/browser/chromeos/release_notes/release_notes_storage_unittest.cc
+++ b/chrome/browser/chromeos/release_notes/release_notes_storage_unittest.cc
@@ -6,13 +6,13 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/version.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "components/account_id/account_id.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/settings/cros_settings_unittest.cc b/chrome/browser/chromeos/settings/cros_settings_unittest.cc
index 50202a0..e4c25a5 100644
--- a/chrome/browser/chromeos/settings/cros_settings_unittest.cc
+++ b/chrome/browser/chromeos/settings/cros_settings_unittest.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
@@ -21,7 +22,6 @@
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "chromeos/tpm/stub_install_attributes.h"
 #include "components/ownership/mock_owner_key_util.h"
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc
index b7506fa..fefda20 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider.cc
@@ -10,6 +10,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
@@ -30,7 +31,6 @@
 #include "chrome/browser/chromeos/settings/device_settings_cache.h"
 #include "chrome/browser/chromeos/settings/stats_reporting_controller.h"
 #include "chrome/browser/chromeos/tpm_firmware_update.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/cryptohome/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
diff --git a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
index cc0a26f6..f4c2280 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
@@ -26,7 +27,6 @@
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "chromeos/tpm/stub_install_attributes.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
diff --git a/chrome/browser/chromeos/sync/app_settings_model_type_controller.cc b/chrome/browser/chromeos/sync/app_settings_model_type_controller.cc
index 334c1ae..a594bdf 100644
--- a/chrome/browser/chromeos/sync/app_settings_model_type_controller.cc
+++ b/chrome/browser/chromeos/sync/app_settings_model_type_controller.cc
@@ -6,8 +6,8 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/base/pref_names.h"
diff --git a/chrome/browser/chromeos/sync/apps_model_type_controller.cc b/chrome/browser/chromeos/sync/apps_model_type_controller.cc
index d746d0c..c13d759b 100644
--- a/chrome/browser/chromeos/sync/apps_model_type_controller.cc
+++ b/chrome/browser/chromeos/sync/apps_model_type_controller.cc
@@ -6,11 +6,11 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/check.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/chromeos/sync/os_sync_model_type_controller.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/model/client_tag_based_model_type_processor.h"
 #include "components/sync/model/forwarding_model_type_controller_delegate.h"
diff --git a/chrome/browser/chromeos/sync/os_sync_model_type_controller.cc b/chrome/browser/chromeos/sync/os_sync_model_type_controller.cc
index cc13993c..82760319 100644
--- a/chrome/browser/chromeos/sync/os_sync_model_type_controller.cc
+++ b/chrome/browser/chromeos/sync/os_sync_model_type_controller.cc
@@ -7,9 +7,9 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/base/pref_names.h"
diff --git a/chrome/browser/chromeos/sync/os_sync_util.cc b/chrome/browser/chromeos/sync/os_sync_util.cc
index d16746edb..52fe4a4 100644
--- a/chrome/browser/chromeos/sync/os_sync_util.cc
+++ b/chrome/browser/chromeos/sync/os_sync_util.cc
@@ -4,9 +4,9 @@
 
 #include "chrome/browser/chromeos/sync/os_sync_util.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/ui/webui/settings/chromeos/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/pref_names.h"
diff --git a/chrome/browser/chromeos/sync/os_sync_util_unittest.cc b/chrome/browser/chromeos/sync/os_sync_util_unittest.cc
index 949b3c7..90d5f83 100644
--- a/chrome/browser/chromeos/sync/os_sync_util_unittest.cc
+++ b/chrome/browser/chromeos/sync/os_sync_util_unittest.cc
@@ -4,11 +4,11 @@
 
 #include "chrome/browser/chromeos/sync/os_sync_util.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h"
 #include "chrome/browser/ui/webui/settings/chromeos/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/base/sync_prefs.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
diff --git a/chrome/browser/chromeos/sync/os_syncable_service_model_type_controller.cc b/chrome/browser/chromeos/sync/os_syncable_service_model_type_controller.cc
index d707ed6..43cfb0c1 100644
--- a/chrome/browser/chromeos/sync/os_syncable_service_model_type_controller.cc
+++ b/chrome/browser/chromeos/sync/os_syncable_service_model_type_controller.cc
@@ -7,10 +7,10 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/memory/ptr_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/base/pref_names.h"
diff --git a/chrome/browser/chromeos/sync/split_settings_sync_field_trial.cc b/chrome/browser/chromeos/sync/split_settings_sync_field_trial.cc
index 128de71..aa8269f6 100644
--- a/chrome/browser/chromeos/sync/split_settings_sync_field_trial.cc
+++ b/chrome/browser/chromeos/sync/split_settings_sync_field_trial.cc
@@ -4,11 +4,11 @@
 
 #include "chrome/browser/chromeos/sync/split_settings_sync_field_trial.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/metrics/field_trial.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/common/channel_info.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/variations/variations_associated_data.h"
diff --git a/chrome/browser/chromeos/sync/turn_sync_on_helper.cc b/chrome/browser/chromeos/sync/turn_sync_on_helper.cc
index c6cbd66..71baba3 100644
--- a/chrome/browser/chromeos/sync/turn_sync_on_helper.cc
+++ b/chrome/browser/chromeos/sync/turn_sync_on_helper.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
@@ -19,7 +20,6 @@
 #include "chrome/browser/unified_consent/unified_consent_service_factory.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/webui_url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/signin/public/identity_manager/consent_level.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
diff --git a/chrome/browser/chromeos/sync/turn_sync_on_helper_unittest.cc b/chrome/browser/chromeos/sync/turn_sync_on_helper_unittest.cc
index edfa6960..7558073 100644
--- a/chrome/browser/chromeos/sync/turn_sync_on_helper_unittest.cc
+++ b/chrome/browser/chromeos/sync/turn_sync_on_helper_unittest.cc
@@ -4,13 +4,13 @@
 
 #include "chrome/browser/chromeos/sync/turn_sync_on_helper.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/signin/public/identity_manager/consent_level.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/driver/sync_user_settings.h"
diff --git a/chrome/browser/chromeos/tether/tether_service_unittest.cc b/chrome/browser/chromeos/tether/tether_service_unittest.cc
index 0f0f2d3..f0b7e2fb 100644
--- a/chrome/browser/chromeos/tether/tether_service_unittest.cc
+++ b/chrome/browser/chromeos/tether/tether_service_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
@@ -27,7 +28,6 @@
 #include "chromeos/components/tether/fake_tether_host_fetcher.h"
 #include "chromeos/components/tether/tether_component_impl.h"
 #include "chromeos/components/tether/tether_host_fetcher_impl.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector.cc b/chrome/browser/chromeos/usb/cros_usb_detector.cc
index dba9576..5ced621 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector.cc
+++ b/chrome/browser/chromeos/usb/cros_usb_detector.cc
@@ -9,6 +9,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/notification_utils.h"
 #include "base/callback_helpers.h"
 #include "base/files/file_util.h"
@@ -26,7 +27,6 @@
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/concierge_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/disks/disk.h"
diff --git a/chrome/browser/chromeos/web_applications/camera_app_integration_browsertest.cc b/chrome/browser/chromeos/web_applications/camera_app_integration_browsertest.cc
index 14e3420..6833699 100644
--- a/chrome/browser/chromeos/web_applications/camera_app_integration_browsertest.cc
+++ b/chrome/browser/chromeos/web_applications/camera_app_integration_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/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/web_applications/system_web_app_integration_test.h"
 #include "chrome/browser/ui/browser.h"
@@ -9,7 +10,6 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/web_applications/system_web_app_manager_browsertest.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_navigation_observer.h"
 
diff --git a/chrome/browser/chromeos/web_applications/chrome_help_app_ui_delegate.cc b/chrome/browser/chromeos/web_applications/chrome_help_app_ui_delegate.cc
index 78bf38d..d792aec 100644
--- a/chrome/browser/chromeos/web_applications/chrome_help_app_ui_delegate.cc
+++ b/chrome/browser/chromeos/web_applications/chrome_help_app_ui_delegate.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/assistant/assistant_state.h"
 #include "ash/public/cpp/tablet_mode.h"
 #include "base/system/sys_info.h"
@@ -24,7 +25,6 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/components/help_app_ui/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
 #include "chromeos/system/statistics_provider.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.cc b/chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.cc
index 3bcf980..6e91cce 100644
--- a/chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.cc
+++ b/chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.cc
@@ -4,12 +4,12 @@
 
 #include "chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.h"
 
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/common/channel_info.h"
 #include "chromeos/components/media_app_ui/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/version_info/channel.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/chromeos/web_applications/diagnostics_app_integration_browsertest.cc b/chrome/browser/chromeos/web_applications/diagnostics_app_integration_browsertest.cc
index 7ad236b9..53d369ec 100644
--- a/chrome/browser/chromeos/web_applications/diagnostics_app_integration_browsertest.cc
+++ b/chrome/browser/chromeos/web_applications/diagnostics_app_integration_browsertest.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/web_applications/system_web_app_integration_test.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chromeos/components/diagnostics_ui/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/chromeos/web_applications/eche_app_integration_browsertest.cc b/chrome/browser/chromeos/web_applications/eche_app_integration_browsertest.cc
index 77a1e03..1e0c223a 100644
--- a/chrome/browser/chromeos/web_applications/eche_app_integration_browsertest.cc
+++ b/chrome/browser/chromeos/web_applications/eche_app_integration_browsertest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/web_applications/system_web_app_integration_test.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chromeos/components/eche_app_ui/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/display/screen.h"
diff --git a/chrome/browser/chromeos/web_applications/help_app_integration_browsertest.cc b/chrome/browser/chromeos/web_applications/help_app_integration_browsertest.cc
index 41724570..f85761e 100644
--- a/chrome/browser/chromeos/web_applications/help_app_integration_browsertest.cc
+++ b/chrome/browser/chromeos/web_applications/help_app_integration_browsertest.cc
@@ -5,6 +5,7 @@
 #include <string>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/metrics/user_action_tester.h"
 #include "base/test/scoped_feature_list.h"
@@ -32,7 +33,6 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "chromeos/components/help_app_ui/url_constants.h"
 #include "chromeos/components/web_applications/test/sandboxed_web_ui_test_base.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/user_manager/user_names.h"
 #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/chromeos/web_applications/media_app_integration_browsertest.cc b/chrome/browser/chromeos/web_applications/media_app_integration_browsertest.cc
index f3048d7..9de1ed4 100644
--- a/chrome/browser/chromeos/web_applications/media_app_integration_browsertest.cc
+++ b/chrome/browser/chromeos/web_applications/media_app_integration_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/constants/ash_features.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
@@ -24,7 +25,6 @@
 #include "chromeos/components/media_app_ui/buildflags.h"
 #include "chromeos/components/media_app_ui/test/media_app_ui_browsertest.h"
 #include "chromeos/components/media_app_ui/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/crash/content/browser/error_reporting/mock_crash_endpoint.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_utils.h"
diff --git a/chrome/browser/chromeos/web_applications/scanning_app_integration_browsertest.cc b/chrome/browser/chromeos/web_applications/scanning_app_integration_browsertest.cc
index 7a99e3a..a78f3e5 100644
--- a/chrome/browser/chromeos/web_applications/scanning_app_integration_browsertest.cc
+++ b/chrome/browser/chromeos/web_applications/scanning_app_integration_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/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.h"
@@ -10,7 +11,6 @@
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/components/scanning/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/policy/core/common/policy_pref_names.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/strings/grit/components_strings.h"
diff --git a/chrome/browser/chromeos/web_applications/telemetry_extension_integration_browsertest.cc b/chrome/browser/chromeos/web_applications/telemetry_extension_integration_browsertest.cc
index 8a33799..40d3ab1 100644
--- a/chrome/browser/chromeos/web_applications/telemetry_extension_integration_browsertest.cc
+++ b/chrome/browser/chromeos/web_applications/telemetry_extension_integration_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
@@ -14,7 +15,6 @@
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/common/chrome_paths.h"
 #include "chromeos/components/telemetry_extension_ui/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/component_updater/smart_dim_component_installer.cc b/chrome/browser/component_updater/smart_dim_component_installer.cc
index dbb315c0..a22abe1 100644
--- a/chrome/browser/component_updater/smart_dim_component_installer.cc
+++ b/chrome/browser/component_updater/smart_dim_component_installer.cc
@@ -7,6 +7,7 @@
 #include <cstddef>
 #include <tuple>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
@@ -20,7 +21,6 @@
 #include "base/version.h"
 #include "chrome/browser/chromeos/power/ml/smart_dim/metrics.h"
 #include "chrome/browser/chromeos/power/ml/smart_dim/ml_agent.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/component_updater/component_updater_service.h"
 #include "content/public/browser/browser_thread.h"
 
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
index 1dde9a9..8272e455 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
@@ -33,7 +32,6 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
 #include "components/data_reduction_proxy/core/common/uma_util.h"
-#include "components/data_reduction_proxy/proto/client_config.pb.h"
 #include "components/metrics/content/subprocess_metrics_provider.h"
 #include "components/page_load_metrics/browser/page_load_metrics_test_waiter.h"
 #include "components/prefs/pref_service.h"
@@ -72,10 +70,8 @@
 using testing::HasSubstr;
 using testing::Not;
 
-constexpr char kSessionKey[] = "TheSessionKeyYay!";
 constexpr char kMockHost[] = "mock.host";
 constexpr char kDummyBody[] = "dummy";
-constexpr char kPrimaryProxyResponse[] = "primary";
 
 std::unique_ptr<net::test_server::HttpResponse> BasicResponse(
     const std::string& content,
@@ -100,33 +96,6 @@
       net::NetworkChangeNotifier::ConnectionType(type));
 }
 
-ClientConfig CreateConfigForServer(const net::EmbeddedTestServer& server) {
-  net::HostPortPair host_port_pair = server.host_port_pair();
-  return CreateClientConfig(kSessionKey, 1000, 0);
-}
-
-ClientConfig CreateEmptyConfig() {
-  return CreateClientConfig(kSessionKey, 1000, 0);
-}
-
-class TestSettingsObserver : public DataReductionProxySettingsObserver {
- public:
-  TestSettingsObserver() = default;
-  ~TestSettingsObserver() = default;
-
-  void OnPrefetchProxyHostsChanged(
-      const std::vector<GURL>& prefetch_proxies) override {
-    prefetch_proxies_ = prefetch_proxies;
-  }
-
-  const std::vector<GURL>& prefetch_proxies() const {
-    return prefetch_proxies_;
-  }
-
- private:
-  std::vector<GURL> prefetch_proxies_;
-};
-
 }  // namespace
 
 #if defined(OS_WIN) || defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH)
@@ -140,13 +109,6 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitchASCII(
         network::switches::kForceEffectiveConnectionType, "4G");
-
-    config_server_.RegisterRequestHandler(base::BindRepeating(
-        &DataReductionProxyBrowsertestBase::GetConfigResponse,
-        base::Unretained(this)));
-    ASSERT_TRUE(config_server_.Start());
-    command_line->AppendSwitchASCII(switches::kDataReductionProxyConfigURL,
-                                    config_server_.base_url().spec());
   }
 
   void SetUp() override { InProcessBrowserTest::SetUp(); }
@@ -157,14 +119,10 @@
         std::make_unique<net::test_server::ControllableHttpResponse>(
             embedded_test_server(), "/favicon.ico");
     ASSERT_TRUE(embedded_test_server()->Start());
-    // Set a default proxy config if one isn't set yet.
-    if (!config_.has_proxy_config())
-      SetConfig(CreateConfigForServer(*embedded_test_server()));
 
     host_resolver()->AddRule(kMockHost, "127.0.0.1");
 
     EnableDataSaver(true);
-    WaitForConfig();
   }
 
  protected:
@@ -195,47 +153,6 @@
     return base_url.Resolve(relative_url);
   }
 
-  void SetConfig(const ClientConfig& config) {
-    config_ = config;
-    // Config is not fetched if the lite page
-    // redirect previews are not enabled. So, return early.
-    if (!params::ForceEnableClientConfigServiceForAllDataSaverUsers()) {
-      return;
-    }
-  }
-
-  void RetryForHistogramUntilCountReached(
-      base::HistogramTester* histogram_tester,
-      const std::string& histogram_name,
-      size_t count) {
-    while (true) {
-      base::ThreadPoolInstance::Get()->FlushForTesting();
-      base::RunLoop().RunUntilIdle();
-
-      content::FetchHistogramsFromChildProcesses();
-      metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
-
-      const std::vector<base::Bucket> buckets =
-          histogram_tester->GetAllSamples(histogram_name);
-      size_t total_count = 0;
-      for (const auto& bucket : buckets) {
-        total_count += bucket.count;
-      }
-      if (total_count >= count) {
-        break;
-      }
-    }
-  }
-
-  void WaitForConfig() {
-    if (!params::ForceEnableClientConfigServiceForAllDataSaverUsers()) {
-      return;
-    }
-
-    base::HistogramTester histogram_tester;
-    RetryForHistogramUntilCountReached(
-        &histogram_tester, "DataReductionProxy.Settings.ConfigReceived", 1);
-  }
 
   std::string expect_exp_value_in_request_header_;
 
@@ -244,21 +161,6 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 
  private:
-  // Called when |config_server_| receives a request for config fetch.
-  std::unique_ptr<net::test_server::HttpResponse> GetConfigResponse(
-      const net::test_server::HttpRequest& request) {
-    // Config should be fetched only when lite page
-    // redirect previews are enabled.
-    EXPECT_TRUE(params::ForceEnableClientConfigServiceForAllDataSaverUsers());
-
-    auto response = std::make_unique<net::test_server::BasicHttpResponse>();
-    response->set_content(config_.SerializeAsString());
-    response->set_content_type("text/plain");
-    return response;
-  }
-
-  ClientConfig config_;
-  net::EmbeddedTestServer config_server_;
   std::unique_ptr<net::test_server::ControllableHttpResponse> favicon_catcher_;
 };
 
@@ -269,273 +171,6 @@
   }
 };
 
-IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest, UpdateConfig) {
-  net::EmbeddedTestServer original_server;
-  original_server.RegisterRequestHandler(
-      base::BindRepeating(&BasicResponse, kDummyBody));
-  ASSERT_TRUE(original_server.Start());
-
-  SetConfig(CreateConfigForServer(original_server));
-  // A network change forces the config to be fetched.
-  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
-  WaitForConfig();
-
-  ui_test_utils::NavigateToURL(
-      browser(),
-      GetURLWithMockHost(original_server, "/echoheader?Chrome-Proxy"));
-
-  EXPECT_EQ(GetBody(), kDummyBody);
-}
-
-IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest,
-                       UpdatePrefetchProxyConfig) {
-  TestSettingsObserver observer;
-  DataReductionProxySettings* settings =
-      DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
-          browser()->profile());
-  settings->AddDataReductionProxySettingsObserver(&observer);
-
-  net::EmbeddedTestServer original_server;
-  original_server.RegisterRequestHandler(
-      base::BindRepeating(&BasicResponse, kDummyBody));
-  ASSERT_TRUE(original_server.Start());
-
-  ClientConfig config = CreateConfigForServer(original_server);
-
-  PrefetchProxyConfig_Proxy* valid_secure_proxy =
-      config.mutable_prefetch_proxy_config()->add_proxy_list();
-  valid_secure_proxy->set_type(PrefetchProxyConfig_Proxy_Type_CONNECT);
-  valid_secure_proxy->set_host("prefetch-proxy.com");
-  valid_secure_proxy->set_port(443);
-  valid_secure_proxy->set_scheme(PrefetchProxyConfig_Proxy_Scheme_HTTPS);
-
-  PrefetchProxyConfig_Proxy* non_connect_proxy =
-      config.mutable_prefetch_proxy_config()->add_proxy_list();
-  non_connect_proxy->set_type(PrefetchProxyConfig_Proxy_Type_UNSPECIFIED_TYPE);
-  non_connect_proxy->set_host("prefetch-proxy.com");
-  non_connect_proxy->set_port(443);
-  non_connect_proxy->set_scheme(PrefetchProxyConfig_Proxy_Scheme_HTTPS);
-
-  PrefetchProxyConfig_Proxy* unknown_scheme_proxy =
-      config.mutable_prefetch_proxy_config()->add_proxy_list();
-  unknown_scheme_proxy->set_type(PrefetchProxyConfig_Proxy_Type_CONNECT);
-  unknown_scheme_proxy->set_host("prefetch-proxy.com");
-  unknown_scheme_proxy->set_port(443);
-  unknown_scheme_proxy->set_scheme(
-      PrefetchProxyConfig_Proxy_Scheme_UNSPECIFIED_SCHEME);
-
-  PrefetchProxyConfig_Proxy* invalid_host =
-      config.mutable_prefetch_proxy_config()->add_proxy_list();
-  invalid_host->set_type(PrefetchProxyConfig_Proxy_Type_CONNECT);
-  invalid_host->set_host(std::string());
-  invalid_host->set_port(443);
-  invalid_host->set_scheme(PrefetchProxyConfig_Proxy_Scheme_HTTPS);
-
-  PrefetchProxyConfig_Proxy* insecure_proxy =
-      config.mutable_prefetch_proxy_config()->add_proxy_list();
-  insecure_proxy->set_type(PrefetchProxyConfig_Proxy_Type_CONNECT);
-  insecure_proxy->set_host("insecure-prefetch-proxy.com");
-  insecure_proxy->set_port(80);
-  insecure_proxy->set_scheme(PrefetchProxyConfig_Proxy_Scheme_HTTP);
-
-  SetConfig(config);
-
-  // A network change forces the config to be fetched.
-  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
-  WaitForConfig();
-
-  std::vector<GURL> want_hosts = {
-      GURL("https://prefetch-proxy.com:443/"),
-  };
-  EXPECT_EQ(want_hosts, settings->GetPrefetchProxies());
-  EXPECT_EQ(want_hosts, observer.prefetch_proxies());
-}
-
-IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest,
-                       UpdatePrefetchProxyConfig_Insecure) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      "allow-insecure-prefetch-proxy-for-testing");
-
-  TestSettingsObserver observer;
-  DataReductionProxySettings* settings =
-      DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
-          browser()->profile());
-  settings->AddDataReductionProxySettingsObserver(&observer);
-
-  net::EmbeddedTestServer original_server;
-  original_server.RegisterRequestHandler(
-      base::BindRepeating(&BasicResponse, kPrimaryProxyResponse));
-  ASSERT_TRUE(original_server.Start());
-
-  ClientConfig config = CreateConfigForServer(original_server);
-
-  PrefetchProxyConfig_Proxy* valid_secure_proxy =
-      config.mutable_prefetch_proxy_config()->add_proxy_list();
-  valid_secure_proxy->set_type(PrefetchProxyConfig_Proxy_Type_CONNECT);
-  valid_secure_proxy->set_host("prefetch-proxy.com");
-  valid_secure_proxy->set_port(443);
-  valid_secure_proxy->set_scheme(PrefetchProxyConfig_Proxy_Scheme_HTTPS);
-
-  PrefetchProxyConfig_Proxy* valid_insecure_proxy =
-      config.mutable_prefetch_proxy_config()->add_proxy_list();
-  valid_insecure_proxy->set_type(PrefetchProxyConfig_Proxy_Type_CONNECT);
-  valid_insecure_proxy->set_host("insecure-prefetch-proxy.com");
-  valid_insecure_proxy->set_port(80);
-  valid_insecure_proxy->set_scheme(PrefetchProxyConfig_Proxy_Scheme_HTTP);
-
-  SetConfig(config);
-
-  // A network change forces the config to be fetched.
-  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
-  WaitForConfig();
-
-  std::vector<GURL> want_hosts = {
-      GURL("https://prefetch-proxy.com:443/"),
-      GURL("http://insecure-prefetch-proxy.com/"),
-  };
-  EXPECT_EQ(want_hosts, settings->GetPrefetchProxies());
-  EXPECT_EQ(want_hosts, observer.prefetch_proxies());
-}
-
-IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest,
-                       UpdatePrefetchProxyConfig_CmdLineOverride_Valid) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      "prefetch-proxy-override-proxy-hosts",
-      " ,NotValid, https://override-proxy.com/  ");
-
-  TestSettingsObserver observer;
-  DataReductionProxySettings* settings =
-      DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
-          browser()->profile());
-  settings->AddDataReductionProxySettingsObserver(&observer);
-
-  net::EmbeddedTestServer original_server;
-  original_server.RegisterRequestHandler(
-      base::BindRepeating(&BasicResponse, kPrimaryProxyResponse));
-  ASSERT_TRUE(original_server.Start());
-
-  ClientConfig config = CreateConfigForServer(original_server);
-
-  PrefetchProxyConfig_Proxy* valid_secure_proxy =
-      config.mutable_prefetch_proxy_config()->add_proxy_list();
-  valid_secure_proxy->set_type(PrefetchProxyConfig_Proxy_Type_CONNECT);
-  valid_secure_proxy->set_host("prefetch-proxy.com");
-  valid_secure_proxy->set_port(443);
-  valid_secure_proxy->set_scheme(PrefetchProxyConfig_Proxy_Scheme_HTTPS);
-
-  PrefetchProxyConfig_Proxy* valid_insecure_proxy =
-      config.mutable_prefetch_proxy_config()->add_proxy_list();
-  valid_insecure_proxy->set_type(PrefetchProxyConfig_Proxy_Type_CONNECT);
-  valid_insecure_proxy->set_host("insecure-prefetch-proxy.com");
-  valid_insecure_proxy->set_port(80);
-  valid_insecure_proxy->set_scheme(PrefetchProxyConfig_Proxy_Scheme_HTTP);
-
-  SetConfig(config);
-
-  // A network change forces the config to be fetched.
-  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
-  WaitForConfig();
-
-  std::vector<GURL> want_hosts = {
-      GURL("https://override-proxy.com/"),
-  };
-  EXPECT_EQ(want_hosts, settings->GetPrefetchProxies());
-  EXPECT_EQ(want_hosts, observer.prefetch_proxies());
-}
-
-IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest,
-                       UpdatePrefetchProxyConfig_CmdLineOverride_Invalid) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      "allow-insecure-prefetch-proxy-for-testing");
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      "prefetch-proxy-override-proxy-hosts", " ,NotValid, also-not-valid  ");
-
-  TestSettingsObserver observer;
-  DataReductionProxySettings* settings =
-      DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
-          browser()->profile());
-  settings->AddDataReductionProxySettingsObserver(&observer);
-
-  net::EmbeddedTestServer original_server;
-  original_server.RegisterRequestHandler(
-      base::BindRepeating(&BasicResponse, kPrimaryProxyResponse));
-  ASSERT_TRUE(original_server.Start());
-
-  ClientConfig config = CreateConfigForServer(original_server);
-
-  PrefetchProxyConfig_Proxy* valid_secure_proxy =
-      config.mutable_prefetch_proxy_config()->add_proxy_list();
-  valid_secure_proxy->set_type(PrefetchProxyConfig_Proxy_Type_CONNECT);
-  valid_secure_proxy->set_host("prefetch-proxy.com");
-  valid_secure_proxy->set_port(443);
-  valid_secure_proxy->set_scheme(PrefetchProxyConfig_Proxy_Scheme_HTTPS);
-
-  PrefetchProxyConfig_Proxy* valid_insecure_proxy =
-      config.mutable_prefetch_proxy_config()->add_proxy_list();
-  valid_insecure_proxy->set_type(PrefetchProxyConfig_Proxy_Type_CONNECT);
-  valid_insecure_proxy->set_host("insecure-prefetch-proxy.com");
-  valid_insecure_proxy->set_port(80);
-  valid_insecure_proxy->set_scheme(PrefetchProxyConfig_Proxy_Scheme_HTTP);
-
-  SetConfig(config);
-
-  // A network change forces the config to be fetched.
-  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
-  WaitForConfig();
-
-  std::vector<GURL> want_hosts = {
-      GURL("https://prefetch-proxy.com:443/"),
-      GURL("http://insecure-prefetch-proxy.com/"),
-  };
-  EXPECT_EQ(want_hosts, settings->GetPrefetchProxies());
-  EXPECT_EQ(want_hosts, observer.prefetch_proxies());
-}
-
-// Verify that when a client config with no proxies is provided to Chrome,
-// then usage of proxy is disabled. Later, when the client config with valid
-// proxies is fetched, then the specified proxies are used.
-IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest, EmptyConfig) {
-  net::EmbeddedTestServer origin_server;
-  origin_server.RegisterRequestHandler(
-      base::BindRepeating(&BasicResponse, kDummyBody));
-  ASSERT_TRUE(origin_server.Start());
-
-  // Set config to empty, and verify that the response comes from the
-  // |origin_server|.
-  SetConfig(CreateEmptyConfig());
-  // A network change forces the config to be fetched.
-  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_2G);
-  WaitForConfig();
-  ui_test_utils::NavigateToURL(
-      browser(), GetURLWithMockHost(origin_server, "/echoheader?Chrome-Proxy"));
-  ASSERT_EQ(GetBody(), kDummyBody);
-
-  net::EmbeddedTestServer proxy_server;
-  proxy_server.RegisterRequestHandler(
-      base::BindRepeating(&BasicResponse, kPrimaryProxyResponse));
-  ASSERT_TRUE(proxy_server.Start());
-
-  // Set config to |proxy_server|, and verify that the response comes from
-  // |proxy_server|.
-  SetConfig(CreateConfigForServer(proxy_server));
-  // A network change forces the config to be fetched.
-  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
-  WaitForConfig();
-  ui_test_utils::NavigateToURL(
-      browser(), GetURLWithMockHost(origin_server, "/echoheader?Chrome-Proxy"));
-  EXPECT_EQ(GetBody(), kDummyBody);
-
-  // Set config to empty again, and verify that the response comes from the
-  // |origin_server|.
-  SetConfig(CreateEmptyConfig());
-  // A network change forces the config to be fetched.
-  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_2G);
-  WaitForConfig();
-  ui_test_utils::NavigateToURL(
-      browser(), GetURLWithMockHost(origin_server, "/echoheader?Chrome-Proxy"));
-  ASSERT_EQ(GetBody(), kDummyBody);
-}
-
 // Gets the response body for an XHR to |url| (as seen by the renderer).
 std::string ReadSubresourceFromRenderer(Browser* browser,
                                         const GURL& url,
@@ -638,55 +273,7 @@
   EXPECT_EQ(GetBody(), kDummyBody);
 }
 
-IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest,
-                       ProxyNotUsedForWebSocket) {
-  // Expect the WebSocket handshake to be attempted with |test_server|
-  // directly.
-  base::RunLoop web_socket_handshake_loop;
-  net::EmbeddedTestServer test_server;
-  test_server.RegisterRequestHandler(
-      base::BindRepeating(&BasicResponse, kDummyBody));
-  test_server.RegisterRequestMonitor(base::BindLambdaForTesting(
-      [&web_socket_handshake_loop](
-          const net::test_server::HttpRequest& request) {
-        if (request.headers.count("upgrade") > 0u)
-          web_socket_handshake_loop.Quit();
-      }));
-  ASSERT_TRUE(test_server.Start());
 
-  // If the DRP client (erroneously) decides to proxy the WebSocket handshake,
-  // it will attempt to establish a tunnel through |drp_server|.
-  net::EmbeddedTestServer drp_server;
-  drp_server.AddDefaultHandlers(GetChromeTestDataDir());
-  bool tunnel_attempted = false;
-  drp_server.RegisterRequestMonitor(base::BindLambdaForTesting(
-      [&tunnel_attempted, &web_socket_handshake_loop](
-          const net::test_server::HttpRequest& request) {
-        if (request.method == net::test_server::METHOD_CONNECT) {
-          tunnel_attempted = true;
-          web_socket_handshake_loop.Quit();
-        }
-      }));
-  ASSERT_TRUE(drp_server.Start());
-  SetConfig(CreateConfigForServer(drp_server));
-  // A network change forces the config to be fetched.
-  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
-  WaitForConfig();
-
-  ui_test_utils::NavigateToURL(browser(),
-                               GetURLWithMockHost(test_server, "/echo"));
-
-  const std::string url =
-      base::StrCat({"ws://", kMockHost, ":", test_server.base_url().port()});
-  const std::string script = R"((url => {
-    var ws = new WebSocket(url);
-  }))";
-  EXPECT_TRUE(
-      ExecuteScript(browser()->tab_strip_model()->GetActiveWebContents(),
-                    script + "('" + url + "')"));
-  web_socket_handshake_loop.Run();
-  EXPECT_FALSE(tunnel_attempted);
-}
 
 IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest,
                        DoesNotOverrideExistingProxyConfig) {
@@ -711,69 +298,6 @@
   EXPECT_EQ(GetBody(), kDummyBody);
 }
 
-// Test that enabling the holdback disables the proxy and that the client config
-// is fetched when it is force enabled.
-class DataReductionProxyWithHoldbackBrowsertest
-    : public ::testing::WithParamInterface<bool>,
-      public DataReductionProxyBrowsertest {
- public:
-  DataReductionProxyWithHoldbackBrowsertest()
-      : enable_config_service_fetches_(GetParam()) {}
-
-  void SetUp() override {
-    fetch_client_config_feature_list_.InitWithFeatureState(
-        data_reduction_proxy::features::kFetchClientConfig,
-        enable_config_service_fetches_);
-
-    InProcessBrowserTest::SetUp();
-  }
-
-  const bool enable_config_service_fetches_;
-
- private:
-  base::test::ScopedFeatureList fetch_client_config_feature_list_;
-};
-
-IN_PROC_BROWSER_TEST_P(DataReductionProxyWithHoldbackBrowsertest,
-                       UpdateConfig) {
-  net::EmbeddedTestServer proxy_server;
-  proxy_server.RegisterRequestHandler(
-      base::BindRepeating(&BasicResponse, kPrimaryProxyResponse));
-  ASSERT_TRUE(proxy_server.Start());
-
-  SetConfig(CreateConfigForServer(proxy_server));
-  // A network change forces the config to be fetched.
-  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
-
-  // Ensure that the client config is fetched when lite page redirect preview is
-  // enabled.
-  WaitForConfig();
-
-  // Load a webpage in holdback group as well. This ensures that while in
-  // holdback group, Chrome does not fetch the client config. If Chrome were to
-  // fetch the client config, the DCHECKs and other conditionals that check that
-  // holdback is not enabled would trigger and cause the test to fail.
-  ui_test_utils::NavigateToURL(browser(), GURL("http://does.not.resolve/foo"));
-
-  EXPECT_NE(GetBody(), kPrimaryProxyResponse);
-}
-
-// Parameter is true if data reduction proxy config should always be fetched.
-INSTANTIATE_TEST_SUITE_P(All,
-                         DataReductionProxyWithHoldbackBrowsertest,
-                         ::testing::Bool());
-
-class DataReductionProxyExpBrowsertest : public DataReductionProxyBrowsertest {
- public:
-  void SetUp() override {
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        data_reduction_proxy::switches::kDataReductionProxyExperiment,
-        "foo_experiment");
-
-    DataReductionProxyBrowsertest::SetUp();
-  }
-};
-
 class DataReductionProxyExpFeatureBrowsertest
     : public DataReductionProxyBrowsertest {
  public:
@@ -797,40 +321,6 @@
   const std::string experiment_name = "foo_feature_experiment";
 };
 
-// Threadsafe log for recording a sequence of events as newline separated text.
-class EventLog {
- public:
-  void Add(const std::string& event) {
-    base::AutoLock lock(lock_);
-    log_ += event + "\n";
-  }
-
-  std::string GetAndReset() {
-    base::AutoLock lock(lock_);
-    return std::move(log_);
-  }
-
- private:
-  base::Lock lock_;
-  std::string log_;
-};
-
-// Responds to requests with the path as response body, and logs the request
-// into |event_log|.
-std::unique_ptr<net::test_server::HttpResponse> RespondWithRequestPathHandler(
-    const std::string& server_name,
-    EventLog* event_log,
-    const net::test_server::HttpRequest& request) {
-  if (request.relative_url == "/favicon.ico")
-    return nullptr;
-
-  event_log->Add(server_name + " responded 200 for " + request.relative_url);
-  auto response = std::make_unique<net::test_server::BasicHttpResponse>();
-  response->set_content_type("text/plain");
-  response->set_code(net::HTTP_OK);
-  response->set_content(request.relative_url);
-  return response;
-}
 
 // Verify that requests initiated by SimpleURLLoader use the proxy only if
 // render frame ID is set.
@@ -843,11 +333,8 @@
   net::EmbeddedTestServer proxy_server;
   ASSERT_TRUE(proxy_server.Start());
 
-  // Set config to |proxy_server|.
-  SetConfig(CreateConfigForServer(proxy_server));
   // A network change forces the config to be fetched.
   SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
-  WaitForConfig();
 
   for (const bool set_render_frame_id : {false, true}) {
     auto resource_request = std::make_unique<network::ResourceRequest>();
@@ -885,56 +372,6 @@
   }
 }
 
-// Ensure that renderer initiated same-site navigations work.
-IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest,
-                       RendererInitiatedSameSiteNavigation) {
-  // Perform a browser-initiated navigation.
-  net::EmbeddedTestServer origin_server;
-  origin_server.ServeFilesFromSourceDirectory(
-      base::FilePath(FILE_PATH_LITERAL("content/test/data")));
-  ASSERT_TRUE(origin_server.Start());
 
-  net::EmbeddedTestServer proxy_server;
-  proxy_server.ServeFilesFromSourceDirectory(
-      base::FilePath(FILE_PATH_LITERAL("content/test/data")));
-  ASSERT_TRUE(proxy_server.Start());
-  // Set config to |proxy_server|.
-  SetConfig(CreateConfigForServer(proxy_server));
-  // A network change forces the config to be fetched.
-  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
-  WaitForConfig();
-
-  {
-    content::TestNavigationObserver observer(
-        browser()->tab_strip_model()->GetActiveWebContents());
-    GURL url(GetURLWithMockHost(origin_server, "/simple_links.html"));
-    ui_test_utils::NavigateToURL(browser(), url);
-    EXPECT_EQ(url, observer.last_navigation_url());
-    EXPECT_TRUE(observer.last_navigation_succeeded());
-    EXPECT_FALSE(observer.last_initiator_origin().has_value());
-  }
-
-  // Simulate clicking on a same-site link.
-  {
-    content::TestNavigationObserver observer(
-        browser()->tab_strip_model()->GetActiveWebContents());
-    GURL url(GetURLWithMockHost(origin_server, "/title2.html"));
-    bool success = false;
-    EXPECT_TRUE(ExecuteScriptAndExtractBool(
-        browser()->tab_strip_model()->GetActiveWebContents(),
-        "window.domAutomationController.send(clickSameSiteLink());", &success));
-    EXPECT_TRUE(success);
-    EXPECT_TRUE(
-        WaitForLoadStop(browser()->tab_strip_model()->GetActiveWebContents()));
-    EXPECT_EQ(url, observer.last_navigation_url());
-    EXPECT_TRUE(observer.last_navigation_succeeded());
-    EXPECT_EQ(browser()
-                  ->tab_strip_model()
-                  ->GetActiveWebContents()
-                  ->GetMainFrame()
-                  ->GetLastCommittedOrigin(),
-              observer.last_initiator_origin());
-  }
-}
 
 }  // namespace data_reduction_proxy
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.cc
index aec2154..357f273 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.cc
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.cc
@@ -228,9 +228,7 @@
           ->GetURLLoaderFactoryForBrowserProcess();
   std::unique_ptr<data_reduction_proxy::DataReductionProxyService> service =
       std::make_unique<data_reduction_proxy::DataReductionProxyService>(
-          this, profile_prefs, url_loader_factory, std::move(store),
-          g_browser_process->network_quality_tracker(),
-          content::GetNetworkConnectionTracker(),
+          this, profile_prefs, std::move(store),
           data_use_measurement::ChromeDataUseMeasurement::GetInstance(),
           db_task_runner, commit_delay, GetClient(),
           version_info::GetChannelString(chrome::GetChannel()),
@@ -270,10 +268,6 @@
   //  - request_info_
   auto data = std::make_unique<data_reduction_proxy::DataReductionProxyData>();
   data->set_request_url(handle->GetURL());
-  data->set_effective_connection_type(
-      data_reduction_proxy_service()->GetEffectiveConnectionType());
-  data->set_connection_type(net::NetworkChangeNotifier::ConnectionType(
-      data_reduction_proxy_service()->GetConnectionType()));
   data->set_used_data_reduction_proxy(false);
 
   if (!headers || headers->IsRedirect(nullptr))
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h
index a3c2348..e72fa9d 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h
@@ -12,6 +12,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "net/http/http_response_headers.h"
 
 class PrefService;
 class Profile;
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_unittest.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_unittest.cc
index 5a29a711..b6f13bb6e 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_unittest.cc
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_unittest.cc
@@ -11,15 +11,11 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
-#include "components/data_reduction_proxy/proto/client_config.pb.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/proxy_config/proxy_config_pref_names.h"
 #include "content/public/test/mock_navigation_handle.h"
 #include "net/http/http_util.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/test/test_network_connection_tracker.h"
-#include "services/network/test/test_network_quality_tracker.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -34,8 +30,6 @@
  public:
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
-    network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
-        network::mojom::ConnectionType::CONNECTION_4G);
     auto settings = std::make_unique<DataReductionProxyChromeSettings>(false);
     drp_chrome_settings_ = settings.get();
     test_context_ =
@@ -45,9 +39,6 @@
             .Build();
     net::ProxyList proxies;
     proxies.SetFromPacString(kProxyPac);
-    test_context_->test_network_quality_tracker()
-        ->ReportEffectiveConnectionTypeForTesting(
-            net::EFFECTIVE_CONNECTION_TYPE_4G);
     dict_ = std::make_unique<base::DictionaryValue>();
 
     PrefRegistrySimple* registry = test_context_->pref_service()->registry();
diff --git a/chrome/browser/data_saver/data_saver_browsertest.cc b/chrome/browser/data_saver/data_saver_browsertest.cc
index 3640c2fc..7effdac 100644
--- a/chrome/browser/data_saver/data_saver_browsertest.cc
+++ b/chrome/browser/data_saver/data_saver_browsertest.cc
@@ -231,20 +231,6 @@
     SetDataSaverEnabled(browser()->profile(), enabled);
   }
 
-  net::EffectiveConnectionType GetEffectiveConnectionType() const {
-    return DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
-               browser()->profile())
-        ->data_reduction_proxy_service()
-        ->GetEffectiveConnectionType();
-  }
-
-  base::Optional<base::TimeDelta> GetHttpRttEstimate() const {
-    return DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
-               browser()->profile())
-        ->data_reduction_proxy_service()
-        ->GetHttpRttEstimate();
-  }
-
   std::unique_ptr<net::test_server::HttpResponse> VerifySaveDataHeader(
       const net::test_server::HttpRequest& request) {
     auto save_data_header_it = request.headers.find("save-data");
@@ -295,66 +281,6 @@
       browser()->tab_strip_model()->GetActiveWebContents()));
 }
 
-// Test that the data saver receives changes in effective connection type.
-IN_PROC_BROWSER_TEST_F(DataSaverWithServerBrowserTest,
-                       EffectiveConnectionType) {
-  Init();
-
-  // Add a test observer. To determine if data reduction proxy component has
-  // received the network quality change notification, we check if the test
-  // observer has received the notification. Note that all the observers are
-  // notified in the same message loop by the network quality tracker.
-  TestEffectiveConnectionTypeObserver observer(
-      g_browser_process->network_quality_tracker());
-
-  g_browser_process->network_quality_tracker()
-      ->ReportEffectiveConnectionTypeForTesting(
-          net::EFFECTIVE_CONNECTION_TYPE_4G);
-  observer.WaitForNotification(net::EFFECTIVE_CONNECTION_TYPE_4G);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_4G, GetEffectiveConnectionType());
-
-  g_browser_process->network_quality_tracker()
-      ->ReportEffectiveConnectionTypeForTesting(
-          net::EFFECTIVE_CONNECTION_TYPE_2G);
-  observer.WaitForNotification(net::EFFECTIVE_CONNECTION_TYPE_2G);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G, GetEffectiveConnectionType());
-
-  g_browser_process->network_quality_tracker()
-      ->ReportEffectiveConnectionTypeForTesting(
-          net::EFFECTIVE_CONNECTION_TYPE_3G);
-  observer.WaitForNotification(net::EFFECTIVE_CONNECTION_TYPE_3G);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_3G, GetEffectiveConnectionType());
-}
-
-// Test that the data saver receives changes in HTTP RTT estimate.
-IN_PROC_BROWSER_TEST_F(DataSaverWithServerBrowserTest, HttpRttEstimate) {
-  Init();
-
-  // Add a test observer. To determine if data reduction proxy component has
-  // received the network quality change notification, we check if the test
-  // observer has received the notification. Note that all the observers are
-  // notified in the same message loop by the network quality tracker.
-  TestRTTAndThroughputEstimatesObserver observer(
-      g_browser_process->network_quality_tracker());
-
-  g_browser_process->network_quality_tracker()
-      ->ReportRTTsAndThroughputForTesting(
-          base::TimeDelta::FromMilliseconds(100), 0);
-  observer.WaitForNotification(base::TimeDelta::FromMilliseconds(100));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(base::TimeDelta::FromMilliseconds(100), GetHttpRttEstimate());
-
-  g_browser_process->network_quality_tracker()
-      ->ReportRTTsAndThroughputForTesting(
-          base::TimeDelta::FromMilliseconds(500), 0);
-  observer.WaitForNotification(base::TimeDelta::FromMilliseconds(500));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(base::TimeDelta::FromMilliseconds(500), GetHttpRttEstimate());
-}
-
 class DataSaverForWorkerBrowserTest : public InProcessBrowserTest,
                                       public testing::WithParamInterface<bool> {
  protected:
diff --git a/chrome/browser/error_reporting/BUILD.gn b/chrome/browser/error_reporting/BUILD.gn
index 2faabc2..91b7606 100644
--- a/chrome/browser/error_reporting/BUILD.gn
+++ b/chrome/browser/error_reporting/BUILD.gn
@@ -1,10 +1,19 @@
 # Copyright 2020 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
 
 # TODO(crbug.com/1129544) This is currently disabled due to Windows DLL
 # thunking issues. Fix & re-enable.
-assert(is_linux || is_chromeos)
+assert(is_linux || is_chromeos_ash || is_chromeos_lacros)
+
+source_set("constants") {
+  sources = [
+    "constants.cc",
+    "constants.h",
+  ]
+  deps = [ "//build:chromeos_buildflags" ]
+}
 
 static_library("error_reporting") {
   sources = [
@@ -25,6 +34,12 @@
     "//services/network:network_service",
     "//services/network/public/cpp",
   ]
+  if (is_chromeos_ash || is_chromeos_lacros) {
+    sources += [ "chrome_js_error_report_processor_chromeos.cc" ]
+    deps += [ ":constants" ]
+  } else {
+    sources += [ "chrome_js_error_report_processor_nonchromeos.cc" ]
+  }
 }
 
 source_set("test_support") {
@@ -42,6 +57,9 @@
     "//components/crash/content/browser/error_reporting",
     "//components/crash/content/browser/error_reporting:mock_crash_endpoint",
   ]
+  if (is_chromeos_ash || is_chromeos_lacros) {
+    data_deps = [ ":mock_chromeos_crash_reporter" ]
+  }
 }
 
 source_set("unit_test") {
@@ -61,3 +79,17 @@
     "//testing/gtest",
   ]
 }
+
+if (is_chromeos_ash || is_chromeos_lacros) {
+  executable("mock_chromeos_crash_reporter") {
+    testonly = true
+    sources = [ "mock_chromeos_crash_reporter.cc" ]
+
+    deps = [
+      ":constants",
+      "//base",
+      "//net",
+      "//third_party/breakpad:client",
+    ]
+  }
+}
diff --git a/chrome/browser/error_reporting/DEPS b/chrome/browser/error_reporting/DEPS
new file mode 100644
index 0000000..74e1615e
--- /dev/null
+++ b/chrome/browser/error_reporting/DEPS
@@ -0,0 +1,6 @@
+specific_include_rules = {
+  "mock_chromeos_crash_reporter.cc" : [
+    # For testing of crash uploads
+    "+third_party/breakpad/breakpad/src/common/linux/libcurl_wrapper.h",
+  ],
+}
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor.cc b/chrome/browser/error_reporting/chrome_js_error_report_processor.cc
index ff6454ce..2233307 100644
--- a/chrome/browser/error_reporting/chrome_js_error_report_processor.cc
+++ b/chrome/browser/error_reporting/chrome_js_error_report_processor.cc
@@ -6,43 +6,32 @@
 
 #include <tuple>
 #include <utility>
-#include <vector>
 
 #include "base/callback.h"
 #include "base/callback_helpers.h"
-#include "base/files/file.h"
-#include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/path_service.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/time/default_clock.h"
 #include "build/build_config.h"
-#include "chrome/common/chrome_paths.h"
 #include "components/crash/content/browser/error_reporting/javascript_error_report.h"
 #include "components/crash/core/app/client_upload_info.h"
 #include "components/crash/core/app/crashpad.h"
 #include "components/feedback/redaction_tool.h"
 #include "components/startup_metric_utils/browser/startup_metric_utils.h"
-#include "components/upload_list/crash_upload_list.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_partition.h"
 #include "net/base/escape.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/public/cpp/simple_url_loader.h"
 
 namespace {
 
-constexpr char kCrashEndpointUrl[] = "https://clients2.google.com/cr/report";
-constexpr char kCrashEndpointStagingUrl[] =
-    "https://clients2.google.com/cr/staging_report";
 constexpr char kNoBrowserNoWindow[] = "NO_BROWSER";
 constexpr char kRegularTabbedWindow[] = "REGULAR_TABBED";
 constexpr char kWebAppWindow[] = "WEB_APP";
@@ -74,18 +63,6 @@
       .Redact(message);
 }
 
-using ParameterMap = std::map<std::string, std::string>;
-
-std::string BuildPostRequestQueryString(const ParameterMap& params) {
-  std::vector<std::string> query_parts;
-  for (const auto& kv : params) {
-    query_parts.push_back(base::StrCat(
-        {kv.first, "=",
-         net::EscapeQueryParamValue(kv.second, /*use_plus=*/false)}));
-  }
-  return base::JoinString(query_parts, "&");
-}
-
 std::string MapWindowTypeToString(WindowType window_type) {
   switch (window_type) {
     case WindowType::kRegularTabbed:
@@ -105,69 +82,19 @@
     : clock_(base::DefaultClock::GetInstance()) {}
 ChromeJsErrorReportProcessor::~ChromeJsErrorReportProcessor() = default;
 
-#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
-void ChromeJsErrorReportProcessor::UpdateReportDatabase(
-    std::string remote_report_id,
-    base::Time report_time) {
-  // Uploads.log format is "seconds_since_epoch,crash_id\n"
-  base::FilePath crash_dir_path;
-  if (!base::PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dir_path)) {
-    VLOG(1) << "Nowhere to write uploads.log";
-    return;
-  }
-  base::FilePath upload_log_path =
-      crash_dir_path.AppendASCII(CrashUploadList::kReporterLogFilename);
-  base::File upload_log(upload_log_path,
-                        base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND);
-  if (!upload_log.IsValid()) {
-    VLOG(1) << "Could not open upload.log: "
-            << base::File::ErrorToString(upload_log.error_details());
-    return;
-  }
-  std::string line = base::StrCat({base::NumberToString(report_time.ToTimeT()),
-                                   ",", remote_report_id, "\n"});
-  // WriteAtCurrentPos because O_APPEND.
-  if (upload_log.WriteAtCurrentPos(line.c_str(), line.length()) !=
-      static_cast<int>(line.length())) {
-    VLOG(1) << "Could not write to upload.log";
-    return;
-  }
-}
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
-
-void ChromeJsErrorReportProcessor::OnRequestComplete(
-    std::unique_ptr<network::SimpleURLLoader> url_loader,
-    base::ScopedClosureRunner callback_runner,
-    base::Time report_time,
-    std::unique_ptr<std::string> response_body) {
-  if (response_body) {
-    VLOG(1) << "Uploaded crash report. ID: " << *response_body;
-    // On Chrome OS, we use a different format than other platforms. Since we
-    // will soon not call this function at all on Chrome OS (crbug.com/986166),
-    // don't bother writing code to write to that format.
-#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
-    base::ThreadPool::PostTaskAndReply(
-        FROM_HERE, {base::MayBlock()},
-        base::BindOnce(&ChromeJsErrorReportProcessor::UpdateReportDatabase,
-                       this, *response_body, report_time),
-        callback_runner.Release());
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
-  } else {
-    LOG(ERROR) << "Failed to upload crash report";
-  }
-  // callback_runner may implicitly run the callback when we reach this line if
-  // we didn't add a task to update the report database.
-}
-
 // Returns the redacted, fixed-up error report if the user consented to have it
 // sent. Returns base::nullopt if the user did not consent or we otherwise
 // should not send the report. All the MayBlock work should be done in here.
 base::Optional<JavaScriptErrorReport>
 ChromeJsErrorReportProcessor::CheckConsentAndRedact(
     JavaScriptErrorReport error_report) {
+  // Consent is handled at the OS level by crash_reporter so we don't need to
+  // check it here for Chrome OS.
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
   if (!crash_reporter::GetClientCollectStatsConsent()) {
     return base::nullopt;
   }
+#endif
 
   // Remove error message from stack trace before redaction, since redaction
   // might change the error message enough that we don't find it.
@@ -186,7 +113,6 @@
   std::string product_name;
   std::string version;
   std::string channel;
-  std::string os_version;
 };
 
 ChromeJsErrorReportProcessor::PlatformInfo
@@ -199,79 +125,9 @@
   crash_reporter::GetClientProductNameAndVersion(&info.product_name,
                                                  &info.version, &info.channel);
 #endif
-  int32_t os_major_version = 0;
-  int32_t os_minor_version = 0;
-  int32_t os_bugfix_version = 0;
-  GetOsVersion(os_major_version, os_minor_version, os_bugfix_version);
-  info.os_version = base::StringPrintf("%d.%d.%d", os_major_version,
-                                       os_minor_version, os_bugfix_version);
   return info;
 }
 
-void ChromeJsErrorReportProcessor::SendReport(
-    const GURL& url,
-    const std::string& body,
-    base::ScopedClosureRunner callback_runner,
-    base::Time report_time,
-    network::SharedURLLoaderFactory* loader_factory) {
-  auto resource_request = std::make_unique<network::ResourceRequest>();
-  resource_request->method = "POST";
-  resource_request->url = url;
-
-  const auto traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("javascript_report_error", R"(
-      semantics {
-        sender: "JavaScript error reporter"
-        description:
-          "Chrome can send JavaScript errors that occur within built-in "
-          "component extensions and chrome:// webpages. If enabled, the error "
-          "message, along with information about Chrome and the operating "
-          "system, is sent to Google for debugging."
-        trigger:
-          "A JavaScript error occurs in a Chrome component extension (an "
-          "extension bundled with the Chrome browser, not downloaded "
-          "separately) or in certain chrome:// webpages."
-        data:
-          "The JavaScript error message, the version and channel of Chrome, "
-          "the URL of the extension or webpage, the line and column number of "
-          "the JavaScript code where the error occurred, and a stack trace of "
-          "the error."
-        destination: GOOGLE_OWNED_SERVICE
-      }
-      policy {
-        cookies_allowed: NO
-        setting:
-          "You can enable or disable this feature via 'Automatically send "
-          "usage statistics and crash reports to Google' in Chromium's "
-          "settings under Advanced, Privacy. (This is in System Settings on "
-          "Chromebooks.) This feature is enabled by default."
-        chrome_policy {
-          MetricsReportingEnabled {
-            policy_options {mode: MANDATORY}
-            MetricsReportingEnabled: false
-          }
-        }
-      })");
-
-  VLOG(1) << "Sending crash report: " << resource_request->url;
-
-  auto url_loader = network::SimpleURLLoader::Create(
-      std::move(resource_request), traffic_annotation);
-
-  if (!body.empty()) {
-    url_loader->AttachStringForUpload(body, "text/plain");
-  }
-
-  constexpr int kCrashEndpointResponseMaxSizeInBytes = 1024;
-  network::SimpleURLLoader* loader = url_loader.get();
-  loader->DownloadToString(
-      loader_factory,
-      base::BindOnce(&ChromeJsErrorReportProcessor::OnRequestComplete, this,
-                     std::move(url_loader), std::move(callback_runner),
-                     report_time),
-      kCrashEndpointResponseMaxSizeInBytes);
-}
-
 // Finishes sending process once the MayBlock processing is done. On UI thread.
 void ChromeJsErrorReportProcessor::OnConsentCheckCompleted(
     base::ScopedClosureRunner callback_runner,
@@ -285,13 +141,7 @@
     return;
   }
 
-  std::string crash_endpoint_string = error_report->send_to_production_servers
-                                          ? GetCrashEndpoint()
-                                          : GetCrashEndpointStaging();
-
-  // TODO(https://crbug.com/986166): Use crash_reporter for Chrome OS.
   const auto platform = GetPlatformInfo();
-
   const GURL source(error_report->url);
   const auto product = error_report->product.empty() ? platform.product_name
                                                      : error_report->product;
@@ -311,8 +161,8 @@
   params["os"] = "ChromeOS";
 #else
   params["os"] = base::SysInfo::OperatingSystemName();
+  params["os_version"] = GetOsVersion();
 #endif
-  params["os_version"] = platform.os_version;
   params["full_url"] = source.spec();
   params["url"] = source.path();
   params["src"] = source.spec();
@@ -334,15 +184,10 @@
   }
   if (error_report->app_locale)
     params["app_locale"] = std::move(*error_report->app_locale);
-  const GURL url(base::StrCat(
-      {crash_endpoint_string, "?", BuildPostRequestQueryString(params)}));
-  std::string body;
-  if (error_report->stack_trace) {
-    body = std::move(*error_report->stack_trace);
-  }
 
-  SendReport(url, body, std::move(callback_runner), report_time,
-             loader_factory.get());
+  SendReport(std::move(params), std::move(error_report->stack_trace),
+             error_report->send_to_production_servers,
+             std::move(callback_runner), report_time, loader_factory);
 }
 
 void ChromeJsErrorReportProcessor::CheckAndUpdateRecentErrorReports(
@@ -447,11 +292,14 @@
 
   base::ScopedClosureRunner callback_runner(std::move(completion_callback));
 
+  scoped_refptr<network::SharedURLLoaderFactory> loader_factory;
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
   // loader_factory must be created on UI thread. Get it now while we still
   // know the browser_context pointer is valid.
-  scoped_refptr<network::SharedURLLoaderFactory> loader_factory =
+  loader_factory =
       content::BrowserContext::GetDefaultStoragePartition(browser_context)
           ->GetURLLoaderFactoryForBrowserProcess();
+#endif
 
   // Get browser uptime before swapping threads to reduce lag time between the
   // error report occurring and sending it off.
@@ -470,18 +318,3 @@
                      std::move(loader_factory), browser_process_uptime,
                      clock_->Now()));
 }
-
-std::string ChromeJsErrorReportProcessor::GetCrashEndpoint() {
-  return kCrashEndpointUrl;
-}
-
-std::string ChromeJsErrorReportProcessor::GetCrashEndpointStaging() {
-  return kCrashEndpointStagingUrl;
-}
-
-void ChromeJsErrorReportProcessor::GetOsVersion(int32_t& os_major_version,
-                                                int32_t& os_minor_version,
-                                                int32_t& os_bugfix_version) {
-  base::SysInfo::OperatingSystemVersionNumbers(
-      &os_major_version, &os_minor_version, &os_bugfix_version);
-}
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor.h b/chrome/browser/error_reporting/chrome_js_error_report_processor.h
index 1ac534e..c702ad4a 100644
--- a/chrome/browser/error_reporting/chrome_js_error_report_processor.h
+++ b/chrome/browser/error_reporting/chrome_js_error_report_processor.h
@@ -9,10 +9,12 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "base/callback_forward.h"
 #include "base/callback_helpers.h"
 #include "base/containers/flat_map.h"
+#include "base/optional.h"
 #include "base/time/clock.h"
 #include "base/time/time.h"
 #include "build/chromeos_buildflags.h"
@@ -49,11 +51,30 @@
     return recent_error_reports_;
   }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  // Force the error report processor to use the less-commonly-used temp file
+  // solution for communicating with crash_reporter. This is normally only used
+  // on old kernels without memfd_create, so we don't get good unit test
+  // coverage unless we force it.
+  void set_force_non_memfd_for_test() { force_non_memfd_for_test_ = true; }
+#endif
+
  protected:
   // Non-tests should call ChromeJsErrorReportProcessor::Create() instead.
   ChromeJsErrorReportProcessor();
   ~ChromeJsErrorReportProcessor() override;
 
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  // Returns the first element(s) of the crash_reporter argv. By default, this
+  // is just the command name (so {"/sbin/crash_reporter"}). Virtual so that
+  // tests can override and can provide additional arguments to the test binary
+  // if needed.
+  virtual std::vector<std::string> GetCrashReporterArgvStart();
+#else
+  // Determines the version of the OS we are on. Virtual so that tests can
+  // override. On Chrome OS, this information is added by the crash_reporter.
+  virtual std::string GetOsVersion();
+
   // Testing hook -- returns the URL we will send the error reports to. By
   // default, returns the real endpoint.
   virtual std::string GetCrashEndpoint();
@@ -63,13 +84,6 @@
   // default, returns the real staging endpoint.
   virtual std::string GetCrashEndpointStaging();
 
-  // Determines the version of the OS we are on. Virtual so that tests can
-  // override.
-  virtual void GetOsVersion(int32_t& os_major_version,
-                            int32_t& os_minor_version,
-                            int32_t& os_bugfix_version);
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
   // Update the uploads.log file with a record of this error report. This
   // ensures that the error appears on chrome://crashes and is listed in the
   // feedback reports.
@@ -79,11 +93,7 @@
 
  private:
   struct PlatformInfo;
-
-  void OnRequestComplete(std::unique_ptr<network::SimpleURLLoader> url_loader,
-                         base::ScopedClosureRunner callback_runner,
-                         base::Time report_time,
-                         std::unique_ptr<std::string> response_body);
+  using ParameterMap = std::map<std::string, std::string>;
 
   base::Optional<JavaScriptErrorReport> CheckConsentAndRedact(
       JavaScriptErrorReport error_report);
@@ -114,6 +124,41 @@
       const JavaScriptErrorReport& error_report,
       bool* should_send);
 
+  void SendReport(
+      ParameterMap params,
+      base::Optional<std::string> stack_trace,
+      bool send_to_production_servers,
+      base::ScopedClosureRunner callback_runner,
+      base::Time report_time,
+      scoped_refptr<network::SharedURLLoaderFactory> loader_factory);
+
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  // Write the parameters (and the stack_trace, if present) into a string
+  // suitable for passing the crash_reporter. Returns the string.
+  //
+  // Format is the same key:length:value format used by Crashpad and Breakpad
+  // when talking to crash_reporter. Example:
+  // value1:5:abcdevalue2:10:hellothere
+  static std::string ParamsToCrashReporterString(
+      const ParameterMap& params,
+      const base::Optional<std::string>& stack_trace);
+
+  void SendReportViaCrashReporter(ParameterMap params,
+                                  base::Optional<std::string> stack_trace);
+
+  bool force_non_memfd_for_test_ = false;
+#else
+  // Turn the parameter key/value pairs into a list of parameters suitable for
+  // being the query part of a URL. Does URL escaping and such.
+  static std::string BuildPostRequestQueryString(const ParameterMap& params);
+
+  void OnRequestComplete(std::unique_ptr<network::SimpleURLLoader> url_loader,
+                         base::ScopedClosureRunner callback_runner,
+                         base::Time report_time,
+                         std::unique_ptr<std::string> response_body);
+
+#endif
+
   // For JavaScript error reports, a mapping of message+product+line+column to
   // the last time we sent an error message for that
   // message+product+line+column.
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor_chromeos.cc b/chrome/browser/error_reporting/chrome_js_error_report_processor_chromeos.cc
new file mode 100644
index 0000000..f28b23f
--- /dev/null
+++ b/chrome/browser/error_reporting/chrome_js_error_report_processor_chromeos.cc
@@ -0,0 +1,187 @@
+// 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/error_reporting/chrome_js_error_report_processor.h"
+
+#include <errno.h>
+
+#include <algorithm>
+
+#include "base/callback_helpers.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/launch.h"
+#include "base/process/process.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/thread_restrictions.h"
+#include "chrome/browser/error_reporting/constants.h"
+
+// Per the memfd_create man page, we need _GNU_SOURCE
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <sys/mman.h>
+
+namespace {
+
+// The format used to communicate with crash_reporter keys treats ':' as special
+// (introducing the length of the value). Remove any :'s from the key names in
+// place.
+void ReplaceColonsWithUnderscores(std::string& key) {
+  std::replace(key.begin(), key.end(), ':', '_');
+}
+
+// Gets a File pointing to some temporary location. In some cases, we have to
+// do extra cleanup; pass an *unbound* ScopedClosureRunner in |cleanup| so that
+// this function can add the necessary cleanup function.
+// If |force_non_memfd_for_test| is true, we act as if the memfd call failed and
+// go to the temp file case. Since most machines have memfd_create implemented,
+// this is the only way to get some unit-test coverage on the non-memfd_create
+// path.
+base::File GetMemfdOrTempFile(base::ScopedClosureRunner& cleanup,
+                              bool force_non_memfd_for_test) {
+  DCHECK(!cleanup) << "cleanup must be unbound";
+  if (!force_non_memfd_for_test) {
+    int memfd = HANDLE_EINTR(memfd_create("javascript_error", 0));
+    if (memfd != -1) {
+      return base::File(memfd);
+    }
+
+    if (errno != ENOSYS) {
+      PLOG(ERROR)
+          << "Could not create memfd file for JavaScript error reporting";
+      return base::File(base::File::FILE_ERROR_FAILED);
+    }
+  }
+
+  // Note that some VMs and boards with old kernels don't have memfd_create
+  // implemented yet. Work around by creating a temp file.
+  base::FilePath output_path;
+  base::ScopedFILE output_file = CreateAndOpenTemporaryStream(&output_path);
+  if (!output_file) {
+    PLOG(ERROR)
+        << "memfd_create not implemented and cannot create temporary stream";
+    return base::File(base::File::FILE_ERROR_FAILED);
+  }
+
+  DLOG(WARNING) << "JavaScript error reporting: Falling back to temp file "
+                << output_path.value();
+
+  // Need to actually delete the temp file once we're done.
+  cleanup.ReplaceClosure(
+      base::BindOnce(base::GetDeleteFileCallback(), std::move(output_path)));
+  return base::FILEToFile(output_file.release());
+}
+
+}  // namespace
+
+std::vector<std::string>
+ChromeJsErrorReportProcessor::GetCrashReporterArgvStart() {
+  return {"/sbin/crash_reporter"};
+}
+
+std::string ChromeJsErrorReportProcessor::ParamsToCrashReporterString(
+    const ParameterMap& params,
+    const base::Optional<std::string>& stack_trace) {
+  std::string result;
+  for (const auto& param : params) {
+    std::string key = param.first;
+    const std::string& value = param.second;
+    ReplaceColonsWithUnderscores(key);
+    std::string value_length_string = base::NumberToString(value.length());
+    base::StrAppend(&result, {key, ":", value_length_string, ":", value});
+  }
+  if (stack_trace) {
+    const std::string& payload = stack_trace.value();
+
+    std::string value_length_string = base::NumberToString(payload.length());
+    base::StrAppend(
+        &result, {kJavaScriptStackKey, ":", value_length_string, ":", payload});
+  }
+
+  return result;
+}
+
+void ChromeJsErrorReportProcessor::SendReportViaCrashReporter(
+    ParameterMap params,
+    base::Optional<std::string> stack_trace) {
+  base::ScopedClosureRunner cleanup;
+  base::File output(GetMemfdOrTempFile(cleanup, force_non_memfd_for_test_));
+  if (!output.IsValid()) {
+    return;  // Already logged error message in GetMemfdOrTempFile.
+  }
+
+  std::string string_to_write =
+      ParamsToCrashReporterString(params, stack_trace);
+  if (output.WriteAtCurrentPos(string_to_write.data(),
+                               string_to_write.length()) !=
+      static_cast<int>(string_to_write.length())) {
+    PLOG(ERROR) << "Failed to write to crash_reporter pipe";
+    return;
+  }
+
+  base::LaunchOptions crash_reporter_options;
+  crash_reporter_options.fds_to_remap.emplace_back(output.GetPlatformFile(),
+                                                   output.GetPlatformFile());
+
+  std::vector<std::string> argv(GetCrashReporterArgvStart());
+  argv.insert(argv.end(),
+              {base::StrCat({"--chrome_memfd=",
+                             base::NumberToString(output.GetPlatformFile())}),
+               base::StrCat({"--pid=", base::NumberToString(getpid())}),
+               base::StrCat({"--uid=", base::NumberToString(geteuid())}),
+               "--error_key=jserror"});
+
+  base::Process process = base::LaunchProcess(argv, crash_reporter_options);
+  if (!process.IsValid()) {
+    PLOG(ERROR) << "Failed to launch " << base::JoinString(argv, " ");
+    return;
+  }
+
+  {
+    base::ScopedAllowBaseSyncPrimitives allow_wait_for_exit;
+    // Wait for crash_reporter to finish. We need to wait for it to finish
+    // before we delete the temporary files that may have been created in
+    // GetMemfdOrTempFile().
+    int return_code = 0;
+    constexpr base::TimeDelta kMaximumWait = base::TimeDelta::FromMinutes(1);
+    if (process.WaitForExitWithTimeout(kMaximumWait, &return_code)) {
+      if (return_code != 0) {
+        LOG(WARNING) << "crash_reporter subprocess failed with return value "
+                     << return_code
+                     << (return_code == -1 ? " or maybe crashed" : "");
+      }
+    } else {
+      // Kill the stuck process to avoid zombies.
+      LOG(WARNING) << "crash_reporter failed to complete within "
+                   << kMaximumWait;
+      process.Terminate(0, false /*wait*/);
+    }
+  }
+}
+
+void ChromeJsErrorReportProcessor::SendReport(
+    ParameterMap params,
+    base::Optional<std::string> stack_trace,
+    bool send_to_production_servers,
+    base::ScopedClosureRunner callback_runner,
+    base::Time report_time,
+    scoped_refptr<network::SharedURLLoaderFactory> loader_factory) {
+  // On Chrome OS, send the report through the OS crash reporting system to
+  // get more metadata and to keep all the consent logic in one place. We need
+  // to do file I/O, so over to a blockable thread for the send and then back to
+  // the UI thread for the finished callback.
+  base::ThreadPool::PostTaskAndReply(
+      FROM_HERE, {base::MayBlock()},
+      base::BindOnce(&ChromeJsErrorReportProcessor::SendReportViaCrashReporter,
+                     this, std::move(params), std::move(stack_trace)),
+      callback_runner.Release());
+}
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor_nonchromeos.cc b/chrome/browser/error_reporting/chrome_js_error_report_processor_nonchromeos.cc
new file mode 100644
index 0000000..050a2c7
--- /dev/null
+++ b/chrome/browser/error_reporting/chrome_js_error_report_processor_nonchromeos.cc
@@ -0,0 +1,186 @@
+// 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/error_reporting/chrome_js_error_report_processor.h"
+
+#include <utility>
+
+#include "base/callback_helpers.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/system/sys_info.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "chrome/common/chrome_paths.h"
+#include "components/upload_list/crash_upload_list.h"
+#include "net/base/escape.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "url/gurl.h"
+
+namespace {
+
+constexpr char kCrashEndpointUrl[] = "https://clients2.google.com/cr/report";
+constexpr char kCrashEndpointStagingUrl[] =
+    "https://clients2.google.com/cr/staging_report";
+
+}  // namespace
+
+void ChromeJsErrorReportProcessor::OnRequestComplete(
+    std::unique_ptr<network::SimpleURLLoader> url_loader,
+    base::ScopedClosureRunner callback_runner,
+    base::Time report_time,
+    std::unique_ptr<std::string> response_body) {
+  if (response_body) {
+    VLOG(1) << "Uploaded crash report. ID: " << *response_body;
+    // On Chrome OS, we use a different format than other platforms. Since we
+    // will soon not call this function at all on Chrome OS (crbug.com/986166),
+    // don't bother writing code to write to that format.
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
+    base::ThreadPool::PostTaskAndReply(
+        FROM_HERE, {base::MayBlock()},
+        base::BindOnce(&ChromeJsErrorReportProcessor::UpdateReportDatabase,
+                       this, std::move(*response_body), report_time),
+        callback_runner.Release());
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
+  } else {
+    LOG(ERROR) << "Failed to upload crash report";
+  }
+  // callback_runner may implicitly run the callback when we reach this line if
+  // we didn't add a task to update the report database.
+}
+
+std::string ChromeJsErrorReportProcessor::BuildPostRequestQueryString(
+    const ParameterMap& params) {
+  std::vector<std::string> query_parts;
+  for (const auto& kv : params) {
+    query_parts.push_back(base::StrCat(
+        {kv.first, "=",
+         net::EscapeQueryParamValue(kv.second, /*use_plus=*/false)}));
+  }
+  return base::JoinString(query_parts, "&");
+}
+
+void ChromeJsErrorReportProcessor::UpdateReportDatabase(
+    std::string remote_report_id,
+    base::Time report_time) {
+  // Uploads.log format is "seconds_since_epoch,crash_id\n"
+  base::FilePath crash_dir_path;
+  if (!base::PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dir_path)) {
+    VLOG(1) << "Nowhere to write uploads.log";
+    return;
+  }
+  base::FilePath upload_log_path =
+      crash_dir_path.AppendASCII(CrashUploadList::kReporterLogFilename);
+  base::File upload_log(upload_log_path,
+                        base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND);
+  if (!upload_log.IsValid()) {
+    VLOG(1) << "Could not open upload.log: "
+            << base::File::ErrorToString(upload_log.error_details());
+    return;
+  }
+  std::string line = base::StrCat({base::NumberToString(report_time.ToTimeT()),
+                                   ",", remote_report_id, "\n"});
+  // WriteAtCurrentPos because O_APPEND.
+  if (upload_log.WriteAtCurrentPos(line.c_str(), line.length()) !=
+      static_cast<int>(line.length())) {
+    VLOG(1) << "Could not write to upload.log";
+    return;
+  }
+}
+
+std::string ChromeJsErrorReportProcessor::GetCrashEndpoint() {
+  return kCrashEndpointUrl;
+}
+
+std::string ChromeJsErrorReportProcessor::GetCrashEndpointStaging() {
+  return kCrashEndpointStagingUrl;
+}
+
+// On non-Chrome OS platforms, send the report directly.
+void ChromeJsErrorReportProcessor::SendReport(
+    ParameterMap params,
+    base::Optional<std::string> stack_trace,
+    bool send_to_production_servers,
+    base::ScopedClosureRunner callback_runner,
+    base::Time report_time,
+    scoped_refptr<network::SharedURLLoaderFactory> loader_factory) {
+  std::string crash_endpoint_string = send_to_production_servers
+                                          ? GetCrashEndpoint()
+                                          : GetCrashEndpointStaging();
+
+  const GURL url(base::StrCat(
+      {crash_endpoint_string, "?", BuildPostRequestQueryString(params)}));
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->method = "POST";
+  resource_request->url = url;
+
+  const auto traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("javascript_report_error", R"(
+      semantics {
+        sender: "JavaScript error reporter"
+        description:
+          "Chrome can send JavaScript errors that occur within built-in "
+          "component extensions and chrome:// webpages. If enabled, the error "
+          "message, along with information about Chrome and the operating "
+          "system, is sent to Google for debugging."
+        trigger:
+          "A JavaScript error occurs in a Chrome component extension (an "
+          "extension bundled with the Chrome browser, not downloaded "
+          "separately) or in certain chrome:// webpages."
+        data:
+          "The JavaScript error message, the version and channel of Chrome, "
+          "the URL of the extension or webpage, the line and column number of "
+          "the JavaScript code where the error occurred, and a stack trace of "
+          "the error."
+        destination: GOOGLE_OWNED_SERVICE
+      }
+      policy {
+        cookies_allowed: NO
+        setting:
+          "You can enable or disable this feature via 'Automatically send "
+          "usage statistics and crash reports to Google' in Chromium's "
+          "settings under Advanced, Privacy. (This is in System Settings on "
+          "Chromebooks.) This feature is enabled by default."
+        chrome_policy {
+          MetricsReportingEnabled {
+            policy_options {mode: MANDATORY}
+            MetricsReportingEnabled: false
+          }
+        }
+      })");
+
+  VLOG(1) << "Sending crash report: " << resource_request->url;
+
+  auto url_loader = network::SimpleURLLoader::Create(
+      std::move(resource_request), traffic_annotation);
+
+  if (stack_trace) {
+    url_loader->AttachStringForUpload(*stack_trace, "text/plain");
+  }
+
+  constexpr int kCrashEndpointResponseMaxSizeInBytes = 1024;
+  network::SimpleURLLoader* loader = url_loader.get();
+  loader->DownloadToString(
+      loader_factory.get(),
+      base::BindOnce(&ChromeJsErrorReportProcessor::OnRequestComplete, this,
+                     std::move(url_loader), std::move(callback_runner),
+                     report_time),
+      kCrashEndpointResponseMaxSizeInBytes);
+}
+
+std::string ChromeJsErrorReportProcessor::GetOsVersion() {
+  int32_t os_major_version = 0;
+  int32_t os_minor_version = 0;
+  int32_t os_bugfix_version = 0;
+  base::SysInfo::OperatingSystemVersionNumbers(
+      &os_major_version, &os_minor_version, &os_bugfix_version);
+  return base::StrCat({base::NumberToString(os_major_version), ".",
+                       base::NumberToString(os_minor_version), ".",
+                       base::NumberToString(os_bugfix_version)});
+}
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc b/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc
index 6df0d6d9..0e7ebf61c 100644
--- a/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc
+++ b/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/callback.h"
 #include "base/callback_helpers.h"
+#include "base/run_loop.h"
 #include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/simple_test_clock.h"
@@ -70,6 +71,10 @@
     run_loop.Run();
   }
 
+  // Helper for TEST_F(ChromeJsErrorReportProcessorTest, AllFields) and
+  // TEST_F(ChromeJsErrorReportProcessorTest, WorksWithoutMemfdCreate).
+  void TestAllFields();
+
  protected:
   base::SimpleTestClock test_clock_;
   content::BrowserTaskEnvironment task_environment_;
@@ -122,9 +127,12 @@
   EXPECT_THAT(actual_report->query,
               HasSubstr("full_url=https%3A%2F%2Fwww.chromium.org%2FHome"));
   EXPECT_THAT(actual_report->query, HasSubstr("url=%2FHome"));
+  EXPECT_THAT(actual_report->query, HasSubstr("browser=Chrome"));
+
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
   // This is from MockChromeJsErrorReportProcessor::GetOsVersion()
   EXPECT_THAT(actual_report->query, HasSubstr("os_version=7.20.1"));
-  EXPECT_THAT(actual_report->query, HasSubstr("browser=Chrome"));
+#endif
   // These are from MockCrashEndpoint::Client::GetProductNameAndVersion, which
   // is only defined for non-MAC POSIX systems. TODO(https://crbug.com/1121816):
   // Get this info for non-POSIX platforms.
@@ -137,7 +145,7 @@
   EXPECT_EQ(actual_report->content, "");
 }
 
-TEST_F(ChromeJsErrorReportProcessorTest, AllFields) {
+void ChromeJsErrorReportProcessorTest::TestAllFields() {
   auto report = MakeErrorReport("Hello World");
   report.url = "https://www.chromium.org/Home";
   report.product = "Unit test";
@@ -166,8 +174,6 @@
   EXPECT_THAT(actual_report->query,
               HasSubstr("full_url=https%3A%2F%2Fwww.chromium.org%2FHome"));
   EXPECT_THAT(actual_report->query, HasSubstr("url=%2FHome"));
-  // This is from MockChromeJsErrorReportProcessor::GetOsVersion()
-  EXPECT_THAT(actual_report->query, HasSubstr("os_version=7.20.1"));
   EXPECT_THAT(actual_report->query, HasSubstr("browser=Chrome"));
   // product is double-escaped. The first time, it transforms to Unit%20test,
   // then the % is turned into %25.
@@ -175,6 +181,11 @@
   EXPECT_THAT(actual_report->query, HasSubstr("ver=6.2.3.4"));
   EXPECT_THAT(actual_report->query, HasSubstr("line=83"));
   EXPECT_THAT(actual_report->query, HasSubstr("column=14"));
+
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
+  // This is from MockChromeJsErrorReportProcessor::GetOsVersion()
+  EXPECT_THAT(actual_report->query, HasSubstr("os_version=7.20.1"));
+#endif
   // These are from MockCrashEndpoint::Client::GetProductNameAndVersion, which
   // is only defined for non-MAC POSIX systems. TODO(https://crbug.com/1121816):
   // Get this info for non-POSIX platforms.
@@ -185,6 +196,13 @@
   EXPECT_EQ(actual_report->content, "bad_func(1, 2)\nonclick()\n");
 }
 
+TEST_F(ChromeJsErrorReportProcessorTest, AllFields) {
+  TestAllFields();
+}
+
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
+// On Chrome OS, consent checks are handled in the crash_reporter, not in the
+// browser.
 TEST_F(ChromeJsErrorReportProcessorTest, NoConsent) {
   endpoint_->set_consented(false);
   auto report = MakeErrorReport("Hello World");
@@ -195,6 +213,7 @@
 
   EXPECT_FALSE(endpoint_->last_report());
 }
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
 
 TEST_F(ChromeJsErrorReportProcessorTest, StackTraceWithErrorMessage) {
   auto report = MakeErrorReport("Hello World");
@@ -508,3 +527,10 @@
                      << UploadInfoVectorToString(uploads);
 }
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
+
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+TEST_F(ChromeJsErrorReportProcessorTest, WorksWithoutMemfdCreate) {
+  processor_->set_force_non_memfd_for_test();
+  TestAllFields();
+}
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/chrome/browser/error_reporting/constants.cc b/chrome/browser/error_reporting/constants.cc
new file mode 100644
index 0000000..774c90b
--- /dev/null
+++ b/chrome/browser/error_reporting/constants.cc
@@ -0,0 +1,9 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/error_reporting/constants.h"
+
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+const char kJavaScriptStackKey[] = "upload_file_js_stack\"; filename=\"stack\"";
+#endif
diff --git a/chrome/browser/error_reporting/constants.h b/chrome/browser/error_reporting/constants.h
new file mode 100644
index 0000000..2d96c57
--- /dev/null
+++ b/chrome/browser/error_reporting/constants.h
@@ -0,0 +1,19 @@
+// 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_ERROR_REPORTING_CONSTANTS_H_
+#define CHROME_BROWSER_ERROR_REPORTING_CONSTANTS_H_
+
+#include "build/chromeos_buildflags.h"
+
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+// The key we pass to crash_reporter to indicate this key/value pair is the
+// JavaScript stack payload.
+// The format of the key needs to match Chrome OS's
+// ChromeCollector::ParseCrashLog and kDefaultJavaScriptStackName. The
+// 'filename' within the key doesn't actually matter but must be present.
+extern const char kJavaScriptStackKey[];
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+
+#endif  // CHROME_BROWSER_ERROR_REPORTING_CONSTANTS_H_
diff --git a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc
index 5437218c..a6a40e45 100644
--- a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc
+++ b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc
@@ -4,8 +4,13 @@
 
 #include "chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h"
 
+#include "base/base_paths.h"
 #include "base/check.h"
+#include "base/files/file_path.h"
 #include "base/logging.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/strings/strcat.h"
 #include "components/crash/content/browser/error_reporting/javascript_error_report.h"
 #include "components/crash/content/browser/error_reporting/mock_crash_endpoint.h"
 
@@ -44,6 +49,24 @@
   crash_endpoint_staging_ = crash_endpoint;
 }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+std::vector<std::string>
+MockChromeJsErrorReportProcessor::GetCrashReporterArgvStart() {
+  // Redirect uploads to our a simple upload shim which will then send them to
+  // the MockCrashEndpoint. This simulates the Chrome OS crash_reporter and
+  // crash_sender in a way that allows most tests to run without changes.
+  base::FilePath mock_crash_reporter_path;
+  CHECK(base::PathService::Get(base::DIR_EXE, &mock_crash_reporter_path));
+  mock_crash_reporter_path =
+      mock_crash_reporter_path.Append("mock_chromeos_crash_reporter");
+  return {mock_crash_reporter_path.value(),
+          base::StrCat({"--upload_to=", crash_endpoint_})};
+}
+#else
+std::string MockChromeJsErrorReportProcessor::GetOsVersion() {
+  return "7.20.1";
+}
+
 std::string MockChromeJsErrorReportProcessor::GetCrashEndpoint() {
   return crash_endpoint_;
 }
@@ -52,16 +75,6 @@
   return crash_endpoint_staging_;
 }
 
-void MockChromeJsErrorReportProcessor::GetOsVersion(
-    int32_t& os_major_version,
-    int32_t& os_minor_version,
-    int32_t& os_bugfix_version) {
-  os_major_version = 7;
-  os_minor_version = 20;
-  os_bugfix_version = 1;
-}
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
 void MockChromeJsErrorReportProcessor::UpdateReportDatabase(
     std::string remote_report_id,
     base::Time report_time) {
diff --git a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h
index 015ca699..2b8dcec 100644
--- a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h
+++ b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h
@@ -9,8 +9,10 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "base/memory/scoped_refptr.h"
+#include "base/synchronization/lock.h"
 #include "base/test/scoped_path_override.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/error_reporting/chrome_js_error_report_processor.h"
@@ -53,15 +55,13 @@
 #endif
 
  protected:
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  std::vector<std::string> GetCrashReporterArgvStart() override;
+#else
+  // Always returns "7.20.1" (arbitrary).
+  std::string GetOsVersion() override;
   std::string GetCrashEndpoint() override;
   std::string GetCrashEndpointStaging() override;
-
-  // Always returns 7.20.1 (arbitrary).
-  void GetOsVersion(int32_t& os_major_version,
-                    int32_t& os_minor_version,
-                    int32_t& os_bugfix_version) override;
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
   void UpdateReportDatabase(std::string remote_report_id,
                             base::Time report_time) override;
 #endif
diff --git a/chrome/browser/error_reporting/mock_chromeos_crash_reporter.cc b/chrome/browser/error_reporting/mock_chromeos_crash_reporter.cc
new file mode 100644
index 0000000..646b94f
--- /dev/null
+++ b/chrome/browser/error_reporting/mock_chromeos_crash_reporter.cc
@@ -0,0 +1,187 @@
+// 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.
+
+// A simple binary that replicates the crash_reporter / crash_sender
+// functionality of Chrome OS for testing purposes. In particular, it has a
+// stripped-down version of the parsing logic in
+// src/platform2/crash-reporter/chrome_collector.cc, coupled with a simple
+// upload function similar to src/platform2/crash-reporter/crash_sender_util.cc
+// (but without the compression). This is used in tests to substitute for the
+// actual OS crash reporting system.
+
+#include <stdlib.h>
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/files/file.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/task/single_thread_task_executor.h"
+#include "base/threading/thread_restrictions.h"
+#include "chrome/browser/error_reporting/constants.h"
+#include "net/base/escape.h"
+#include "net/http/http_status_code.h"
+#include "third_party/breakpad/breakpad/src/common/linux/libcurl_wrapper.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Parses the key:length:value triplets similar to
+// ChromeCollector::ParseCrashLog. Input is the file descriptor |fd|,
+// return is a list of key/value pairs in |values| and a payload in |payload|.
+//
+// Closes |fd| when done.
+bool ParseTriplets(int fd,
+                   std::map<std::string, std::string>& values,
+                   std::string& payload) {
+  base::File input(fd, false);
+  if (!input.IsValid()) {
+    LOG(ERROR) << "Invalid FD";
+    return false;
+  }
+  if (input.Seek(base::File::FROM_BEGIN, 0) == -1) {
+    LOG(ERROR) << "Seek failed";
+    return false;
+  }
+
+  char buffer[64 * 1024];
+  std::string data;
+  int result = input.ReadAtCurrentPos(buffer, sizeof(buffer));
+  while (result > 0) {
+    data.append(buffer, buffer + result);
+    result = input.ReadAtCurrentPos(buffer, sizeof(buffer));
+  }
+  if (result == -1) {
+    LOG(WARNING) << "Reading failed, may be incomplete";
+  }
+
+  std::string::size_type pos = 0;
+  while (pos < data.size()) {
+    std::string::size_type end_of_key = data.find(':', pos);
+    if (end_of_key == std::string::npos) {
+      LOG(ERROR) << "Incomplete value found, starting at position " << pos;
+      return false;
+    }
+
+    std::string key = data.substr(pos, end_of_key - pos);
+    std::string::size_type end_of_length = data.find(':', end_of_key + 1);
+    if (end_of_length == std::string::npos) {
+      LOG(ERROR) << "Incomplete length found, starting at position "
+                 << (end_of_key + 1);
+      return false;
+    }
+
+    std::string length_string =
+        data.substr(end_of_key + 1, end_of_length - (end_of_key + 1));
+    size_t length;
+    if (!base::StringToSizeT(length_string, &length)) {
+      LOG(ERROR) << "Bad length string '" << length_string << "'";
+      return false;
+    }
+
+    std::string value = data.substr(end_of_length + 1, length);
+    pos = end_of_length + length + 1;
+
+    if (key == kJavaScriptStackKey) {
+      payload = std::move(value);
+    } else {
+      values.emplace(std::move(key), std::move(value));
+    }
+  }
+  return true;
+}
+
+// Upload the error report to the provided URL.
+bool UploadViaHttp(const std::string& base_url,
+                   const std::map<std::string, std::string>& values,
+                   const std::string& payload) {
+  std::vector<std::string> query_parts;
+  for (const auto& kv : values) {
+    query_parts.emplace_back(base::StrCat(
+        {net::EscapeQueryParamValue(kv.first, /*use_plus=*/false), "=",
+         net::EscapeQueryParamValue(kv.second, /*use_plus=*/false)}));
+  }
+  std::string upload_str =
+      base::StrCat({base_url, "?", base::JoinString(query_parts, "&")});
+
+  GURL upload_url(upload_str);
+  if (!upload_url.is_valid()) {
+    LOG(ERROR) << "Invalid upload_to URL: '" << upload_str << "'";
+    return false;
+  }
+
+  // Upload using Breakpad's curl wrapper. The normal Chromium way
+  // (SimpleURLLoader) needs a lot of browser stuff to be set up before it can
+  // be used, so we use the standalone LibcurlWrapper in this test binary.
+  google_breakpad::LibcurlWrapper uploader;
+  if (!uploader.Init()) {
+    LOG(ERROR) << "Libcurl init error";
+    return false;
+  }
+  long http_status_code = 0;
+  std::string http_header_data;
+  std::string http_response_data;
+  if (!uploader.SendSimplePostRequest(upload_url.spec(), payload, "text/plain",
+                                      &http_status_code, &http_header_data,
+                                      &http_response_data)) {
+    LOG(ERROR) << "Libcurl init error";
+    return false;
+  }
+  if (http_status_code != net::HTTP_OK) {
+    LOG(ERROR) << "http response " << http_status_code;
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  base::AtExitManager exit_manager;
+  base::CommandLine::Init(argc, argv);
+  base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+  base::ScopedAllowBaseSyncPrimitivesForTesting allow;
+
+  constexpr char kFdSwitch[] = "chrome_memfd";
+  if (!cmd_line->HasSwitch(kFdSwitch)) {
+    LOG(ERROR) << "No --chrome_memfd";
+    return EXIT_FAILURE;
+  }
+  auto fd_string = cmd_line->GetSwitchValueASCII(kFdSwitch);
+  int fd;
+  if (!base::StringToInt(fd_string, &fd)) {
+    LOG(ERROR) << "Can't parse --chrome_memfd '" << fd_string << "' as int";
+    return EXIT_FAILURE;
+  }
+
+  // Note: This must be a map (not an unordered_map or such) because some unit
+  // tests rely on the order of the parameters in the URL string. Until that's
+  // fixed, keep the values sorted by key in the URL.
+  std::map<std::string, std::string> values;
+  std::string payload;
+  if (!ParseTriplets(fd, values, payload)) {
+    return EXIT_FAILURE;
+  }
+
+  constexpr char kUploadSwitch[] = "upload_to";
+  if (!cmd_line->HasSwitch(kUploadSwitch)) {
+    LOG(ERROR) << "No --upload_to";
+    return EXIT_FAILURE;
+  }
+  std::string base_url = cmd_line->GetSwitchValueASCII(kUploadSwitch);
+  if (!UploadViaHttp(base_url, values, payload)) {
+    return EXIT_FAILURE;
+  }
+
+  return EXIT_SUCCESS;
+}
diff --git a/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc b/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc
index 7885eb3..04d813e 100644
--- a/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc
+++ b/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.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/constants/ash_features.h"
 #include "base/system/sys_info.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_clock.h"
@@ -11,7 +12,6 @@
 #include "chrome/browser/extensions/api/crash_report_private/crash_report_private_api.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/crash/content/browser/error_reporting/mock_crash_endpoint.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/browser_test.h"
@@ -119,7 +119,7 @@
                    "\\d+&browser_"
                    "version=1.2.3.4&channel=Stable&"
                    "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2F&"
-                   "os=ChromeOS&os_version=7.20.1"
+                   "os=ChromeOS"
                    "&prod=Chrome_ChromeOS&renderer_process_uptime_ms=\\d+&src="
                    "http%3A%2F%2Fwww.test."
                    "com%2F&type=JavascriptError&url=%2F&ver=1.2.3.4"));
@@ -151,7 +151,7 @@
                    "\\d+&browser_"
                    "version=1.2.3.4&channel=Stable&column=456&"
                    "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2Ffoo"
-                   "&line=123&os=ChromeOS&os_version=7.20.1"
+                   "&line=123&os=ChromeOS"
                    "&prod=Chrome%2520\\(Chrome%2520OS\\)&renderer_process_"
                    "uptime_ms=\\d+&"
                    "src=http%3A%2F%2Fwww.test.com%2Ffoo&"
@@ -182,7 +182,7 @@
                    "\\d+&browser_version=1.2."
                    "3.4&channel=Stable&column=456&"
                    "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2Ffoo&"
-                   "line=123&os=ChromeOS&os_version=7.20.1"
+                   "line=123&os=ChromeOS"
                    "&prod=TestApp&renderer_process_uptime_ms=\\d+&src=http%3A%"
                    "2F%2Fwww.test.com%2Ffoo&type="
                    "JavascriptError&url=%2Ffoo&ver=1.0.0.0"));
@@ -214,8 +214,7 @@
           "browser_version=1.2."
           "3.4&channel=Stable&column=456&"
           "error_message=%5BMAC%20OUI%3D06%3A00%3A00%20IFACE%3D1%5D&"
-          "full_url=http%3A%2F%2Fwww.test.com%2Ffoo&line=123&os=ChromeOS&"
-          "os_version=7.20.1"
+          "full_url=http%3A%2F%2Fwww.test.com%2Ffoo&line=123&os=ChromeOS"
           "&prod=TestApp&renderer_process_uptime_ms=\\d+&src=http%3A%2F%2Fwww."
           "test.com%2Ffoo&type="
           "JavascriptError&url=%2Ffoo&ver=1.0.0.0"));
@@ -255,27 +254,6 @@
   ASSERT_FALSE(report);
 }
 
-// Ensures that reportError checks user consent for data collection on the
-// correct thread and correctly handles the case where consent is not given.
-IN_PROC_BROWSER_TEST_F(CrashReportPrivateApiTest, NoConsent) {
-  constexpr char kTestScript[] = R"(
-    chrome.crashReportPrivate.reportError({
-        message: "hi",
-        url: "http://www.test.com",
-      },
-      () => {
-        window.domAutomationController.send(chrome.runtime.lastError ?
-            chrome.runtime.lastError.message : "")
-      });
-  )";
-
-  crash_endpoint_->set_consented(false);
-  EXPECT_EQ("", ExecuteScriptInBackgroundPage(extension_->id(), kTestScript));
-  // The server should not receive any reports.
-  const base::Optional<MockCrashEndpoint::Report>& report = last_report();
-  EXPECT_FALSE(report);
-}
-
 // Test REGULAR_TABBED is detected when |CrashReportPrivate| is called from a
 // tab's |web_contents|.
 IN_PROC_BROWSER_TEST_F(CrashReportPrivateApiTest, CalledFromWebContentsInTab) {
@@ -306,7 +284,7 @@
                    "\\d+&browser_"
                    "version=1.2.3.4&channel=Stable&"
                    "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2F&"
-                   "os=ChromeOS&os_version=7.20.1"
+                   "os=ChromeOS"
                    "&prod=Chrome_ChromeOS&renderer_process_uptime_ms=\\d+&src="
                    "http%3A%2F%2Fwww.test."
                    "com%2F&type=JavascriptError&url=%2F&ver=1.2.3.4&window_"
@@ -356,7 +334,7 @@
                    "\\d+&browser_"
                    "version=1.2.3.4&channel=Stable&"
                    "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2F&"
-                   "os=ChromeOS&os_version=7.20.1"
+                   "os=ChromeOS"
                    "&prod=Chrome_ChromeOS&renderer_process_uptime_ms=\\d+&src="
                    "http%3A%2F%2Fwww.test."
                    "com%2F&type=JavascriptError&url=%2F&ver=1.2.3.4&window_"
@@ -390,7 +368,7 @@
                    "\\d+&browser_"
                    "version=1.2.3.4&channel=Stable&"
                    "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2F&"
-                   "os=ChromeOS&os_version=7.20.1"
+                   "os=ChromeOS"
                    "&prod=Chrome_ChromeOS&renderer_process_uptime_ms=\\d+&src="
                    "http%3A%2F%2Fwww.test."
                    "com%2F&type=JavascriptError&url=%2F&ver=1.2.3.4&window_"
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
index 8b8eb261..d6432924 100644
--- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
+++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -4432,8 +4432,10 @@
   EXPECT_FALSE(prefs->GetDNRDynamicRulesetChecksum(extension_id, &checksum));
 }
 
-// Tests the allowAllRequests action.
-IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, AllowAllRequests) {
+// Fixture to test the "allowAllRequests" action.
+class DeclarativeNetRequestAllowAllRequestsBrowserTest
+    : public DeclarativeNetRequestBrowserTest {
+ public:
   struct RuleData {
     int id;
     int priority;
@@ -4443,11 +4445,11 @@
     base::Optional<std::vector<std::string>> resource_types;
   };
 
-  auto run_test = [this](const std::string& extension_directory,
-                         const GURL& page_url,
-                         const std::vector<RuleData>& rule_data,
-                         const std::vector<std::string>& paths_seen,
-                         const std::vector<std::string>& paths_not_seen) {
+  DeclarativeNetRequestAllowAllRequestsBrowserTest() = default;
+
+  void RunTest(const std::vector<RuleData>& rule_data,
+               const std::vector<std::string>& paths_seen,
+               const std::vector<std::string>& paths_not_seen) {
     std::vector<TestRule> test_rules;
     for (const auto& rule : rule_data) {
       TestRule test_rule = CreateGenericRule();
@@ -4463,9 +4465,10 @@
       test_rules.push_back(test_rule);
     }
 
-    ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules(
-        test_rules, extension_directory, {} /* hosts */));
+    ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules(test_rules));
 
+    GURL page_url = embedded_test_server()->GetURL(
+        "example.com", "/page_with_two_frames.html");
     ui_test_utils::NavigateToURL(browser(), page_url);
 
     const std::set<GURL> requests_seen = GetAndResetRequestsToServer();
@@ -4482,13 +4485,11 @@
       EXPECT_FALSE(base::Contains(requests_seen, expected_request_url))
           << expected_request_url.spec() << " request seen unexpectedly.";
     }
+  }
 
-    UninstallExtension(last_loaded_extension_id());
-  };
-
-  // This page causes the following requests.
-  GURL page_url = embedded_test_server()->GetURL("example.com",
-                                                 "/page_with_two_frames.html");
+ protected:
+  // Requests made when the browser is navigated to
+  // "http://example.com/page_with_two_frames.html".
   std::vector<std::string> requests = {
       {"/page_with_two_frames.html"},         // 0
       {"/subresources/script.js"},            // 1
@@ -4497,90 +4498,91 @@
       {"/child_frame.html?frame=2"},          // 4
       {"/subresources/script.js?frameId=2"},  // 5
   };
+};
 
-  {
-    SCOPED_TRACE("Testing case 1");
-    std::vector<RuleData> rule_data = {
-        {1, 4, "allowAllRequests", "page_with_two_frames\\.html", true,
-         std::vector<std::string>({"main_frame"})},
-        {2, 3, "block", "script.js|", false},
-        {3, 5, "block", "script.js?frameId=1", false},
-        {4, 3, "block", "script\\.js?frameId=2", true}};
-    // Requests:
-    // -/page_with_two_frames.html (Matching rule=1)
-    //   -/subresources/script.js (Matching rule=[1,2] Winner=1)
-    //   -/child_frame.html?frame=1 (Matching Rule=1)
-    //     -/subresources/script.js?frameId=1 (Matching Rule=[1,3] Winner=3)
-    //   -/child_frame.html?frame=2 (Matching Rule=1)
-    //     -/subresources/script.js?frameId=2 (Matching Rule=1,4 Winner=1)
-    // Hence only requests[3] is blocked.
-    run_test("case_1", page_url, rule_data,
-             {requests[0], requests[1], requests[2], requests[4], requests[5]},
-             {requests[3]});
-  }
+IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestAllowAllRequestsBrowserTest,
+                       Test1) {
+  std::vector<RuleData> rule_data = {
+      {1, 4, "allowAllRequests", "page_with_two_frames\\.html", true,
+       std::vector<std::string>({"main_frame"})},
+      {2, 3, "block", "script.js|", false},
+      {3, 5, "block", "script.js?frameId=1", false},
+      {4, 3, "block", "script\\.js?frameId=2", true}};
 
-  {
-    SCOPED_TRACE("Testing case 2");
-    std::vector<RuleData> rule_data = {
-        {1, 4, "allowAllRequests", "page_with_two_frames.html", false,
-         std::vector<std::string>({"main_frame"})},
-        {2, 5, "block", "script\\.js", true},
-        {3, 6, "allowAllRequests", "child_frame.html", false,
-         std::vector<std::string>({"sub_frame"})},
-        {4, 7, "block", "frame=1", true}};
+  // Requests:
+  // -/page_with_two_frames.html (Matching rule=1)
+  //   -/subresources/script.js (Matching rule=[1,2] Winner=1)
+  //   -/child_frame.html?frame=1 (Matching Rule=1)
+  //     -/subresources/script.js?frameId=1 (Matching Rule=[1,3] Winner=3)
+  //   -/child_frame.html?frame=2 (Matching Rule=1)
+  //     -/subresources/script.js?frameId=2 (Matching Rule=1,4 Winner=1)
+  // Hence only requests[3] is blocked.
+  RunTest(rule_data,
+          {requests[0], requests[1], requests[2], requests[4], requests[5]},
+          {requests[3]});
+}
 
-    // Requests:
-    // -/page_with_two_frames.html (Matching rule=1)
-    //   -/subresources/script.js (Matching rule=[1,2] Winner=2, Blocked)
-    //   -/child_frame.html?frame=1 (Matching Rule=[1,3,4] Winner=4, Blocked)
-    //     -/subresources/script.js?frameId=1 (Source Frame was blocked)
-    //   -/child_frame.html?frame=2 (Matching Rule=[1,3] Winner=3)
-    //     -/subresources/script.js?frameId=2 (Matching Rule=[1,2,3] Winner=3)
-    run_test("case_2", page_url, rule_data,
-             {requests[0], requests[4], requests[5]},
-             {requests[1], requests[2], requests[3]});
-  }
+IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestAllowAllRequestsBrowserTest,
+                       Test2) {
+  std::vector<RuleData> rule_data = {
+      {1, 4, "allowAllRequests", "page_with_two_frames.html", false,
+       std::vector<std::string>({"main_frame"})},
+      {2, 5, "block", "script\\.js", true},
+      {3, 6, "allowAllRequests", "child_frame.html", false,
+       std::vector<std::string>({"sub_frame"})},
+      {4, 7, "block", "frame=1", true}};
 
-  {
-    SCOPED_TRACE("Testing case 3");
-    std::vector<RuleData> rule_data = {
-        {1, 1, "allowAllRequests", "page_with_two_frames.html", false,
-         std::vector<std::string>({"main_frame"})},
-        {2, 5, "block", ".*", true},
-    };
+  // Requests:
+  // -/page_with_two_frames.html (Matching rule=1)
+  //   -/subresources/script.js (Matching rule=[1,2] Winner=2, Blocked)
+  //   -/child_frame.html?frame=1 (Matching Rule=[1,3,4] Winner=4, Blocked)
+  //     -/subresources/script.js?frameId=1 (Source Frame was blocked)
+  //   -/child_frame.html?frame=2 (Matching Rule=[1,3] Winner=3)
+  //     -/subresources/script.js?frameId=2 (Matching Rule=[1,2,3] Winner=3)
+  RunTest(rule_data, {requests[0], requests[4], requests[5]},
+          {requests[1], requests[2], requests[3]});
+}
 
-    // Requests:
-    // -/page_with_two_frames.html (Matching rule=1)
-    //   -/subresources/script.js (Matching rule=[1,2] Winner=2)
-    //   -/child_frame.html?frame=1 (Matching Rule=[1,2] Winner=2)
-    //     -/subresources/script.js?frameId=1 (Source Frame was blocked)
-    //   -/child_frame.html?frame=2 (Matching Rule=[1,2] Winner=2)
-    //     -/subresources/script.js?frameId=2 (Source frame was blocked)
-    // Hence only the main-frame request goes through.
-    run_test("case_3", page_url, rule_data, {requests[0]},
-             {requests[1], requests[2], requests[3], requests[4], requests[5]});
-  }
-  {
-    SCOPED_TRACE("Testing case 4");
-    std::vector<RuleData> rule_data = {
-        {1, 6, "allowAllRequests", "page_with_two_frames\\.html", true,
-         std::vector<std::string>({"main_frame"})},
-        {2, 5, "block", "*", false},
-    };
+IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestAllowAllRequestsBrowserTest,
+                       Test3) {
+  std::vector<RuleData> rule_data = {
+      {1, 1, "allowAllRequests", "page_with_two_frames.html", false,
+       std::vector<std::string>({"main_frame"})},
+      {2, 5, "block", ".*", true},
+  };
 
-    // Requests:
-    // -/page_with_two_frames.html (Matching rule=1)
-    //   -/subresources/script.js (Matching rule=[1,2] Winner=1)
-    //   -/child_frame.html?frame=1 (Matching Rule=[1,2] Winner=1)
-    //     -/subresources/script.js?frameId=1 (Matching Rule=[1,2] Winner=1)
-    //   -/child_frame.html?frame=2 (Matching Rule=[1,2] Winner=1)
-    //     -/subresources/script.js?frameId=2 (Matching Rule=[1,2] Winner=1)
-    // Hence all requests go through.
-    run_test("case_4", page_url, rule_data,
-             {requests[0], requests[1], requests[2], requests[3], requests[4],
-              requests[5]},
-             {});
-  }
+  // Requests:
+  // -/page_with_two_frames.html (Matching rule=1)
+  //   -/subresources/script.js (Matching rule=[1,2] Winner=2)
+  //   -/child_frame.html?frame=1 (Matching Rule=[1,2] Winner=2)
+  //     -/subresources/script.js?frameId=1 (Source Frame was blocked)
+  //   -/child_frame.html?frame=2 (Matching Rule=[1,2] Winner=2)
+  //     -/subresources/script.js?frameId=2 (Source frame was blocked)
+  // Hence only the main-frame request goes through.
+  RunTest(rule_data, {requests[0]},
+          {requests[1], requests[2], requests[3], requests[4], requests[5]});
+}
+
+IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestAllowAllRequestsBrowserTest,
+                       Test4) {
+  std::vector<RuleData> rule_data = {
+      {1, 6, "allowAllRequests", "page_with_two_frames\\.html", true,
+       std::vector<std::string>({"main_frame"})},
+      {2, 5, "block", "*", false},
+  };
+
+  // Requests:
+  // -/page_with_two_frames.html (Matching rule=1)
+  //   -/subresources/script.js (Matching rule=[1,2] Winner=1)
+  //   -/child_frame.html?frame=1 (Matching Rule=[1,2] Winner=1)
+  //     -/subresources/script.js?frameId=1 (Matching Rule=[1,2] Winner=1)
+  //   -/child_frame.html?frame=2 (Matching Rule=[1,2] Winner=1)
+  //     -/subresources/script.js?frameId=2 (Matching Rule=[1,2] Winner=1)
+  // Hence all requests go through.
+  RunTest(rule_data,
+          {requests[0], requests[1], requests[2], requests[3], requests[4],
+           requests[5]},
+          {});
 }
 
 // Tests that when an extension is updated but loses the declarativeNetRequest
@@ -5573,6 +5575,11 @@
                          DeclarativeNetRequestGlobalRulesBrowserTest_Packed,
                          ::testing::Values(ExtensionLoadType::PACKED));
 
+INSTANTIATE_TEST_SUITE_P(All,
+                         DeclarativeNetRequestAllowAllRequestsBrowserTest,
+                         ::testing::Values(ExtensionLoadType::PACKED,
+                                           ExtensionLoadType::UNPACKED));
+
 }  // namespace
 }  // namespace declarative_net_request
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
index 35be68af..a2a1df00 100644
--- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
+++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
@@ -47,8 +47,8 @@
 #include "ui/base/l10n/l10n_util_collator.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/ime/chromeos/component_extension_ime_manager.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
index 2411272..22a6cec6 100644
--- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
+++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/clipboard_history_controller.h"
 #include "ash/public/cpp/clipboard_image_model_factory.h"
 #include "ash/public/cpp/keyboard/keyboard_switches.h"
@@ -26,7 +27,6 @@
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
 #include "chrome/common/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/audio_service.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index f5d4d6e..3ef5c9b 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -51,9 +51,9 @@
 #include "ui/base/resource/resource_bundle.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "ash/keyboard/ui/grit/keyboard_resources.h"
 #include "base/system/sys_info.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/user_manager/user_manager.h"
diff --git a/chrome/browser/extensions/execute_script_apitest.cc b/chrome/browser/extensions/execute_script_apitest.cc
index 7c34ee2..d38f1a3 100644
--- a/chrome/browser/extensions/execute_script_apitest.cc
+++ b/chrome/browser/extensions/execute_script_apitest.cc
@@ -80,6 +80,12 @@
 
 // If failing, mark disabled and update http://crbug.com/84760.
 IN_PROC_BROWSER_TEST_P(ExecuteScriptApiTest, ExecuteScriptFileAfterClose) {
+  // TODO(https://crbug.com/1166287): Flaky for Service Worker-based
+  // extension on ASAN bots.
+#if defined(ADDRESS_SANITIZER)
+  if (GetParam() == ContextType::kServiceWorker)
+    return;
+#endif
   ASSERT_TRUE(RunTest("executescript/file_after_close")) << message_;
 }
 
diff --git a/chrome/browser/extensions/external_pref_loader.cc b/chrome/browser/extensions/external_pref_loader.cc
index fdd01cd..c65c2077 100644
--- a/chrome/browser/extensions/external_pref_loader.cc
+++ b/chrome/browser/extensions/external_pref_loader.cc
@@ -29,9 +29,9 @@
 #include "extensions/browser/extension_file_task_runner.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/prefs/pref_change_registrar.h"
diff --git a/chrome/browser/extensions/external_pref_loader_unittest.cc b/chrome/browser/extensions/external_pref_loader_unittest.cc
index 34ed2c66..421d0dd 100644
--- a/chrome/browser/extensions/external_pref_loader_unittest.cc
+++ b/chrome/browser/extensions/external_pref_loader_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
@@ -15,7 +16,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/driver/test_sync_service.h"
diff --git a/chrome/browser/extensions/external_provider_impl_chromeos_unittest.cc b/chrome/browser/extensions/external_provider_impl_chromeos_unittest.cc
index 2512b81..13610ec 100644
--- a/chrome/browser/extensions/external_provider_impl_chromeos_unittest.cc
+++ b/chrome/browser/extensions/external_provider_impl_chromeos_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
@@ -25,7 +26,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "chromeos/system/fake_statistics_provider.h"
 #include "chromeos/system/statistics_provider.h"
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 0f6dd8f6..18e164d3 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1607,6 +1607,11 @@
     "expiry_milestone": 91
   },
   {
+    "name": "enable-experimental-accessibility-switch-access-setup-guide",
+    "owners": ["ansatasi@google.com", "josiahk@google.com", "//ui/accessibility/OWNERS"],
+    "expiry_milestone": 92
+  },
+  {
     "name": "enable-experimental-accessibility-switch-access-text",
     "owners": [ "anastasi@google.com", "//ui/accessibility/OWNERS" ],
     "expiry_milestone": 90
@@ -3431,6 +3436,11 @@
     "expiry_milestone": 92
   },
   {
+    "name": "mojo-linux-sharedmem",
+    "owners": ["bgeffon", "rockot"],
+    "expiry_milestone": 99
+  },
+  {
     "name": "mouse-subframe-no-implicit-capture",
     "owners": [ "eirage", "nzolghadr", "input-dev" ],
     "expiry_milestone": 84
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 62d3248..e46f755 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -658,11 +658,11 @@
 extern const char kDesktopPWAsAttentionBadgingCrOSDescription[] =
     "Enable attention badging for PWA icons in the shelf and launcher.";
 extern const char kDesktopPWAsAttentionBadgingCrOSApiAndNotifications[] =
-    "Enable for Badging API and notifications";
+    "for Badging API and notifications";
 extern const char kDesktopPWAsAttentionBadgingCrOSApiOnly[] =
-    "Enable for Badging API only";
+    "for Badging API only";
 extern const char kDesktopPWAsAttentionBadgingCrOSNotificationsOnly[] =
-    "Enable for notifications only";
+    "for notifications only";
 
 const char kDesktopPWAsRemoveStatusBarName[] = "Desktop PWAs remove status bar";
 const char kDesktopPWAsRemoveStatusBarDescription[] =
@@ -1433,6 +1433,12 @@
 const char kMobilePwaInstallUseBottomSheetDescription[] =
     "Enables use of a rich bottom sheet when offering mobile PWA installation.";
 
+const char kMojoLinuxChannelSharedMemName[] =
+    "Enable Mojo Shared Memory Channel";
+const char kMojoLinuxChannelSharedMemDescription[] =
+    "If enabled Mojo on Linux based platforms can use shared memory as an "
+    "alternate channel for most messages.";
+
 const char kMouseSubframeNoImplicitCaptureName[] =
     "Disable mouse implicit capture for iframe";
 const char kMouseSubframeNoImplicitCaptureDescription[] =
@@ -4300,6 +4306,12 @@
     "Enable an in-process feature to select points onscreen with Switch "
     "Access.";
 
+const char kExperimentalAccessibilitySwitchAccessSetupGuideName[] =
+    "Enable setup guide for Switch Access.";
+const char kExperimentalAccessibilitySwitchAccessSetupGuideDescription[] =
+    "Enable a setup guide to walk through the steps of initially configuring "
+    "Switch Access.";
+
 const char kMagnifierNewFocusFollowingName[] =
     "Enable new focus following in Magnifier";
 const char kMagnifierNewFocusFollowingDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 7f4dc8a..8afa4ab3 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -847,6 +847,9 @@
 extern const char kMobilePwaInstallUseBottomSheetName[];
 extern const char kMobilePwaInstallUseBottomSheetDescription[];
 
+extern const char kMojoLinuxChannelSharedMemName[];
+extern const char kMojoLinuxChannelSharedMemDescription[];
+
 extern const char kMouseSubframeNoImplicitCaptureName[];
 extern const char kMouseSubframeNoImplicitCaptureDescription[];
 
@@ -2511,6 +2514,9 @@
 extern const char kSwitchAccessPointScanningName[];
 extern const char kSwitchAccessPointScanningDescription[];
 
+extern const char kExperimentalAccessibilitySwitchAccessSetupGuideName[];
+extern const char kExperimentalAccessibilitySwitchAccessSetupGuideDescription[];
+
 extern const char kMagnifierNewFocusFollowingName[];
 extern const char kMagnifierNewFocusFollowingDescription[];
 
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 9aa5233..e18eb507 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
@@ -24,6 +24,23 @@
 static constexpr const char* kDiscoveryOnlyModelNames[3] = {
     "eureka dongle", "chromecast audio", "chromecast ultra"};
 
+std::string EnumToString(DialRegistry::DialErrorCode code) {
+  switch (code) {
+    case DialRegistry::DialErrorCode::DIAL_NO_LISTENERS:
+      return "DIAL_NO_LISTENERS";
+    case DialRegistry::DialErrorCode::DIAL_NO_INTERFACES:
+      return "DIAL_NO_INTERFACES";
+    case DialRegistry::DialErrorCode::DIAL_NETWORK_DISCONNECTED:
+      return "DIAL_NETWORK_DISCONNECTED";
+    case DialRegistry::DialErrorCode::DIAL_CELLULAR_NETWORK:
+      return "DIAL_CELLULAR_NETWORK";
+    case DialRegistry::DialErrorCode::DIAL_SOCKET_ERROR:
+      return "DIAL_SOCKET_ERROR";
+    case DialRegistry::DialErrorCode::DIAL_UNKNOWN:
+      return "DIAL_UNKNOWN";
+  }
+}
+
 // Returns true if DIAL (SSDP) was only used to discover this sink, and it is
 // not expected to support other DIAL features (app discovery, activity
 // discovery, etc.)
@@ -182,10 +199,9 @@
 void DialMediaSinkServiceImpl::OnDialError(DialRegistry::DialErrorCode type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (logger_.is_bound()) {
-    logger_->LogError(
-        mojom::LogCategory::kDiscovery, kLoggerComponent,
-        base::StringPrintf("DialErrorCode: %d", static_cast<int>(type)), "", "",
-        "");
+    logger_->LogError(mojom::LogCategory::kDiscovery, kLoggerComponent,
+                      base::StrCat({"Dial Error: ", EnumToString(type)}), "",
+                      "", "");
   }
 }
 
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 c59d4d8..88a4d87 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
@@ -53,6 +53,30 @@
   return MediaSinkInternal(sink, extra_data);
 }
 
+std::string EnumToString(MediaRouterChannelError error) {
+  switch (error) {
+    case MediaRouterChannelError::UNKNOWN:
+      return "UNKNOWN";
+    case MediaRouterChannelError::AUTHENTICATION:
+      return "AUTHENTICATION";
+    case MediaRouterChannelError::CONNECT:
+      return "CONNECT";
+    case MediaRouterChannelError::GENERAL_CERTIFICATE:
+      return "GENERAL_CERTIFICATE";
+    case MediaRouterChannelError::CERTIFICATE_TIMING:
+      return "CERTIFICATE_TIMING";
+    case MediaRouterChannelError::NETWORK:
+      return "NETWORK";
+    case MediaRouterChannelError::CONNECT_TIMEOUT:
+      return "CONNECT_TIMEOUT";
+    case MediaRouterChannelError::PING_TIMEOUT:
+      return "PING_TIMEOUT";
+    case MediaRouterChannelError::TOTAL_COUNT:
+      NOTREACHED();
+      return "";
+  }
+}
+
 MediaRouterChannelError RecordError(cast_channel::ChannelError channel_error,
                                     cast_channel::LastError last_error) {
   MediaRouterChannelError error_code = MediaRouterChannelError::UNKNOWN;
@@ -329,8 +353,8 @@
   if (logger_.is_bound()) {
     auto sink_id = sink_it == sinks.end() ? "" : sink_it->first;
     logger_->LogError(mojom::LogCategory::kDiscovery, kLoggerComponent,
-                      base::StringPrintf("MediaRouterChannelError: %d",
-                                         static_cast<int>(error_code)),
+                      base::StrCat({"Media Router Channel Error: ",
+                                    EnumToString(error_code)}),
                       sink_id, "", "");
   }
   if (sink_it == sinks.end()) {
diff --git a/chrome/browser/metrics/ambient_mode_metrics_provider.cc b/chrome/browser/metrics/ambient_mode_metrics_provider.cc
index da1deac8..5ebe546 100644
--- a/chrome/browser/metrics/ambient_mode_metrics_provider.cc
+++ b/chrome/browser/metrics/ambient_mode_metrics_provider.cc
@@ -4,12 +4,12 @@
 
 #include "chrome/browser/metrics/ambient_mode_metrics_provider.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ambient/ambient_client.h"
 #include "ash/public/cpp/ambient/ambient_metrics.h"
 #include "ash/public/cpp/ambient/ambient_prefs.h"
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 
 namespace {
diff --git a/chrome/browser/metrics/chromeos_metrics_provider.cc b/chrome/browser/metrics/chromeos_metrics_provider.cc
index 47988ff..ae06e32 100644
--- a/chrome/browser/metrics/chromeos_metrics_provider.cc
+++ b/chrome/browser/metrics/chromeos_metrics_provider.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -34,7 +35,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client.h"
 #include "chromeos/system/statistics_provider.h"
diff --git a/chrome/browser/metrics/perf/metric_provider.cc b/chrome/browser/metrics/perf/metric_provider.cc
index f04435b..4727230 100644
--- a/chrome/browser/metrics/perf/metric_provider.cc
+++ b/chrome/browser/metrics/perf/metric_provider.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/metrics/perf/metric_provider.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/task/post_task.h"
@@ -13,7 +14,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/sync/base/user_selectable_type.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/driver/sync_user_settings.h"
diff --git a/chrome/browser/metrics/perf/metric_provider_unittest.cc b/chrome/browser/metrics/perf/metric_provider_unittest.cc
index d2d8a544..70ba89b 100644
--- a/chrome/browser/metrics/perf/metric_provider_unittest.cc
+++ b/chrome/browser/metrics/perf/metric_provider_unittest.cc
@@ -11,6 +11,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/test/bind.h"
@@ -21,7 +22,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/constants/chromeos_features.h"
 #include "components/sync/base/user_selectable_type.h"
 #include "components/sync/driver/test_sync_service.h"
 #include "content/public/test/browser_task_environment.h"
diff --git a/chrome/browser/net/net_error_diagnostics_dialog_chromeos.cc b/chrome/browser/net/net_error_diagnostics_dialog_chromeos.cc
index b4d19307..6793e18 100644
--- a/chrome/browser/net/net_error_diagnostics_dialog_chromeos.cc
+++ b/chrome/browser/net/net_error_diagnostics_dialog_chromeos.cc
@@ -5,12 +5,12 @@
 #include "chrome/browser/net/net_error_diagnostics_dialog.h"
 
 #include "apps/launcher.h"
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h"
 #include "chromeos/components/connectivity_diagnostics/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "extensions/browser/extension_registry.h"
 
 bool CanShowNetworkDiagnosticsDialog(content::WebContents* web_contents) {
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index 0ccb745..951c9cdd 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -23,8 +23,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
-#include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
-#include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h"
 #include "chrome/browser/domain_reliability/service_factory.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/profile.h"
@@ -62,6 +60,7 @@
 #include "third_party/blink/public/common/features.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
@@ -70,7 +69,6 @@
 #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
@@ -813,15 +811,6 @@
                   metrics::prefs::kMetricsReportingEnabled);
   }
 
-  auto* drp_settings =
-      DataReductionProxyChromeSettingsFactory::GetForBrowserContext(profile_);
-  if (drp_settings) {
-    mojo::Remote<network::mojom::CustomProxyConfigClient> config_client;
-    network_context_params->custom_proxy_config_client_receiver =
-        config_client.BindNewPipeAndPassReceiver();
-    drp_settings->AddCustomProxyConfigClient(std::move(config_client));
-  }
-
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   bool profile_supports_policy_certs = false;
   if (chromeos::ProfileHelper::IsSigninProfile(profile_))
diff --git a/chrome/browser/net/profile_network_context_service_browsertest.cc b/chrome/browser/net/profile_network_context_service_browsertest.cc
index c089bcf..ebcbc59a 100644
--- a/chrome/browser/net/profile_network_context_service_browsertest.cc
+++ b/chrome/browser/net/profile_network_context_service_browsertest.cc
@@ -71,7 +71,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif
 
 // Most tests for this class are in NetworkContextConfigurationBrowserTest.
diff --git a/chrome/browser/performance_manager/policies/policy_features.cc b/chrome/browser/performance_manager/policies/policy_features.cc
index ba62f68..6578c7c8 100644
--- a/chrome/browser/performance_manager/policies/policy_features.cc
+++ b/chrome/browser/performance_manager/policies/policy_features.cc
@@ -125,7 +125,8 @@
 
 const base::Feature kUrgentDiscardingFromPerformanceManager{
   "UrgentDiscardingFromPerformanceManager",
-#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_LINUX)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) || \
+    defined(OS_LINUX)
       base::FEATURE_DISABLED_BY_DEFAULT
 #else
       base::FEATURE_ENABLED_BY_DEFAULT
diff --git a/chrome/browser/policy/extension_policy_browsertest.cc b/chrome/browser/policy/extension_policy_browsertest.cc
index 19b8408..20db587 100644
--- a/chrome/browser/policy/extension_policy_browsertest.cc
+++ b/chrome/browser/policy/extension_policy_browsertest.cc
@@ -72,10 +72,10 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/extensions/updater/local_extension_cache.h"
 #include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h"
 #include "chrome/browser/web_applications/components/web_app_id_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #endif
 
diff --git a/chrome/browser/policy/system_features_policy_browsertest.cc b/chrome/browser/policy/system_features_policy_browsertest.cc
index 9347bbc..11dabf8 100644
--- a/chrome/browser/policy/system_features_policy_browsertest.cc
+++ b/chrome/browser/policy/system_features_policy_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/constants/ash_features.h"
 #include "base/values.h"
 #include "chrome/browser/apps/app_service/app_icon_factory.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
@@ -15,7 +16,6 @@
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/policy/core/common/policy_pref_names.h"
 #include "components/policy/policy_constants.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 4dfe345c..558eb37c 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -385,6 +385,11 @@
 #include "components/os_crypt/os_crypt.h"
 #endif
 
+#if defined(OS_WIN) || defined(OS_MAC) || \
+    (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS))
+#include "chrome/browser/web_applications/components/url_handler_prefs.h"
+#endif
+
 // TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
 // of lacros-chrome is complete.
 #if defined(OS_WIN) || defined(OS_MAC) || \
@@ -530,6 +535,10 @@
 // Deprecated 01/2021
 const char kGoogleServicesHostedDomain[] = "google.services.hosted_domain";
 
+const char kDataReductionProxyLastConfigRetrievalTime[] =
+    "data_reduction.last_config_retrieval_time";
+const char kDataReductionProxyConfig[] = "data_reduction.config";
+
 // Register local state used only for migration (clearing or moving to a new
 // key).
 void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) {
@@ -627,6 +636,9 @@
   registry->RegisterBooleanPref(kAssistantQuickAnswersEnabled, true);
 
   registry->RegisterStringPref(kGoogleServicesHostedDomain, std::string());
+
+  registry->RegisterInt64Pref(kDataReductionProxyLastConfigRetrievalTime, 0L);
+  registry->RegisterStringPref(kDataReductionProxyConfig, std::string());
 }
 
 }  // namespace
@@ -818,6 +830,11 @@
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #endif  // defined(OS_WIN)
 
+#if defined(OS_WIN) || defined(OS_MAC) || \
+    (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS))
+  web_app::UrlHandlerPrefs::RegisterLocalStatePrefs(registry);
+#endif
+
 #if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
   RegisterDefaultBrowserPromptPrefs(registry);
   downgrade::RegisterPrefs(registry);
@@ -1281,6 +1298,8 @@
 
   // Added 01/2021
   profile_prefs->ClearPref(kGoogleServicesHostedDomain);
+  profile_prefs->ClearPref(kDataReductionProxyLastConfigRetrievalTime);
+  profile_prefs->ClearPref(kDataReductionProxyConfig);
 
   // Please don't delete the following line. It is used by PRESUBMIT.py.
   // END_MIGRATE_OBSOLETE_PROFILE_PREFS
diff --git a/chrome/browser/profiles/gaia_info_update_service.cc b/chrome/browser/profiles/gaia_info_update_service.cc
index 0d80062..eae6eea 100644
--- a/chrome/browser/profiles/gaia_info_update_service.cc
+++ b/chrome/browser/profiles/gaia_info_update_service.cc
@@ -31,7 +31,7 @@
 #include "ui/gfx/image/image.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif
 
 GAIAInfoUpdateService::GAIAInfoUpdateService(
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 c4c093b0..d6b0d94 100644
--- a/chrome/browser/renderer_context_menu/quick_answers_menu_observer.cc
+++ b/chrome/browser/renderer_context_menu/quick_answers_menu_observer.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/assistant/controller/assistant_interaction_controller.h"
 #include "ash/public/cpp/quick_answers/controller/quick_answers_controller.h"
 #include "base/metrics/histogram_functions.h"
@@ -17,7 +18,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/components/quick_answers/quick_answers_model.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/assistant/public/cpp/assistant_service.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/prefs/pref_service.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 49ce57f..836f950 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
@@ -4,6 +4,7 @@
 
 #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 "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
@@ -12,7 +13,6 @@
 #include "chrome/test/base/chrome_test_utils.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/components/quick_answers/test/test_helpers.h"
-#include "chromeos/constants/chromeos_features.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/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index d41e46f..5bdf364 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -219,12 +219,12 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/clipboard_history_controller.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/arc/intent_helper/open_with_menu.h"
 #include "chrome/browser/chromeos/arc/intent_helper/start_smart_selection_action_menu.h"
 #include "chrome/browser/renderer_context_menu/quick_answers_menu_observer.h"
-#include "chromeos/constants/chromeos_features.h"
 #endif
 
 using base::UserMetricsAction;
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index 201d3733..c100091 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -29,6 +29,7 @@
       "downloads:resources",
       "gaia_auth_host:resources",
       "history:resources",
+      "memories:resources",
       "new_tab_page:resources",
       "read_later:resources",
       "settings:resources",
@@ -104,6 +105,7 @@
         "local_state:closure_compile",
         "management:closure_compile",
         "media_router:closure_compile",
+        "memories:closure_compile",
         "nearby_internals:closure_compile",
         "new_tab_page:closure_compile",
         "ntp4:closure_compile",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
index 00887c15..a4a7aa10 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -33,7 +33,6 @@
   "background/annotation/node_identifier.js",
   "background/annotation/user_annotation_handler.js",
   "background/automation_object_constructor_installer.js",
-  "background/background.js",
   "background/base_automation_handler.js",
   "background/braille_background.js",
   "background/braille_captions_background.js",
@@ -51,7 +50,6 @@
   "background/editing/editing.js",
   "background/editing/intent_handler.js",
   "background/event_source.js",
-  "background/find_handler.js",
   "background/focus_automation_handler.js",
   "background/gesture_command_data.js",
   "background/gesture_command_handler.js",
@@ -67,15 +65,11 @@
   "background/logging/output_logger.js",
   "background/logging/tree_dumper.js",
   "background/math_handler.js",
-  "background/media_automation_handler.js",
   "background/pointer_handler.js",
-  "background/next_earcons.js",
-  "background/notifications.js",
   "background/output.js",
   "background/panel_command.js",
   "background/phonetic_data.js",
   "background/prefs.js",
-  "background/range_automation_handler.js",
   "background/smart_sticky_mode.js",
   "background/tabs_api_handler.js",
   "background/user_action_monitor.js",
@@ -127,6 +121,10 @@
 chromevox_es6_modules = [
   "background/background.js",
   "background/es6_loader.js",
+  "background/find_handler.js",
+  "background/media_automation_handler.js",
+  "background/next_earcons.js",
+  "background/range_automation_handler.js",
 ]
 
 # Closure library modules needed by chromevox.
@@ -160,12 +158,6 @@
     ":chromevox_options_script",
     ":chromevox_panel_script",
     ":chromevox_phonetic_dictionaries_js",
-    ":i_tutorial",
-    ":tutorial_lesson",
-    ":tutorial_lesson_container",
-    ":tutorial_lesson_menu",
-    ":tutorial_main_menu",
-    ":tutorial_navigation_buttons",
     "//chrome/browser/resources/chromeos/accessibility/braille_ime:braille_ime_manifest",
     "//third_party/chromevox:chromevox_third_party_resources",
     "//third_party/liblouis",
@@ -194,9 +186,6 @@
     "background/earcons/static.wav",
     "background/logging/log.css",
     "background/logging/log.html",
-    "i_tutorial/components/constants.js",
-    "i_tutorial/components/localization.js",
-    "i_tutorial/components/tutorial_behavior.js",
     "i_tutorial/practice_areas/jump_commands.html",
     "i_tutorial/practice_areas/selects.html",
     "images/chromevox-128.png",
@@ -470,65 +459,6 @@
   }
 }
 
-copy("tutorial_lesson") {
-  sources = [ "$chromevox_gen_dir/i_tutorial/components/tutorial_lesson.js" ]
-  outputs = [ "$chromevox_out_dir/i_tutorial/components/tutorial_lesson.js" ]
-  deps = [
-    "i_tutorial/components:closure_compile",
-    "i_tutorial/components:components",
-  ]
-}
-
-copy("tutorial_lesson_container") {
-  sources = [ "$chromevox_gen_dir/i_tutorial/components/lesson_container.js" ]
-  outputs = [ "$chromevox_out_dir/i_tutorial/components/lesson_container.js" ]
-
-  deps = [
-    "i_tutorial/components:closure_compile",
-    "i_tutorial/components:components",
-  ]
-}
-
-copy("tutorial_main_menu") {
-  sources = [ "$chromevox_gen_dir/i_tutorial/components/main_menu.js" ]
-  outputs = [ "$chromevox_out_dir/i_tutorial/components/main_menu.js" ]
-
-  deps = [
-    "i_tutorial/components:closure_compile",
-    "i_tutorial/components:components",
-  ]
-}
-
-copy("tutorial_lesson_menu") {
-  sources = [ "$chromevox_gen_dir/i_tutorial/components/lesson_menu.js" ]
-  outputs = [ "$chromevox_out_dir/i_tutorial/components/lesson_menu.js" ]
-
-  deps = [
-    "i_tutorial/components:closure_compile",
-    "i_tutorial/components:components",
-  ]
-}
-
-copy("tutorial_navigation_buttons") {
-  sources = [ "$chromevox_gen_dir/i_tutorial/components/navigation_buttons.js" ]
-  outputs = [ "$chromevox_out_dir/i_tutorial/components/navigation_buttons.js" ]
-
-  deps = [
-    "i_tutorial/components:closure_compile",
-    "i_tutorial/components:components",
-  ]
-}
-
-copy("i_tutorial") {
-  sources = [ "$chromevox_gen_dir/i_tutorial/components/i_tutorial.js" ]
-  outputs = [ "$chromevox_out_dir/i_tutorial/components/i_tutorial.js" ]
-
-  deps = [
-    "i_tutorial/components:closure_compile",
-    "i_tutorial/components:components",
-  ]
-}
-
 # Closure type check compilation and associated js libraries.
 js_type_check("closure_compile") {
   deps = [
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.html b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.html
index ad8525b..9ea919e 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.html
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.html
@@ -1,4 +1,9 @@
 <!-- ChromeVox -->
+
+<!-- ChromeVox compiled script (non-ES6 modules) packed into one file. -->
+<script src="../chromeVoxChromeBackgroundScript.js" charset="utf-8">
+</script>
+
 <!--
   ChromeVox ES6 module(s).
 
@@ -9,9 +14,6 @@
 -->
 <script type="module" src="es6_loader.js"></script>
 
-<!-- ChromeVox compiled script (non-ES6 modules) packed into one file. -->
-<script src="../chromeVoxChromeBackgroundScript.js" charset="utf-8">
-</script>
 <!-- Generated at build time -->
 <script type="text/javascript" src="../phonetic_dictionaries.js"
   charset="utf-8"></script>
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js
index 08f60bc..7123b19 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {FindHandler} from './find_handler.js';
+import {MediaAutomationHandler} from './media_automation_handler.js';
+import {NextEarcons} from './next_earcons.js';
+import {RangeAutomationHandler} from './range_automation_handler.js';
+
 /**
  * @fileoverview The entry point for all ChromeVox2 related code for the
  * background page.
@@ -109,8 +114,6 @@
     PhoneticData.init();
     UserAnnotationHandler.init();
 
-    Notifications.onStartup();
-
     chrome.accessibilityPrivate.onAnnounceForAccessibility.addListener(
         (announceText) => {
           ChromeVox.tts.speak(announceText.join(' '), QueueMode.FLUSH);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/find_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/find_handler.js
index 05c2c40..947d91f 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/find_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/find_handler.js
@@ -1,16 +1,15 @@
 // Copyright 2016 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.
+
 /**
  * @fileoverview Handles output for Chrome's built-in find.
  */
-goog.provide('FindHandler');
 
-goog.require('Output');
-
-goog.scope(function() {
 const TreeChangeObserverFilter = chrome.automation.TreeChangeObserverFilter;
 
+export class FindHandler {}
+
 /**
  * Initializes this module.
  */
@@ -66,5 +65,3 @@
  * @type {!Date}
  */
 FindHandler.lastFindMarkerReceived = new Date();
-
-});  // goog.scope
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js
index 2a08ec6..baaeb32 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js
@@ -19,23 +19,18 @@
 goog.require('DesktopAutomationHandler');
 goog.require('DownloadHandler');
 goog.require('ExtensionBridge');
-goog.require('FindHandler');
 goog.require('FocusAutomationHandler');
 goog.require('GestureCommandHandler');
 goog.require('InstanceChecker');
 goog.require('LiveRegions');
 goog.require('LocaleOutputHelper');
 goog.require('MathHandler');
-goog.require('MediaAutomationHandler');
 goog.require('NavBraille');
-goog.require('NextEarcons');
 goog.require('NodeIdentifier');
-goog.require('Notifications');
 goog.require('Output');
 goog.require('Output.EventType');
 goog.require('PanelCommand');
 goog.require('PhoneticData');
-goog.require('RangeAutomationHandler');
 goog.require('UserAnnotationHandler');
 goog.require('constants');
 goog.require('cursors.Cursor');
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/media_automation_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/media_automation_handler.js
index 791f7e97..d2cb212e 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/media_automation_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/media_automation_handler.js
@@ -3,17 +3,9 @@
 // found in the LICENSE file.
 
 /**
- * @fileoverview Handles media automation events.  Note that to perform any of
- * the actions below such as ducking, and suspension of media sessions, the
- * --enable-audio-focus flag must be passed at the command line.
+ * @fileoverview Handles media automation events.
  */
 
-goog.provide('MediaAutomationHandler');
-
-goog.require('BaseAutomationHandler');
-goog.require('TtsCapturingEventListener');
-
-goog.scope(function() {
 const AutomationEvent = chrome.automation.AutomationEvent;
 const AutomationNode = chrome.automation.AutomationNode;
 const EventType = chrome.automation.EventType;
@@ -22,7 +14,7 @@
 /**
  * @implements {TtsCapturingEventListener}
  */
-MediaAutomationHandler = class extends BaseAutomationHandler {
+export class MediaAutomationHandler extends BaseAutomationHandler {
   constructor() {
     super(null);
     /** @type {!Set<AutomationNode>} @private */
@@ -113,9 +105,7 @@
       item = it.next();
     }
   }
-};
+}
 
 /** @type {number} */
 MediaAutomationHandler.MIN_WAITTIME_MS = 1000;
-
-});  // goog.scope
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/next_earcons.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/next_earcons.js
index f2201de..49e3845 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/next_earcons.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/next_earcons.js
@@ -7,16 +7,7 @@
  * auditory cues.
  */
 
-
-goog.provide('NextEarcons');
-
-goog.require('EarconEngine');
-goog.require('LogStore');
-goog.require('TextLog');
-goog.require('AbstractEarcons');
-
-
-NextEarcons = class extends AbstractEarcons {
+export class NextEarcons extends AbstractEarcons {
   constructor() {
     super();
 
@@ -52,6 +43,10 @@
   }
 
   /**
+   * Plays the specified earcon sound.
+   * @param {Earcon} earcon An earcon identifier.
+   * @param {Object=} opt_location A location associated with the earcon such as
+   *     a control's bounding rectangle.
    * @override
    */
   playEarcon(earcon, opt_location) {
@@ -179,4 +174,4 @@
           device.deviceType === chrome.audio.DeviceType.INTERNAL_SPEAKER;
     });
   }
-};
+}
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/notifications.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/notifications.js
deleted file mode 100644
index a1801134..0000000
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/notifications.js
+++ /dev/null
@@ -1,85 +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.
-
-/**
- * @fileoverview Provides notification support for ChromeVox.
- */
-
-goog.provide('Notifications');
-
-goog.require('PanelCommand');
-
-/**
- * ChromeVox update notification.
- */
-const UpdateNotification = class {
-  constructor() {
-    this.data = {};
-    this.data.type = 'basic';
-    this.data.iconUrl = '/chromevox/images/chromevox-16.png';
-    this.data.title = Msgs.getMsg('update_title');
-    this.data.message = Msgs.getMsg('update_message_new');
-  }
-
-  /** @return {boolean} */
-  shouldShow() {
-    return !localStorage['notifications_update_notification_shown'] &&
-        chrome.runtime.getManifest().version >= '63' &&
-        chrome.runtime.getManifest().version < '64';
-  }
-
-  /** Shows the notification. */
-  show() {
-    if (!this.shouldShow()) {
-      return;
-    }
-    chrome.notifications.create('update', this.data);
-    chrome.notifications.onClicked.addListener(this.onClicked);
-    chrome.notifications.onClosed.addListener(this.onClosed);
-  }
-
-  /**
-   * Handles the chrome.notifications event.
-   * @param {string} notificationId
-   */
-  onClicked(notificationId) {
-    (new PanelCommand(PanelCommandType.TUTORIAL)).send();
-  }
-
-  /**
-   * Handles the chrome.notifications event.
-   * @param {string} id
-   */
-  onClosed(id) {
-    localStorage['notifications_update_notification_shown'] = true;
-  }
-
-  /**
-   * Removes all listeners added by this object.
-   */
-  removeAllListeners() {
-    chrome.notifications.onClicked.removeListener(this.onClicked);
-    chrome.notifications.onClosed.removeListener(this.onClosed);
-  }
-};
-
-
-/**
- * Set after an update is shown.
- * @type {UpdateNotification}
- */
-Notifications.currentUpdate;
-
-/**
- * Runs notifications that should be shown for startup.
- */
-Notifications.onStartup = function() {
-  // Only run on background page.
-  if (document.location.href.indexOf('background.html') === -1) {
-    return;
-  }
-
-  Notifications.currentUpdate = new UpdateNotification();
-  Notifications.currentUpdate.show();
-};
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js
index 8fe89b7..d5b3fc9 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js
@@ -6,11 +6,6 @@
  * @fileoverview Handles automation from ChromeVox's current range.
  */
 
-goog.provide('RangeAutomationHandler');
-
-goog.require('BaseAutomationHandler');
-
-goog.scope(function() {
 const AutomationEvent = chrome.automation.AutomationEvent;
 const AutomationNode = chrome.automation.AutomationNode;
 const Dir = constants.Dir;
@@ -21,7 +16,7 @@
 /**
  * @implements {ChromeVoxStateObserver}
  */
-RangeAutomationHandler = class extends BaseAutomationHandler {
+export class RangeAutomationHandler extends BaseAutomationHandler {
   constructor() {
     super(undefined);
 
@@ -243,6 +238,4 @@
     return rectA.left === rectB.left && rectA.top === rectB.top &&
         rectA.width === rectB.width && rectA.height === rectB.height;
   }
-};
-
-});  // goog.scope
+}
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
index f08b53e..1474cd9 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
@@ -290,7 +290,7 @@
     $('menus_background').hidden =
         (Panel.mode_ !== Panel.Mode.FULLSCREEN_MENUS);
     // Interactive tutorial elements may not have been loaded yet.
-    const iTutorialContainer = $('i-tutorial-container');
+    const iTutorialContainer = $('chromevox-tutorial-container');
     if (iTutorialContainer) {
       iTutorialContainer.hidden =
           (Panel.mode_ !== Panel.Mode.FULLSCREEN_TUTORIAL);
@@ -1099,7 +1099,7 @@
    * @param {string=} opt_page Show a specific page.
    */
   static onTutorial(opt_page) {
-    if (!$('i-tutorial')) {
+    if (!$('chromevox-tutorial')) {
       const curriculum =
           Panel.sessionState === chrome.loginState.SessionState.IN_OOBE_SCREEN ?
           'quick_orientation' :
@@ -1114,25 +1114,22 @@
   }
 
   /**
-   * Creates an <i-tutorial> element and adds it to the dom.
+   * Creates a <chromevox-tutorial> element and adds it to the dom.
    * @param {(string|null)} curriculum
    */
   static createITutorial(curriculum) {
     const tutorialScript = document.createElement('script');
-    tutorialScript.src = '../i_tutorial/components/i_tutorial.js';
+    tutorialScript.src =
+        '../../common/tutorial/components/chromevox_tutorial.js';
     tutorialScript.setAttribute('type', 'module');
-    const lessonScript = document.createElement('script');
-    lessonScript.src = '../i_tutorial/components/tutorial_lesson.js';
-    lessonScript.setAttribute('type', 'module');
     document.body.appendChild(tutorialScript);
-    document.body.appendChild(lessonScript);
 
     // Create tutorial container and element.
     const tutorialContainer = document.createElement('div');
-    tutorialContainer.setAttribute('id', 'i-tutorial-container');
+    tutorialContainer.setAttribute('id', 'chromevox-tutorial-container');
     tutorialContainer.hidden = true;
-    const tutorialElement = document.createElement('i-tutorial');
-    tutorialElement.setAttribute('id', 'i-tutorial');
+    const tutorialElement = document.createElement('chromevox-tutorial');
+    tutorialElement.setAttribute('id', 'chromevox-tutorial');
     if (curriculum) {
       tutorialElement.curriculum = curriculum;
     }
@@ -1145,12 +1142,12 @@
     const chromeVoxState = backgroundPage['ChromeVoxState'];
     const chromeVoxStateInstance = chromeVoxState['instance'];
 
-    $('i-tutorial').addEventListener('closetutorial', (evt) => {
+    $('chromevox-tutorial').addEventListener('closetutorial', (evt) => {
       // Ensure UserActionMonitor is destroyed before closing tutorial.
       chromeVoxStateInstance.destroyUserActionMonitor();
       Panel.onCloseTutorial();
     });
-    $('i-tutorial').addEventListener('requestspeech', (evt) => {
+    $('chromevox-tutorial').addEventListener('requestspeech', (evt) => {
       /**
        * @type {{
        * text: string,
@@ -1169,28 +1166,28 @@
       const cvox = backgroundPage['ChromeVox'];
       cvox.tts.speak(text, queueMode, properties);
     });
-    $('i-tutorial').addEventListener('startinteractivemode', (evt) => {
+    $('chromevox-tutorial').addEventListener('startinteractivemode', (evt) => {
       const actions = evt.detail.actions;
       chromeVoxStateInstance.createUserActionMonitor(actions, () => {
         chromeVoxStateInstance.destroyUserActionMonitor();
         Panel.iTutorial.showNextLesson();
       });
     });
-    $('i-tutorial').addEventListener('stopinteractivemode', (evt) => {
+    $('chromevox-tutorial').addEventListener('stopinteractivemode', (evt) => {
       chromeVoxStateInstance.destroyUserActionMonitor();
     });
-    $('i-tutorial').addEventListener('requestfullydescribe', (evt) => {
+    $('chromevox-tutorial').addEventListener('requestfullydescribe', (evt) => {
       const commandHandler = backgroundPage['CommandHandler'];
       commandHandler.onCommand('fullyDescribe');
     });
-    $('i-tutorial').addEventListener('requestearcon', (evt) => {
+    $('chromevox-tutorial').addEventListener('requestearcon', (evt) => {
       const earconId = evt.detail.earconId;
       backgroundPage['ChromeVox']['earcons']['playEarcon'](earconId);
     });
-    $('i-tutorial').addEventListener('readyfortesting', () => {
+    $('chromevox-tutorial').addEventListener('readyfortesting', () => {
       Panel.iTutorialReadyForTesting_ = true;
     });
-    $('i-tutorial').addEventListener('openUrl', (evt) => {
+    $('chromevox-tutorial').addEventListener('openUrl', (evt) => {
       const url = evt.detail.url;
       // Ensure UserActionMonitor is destroyed before closing tutorial.
       chromeVoxStateInstance.destroyUserActionMonitor();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js
index d82de93a..ac9ca3d 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js
@@ -32,7 +32,7 @@
   async waitForTutorial() {
     return new Promise(resolve => {
       const doc = this.getPanelWindow().document;
-      if (doc.getElementById('i-tutorial-container')) {
+      if (doc.getElementById('chromevox-tutorial-container')) {
         resolve();
       } else {
         /**
@@ -43,7 +43,7 @@
           for (const mutation of mutationsList) {
             if (mutation.type === 'childList') {
               for (const node of mutation.addedNodes) {
-                if (node.id === 'i-tutorial-container') {
+                if (node.id === 'chromevox-tutorial-container') {
                   // Once the tutorial has been added to the document, we need
                   // to wait for the lesson templates to load.
                   const panel = this.getPanel();
diff --git a/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn
index bf004bb..aa684e8 100644
--- a/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn
@@ -18,7 +18,10 @@
     "$root_out_dir/resources/chromeos/accessibility/common"
 
 group("build") {
-  deps = [ ":accessibility_common_copied_files" ]
+  deps = [
+    ":accessibility_common_copied_files",
+    "tutorial:build",
+  ]
 }
 
 run_jsbundler("accessibility_common_copied_files") {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/common/tutorial/BUILD.gn
similarity index 62%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/BUILD.gn
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/BUILD.gn
index 45723f3..74c9eea 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/common/tutorial/BUILD.gn
@@ -1,26 +1,34 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
+# Copyright 2021 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/polymer/html_to_js.gni")
 
+group("build") {
+  deps = [
+    ":closure_compile",
+    ":components",
+    ":copy_files",
+  ]
+}
+
 html_to_js("components") {
   js_files = [
-    "tutorial_lesson.js",
-    "i_tutorial.js",
-    "navigation_buttons.js",
-    "main_menu.js",
-    "lesson_menu.js",
+    "chromevox_tutorial.js",
     "lesson_container.js",
+    "lesson_menu.js",
+    "main_menu.js",
+    "navigation_buttons.js",
+    "tutorial_lesson.js",
   ]
 }
 
 js_type_check("closure_compile") {
   is_polymer3 = true
   deps = [
+    ":chromevox_tutorial",
     ":constants",
-    ":i_tutorial",
     ":lesson_container",
     ":lesson_menu",
     ":localization",
@@ -31,22 +39,16 @@
   ]
 }
 
+js_library("chromevox_tutorial") {
+  deps = [
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+  ]
+}
+
 js_library("constants") {
 }
 
-js_library("tutorial_lesson") {
-  deps = [
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
-js_library("navigation_buttons") {
-  deps = [
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
-js_library("main_menu") {
+js_library("lesson_container") {
   deps = [
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
@@ -58,19 +60,16 @@
   ]
 }
 
-js_library("lesson_container") {
-  deps = [
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
-js_library("i_tutorial") {
-  deps = [
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
 js_library("localization") {
+}
+
+js_library("main_menu") {
+  deps = [
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+  ]
+}
+
+js_library("navigation_buttons") {
   deps = [
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
@@ -81,3 +80,35 @@
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
 }
+
+js_library("tutorial_lesson") {
+  deps = [
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+  ]
+}
+
+tutorial_gen_dir = "$root_gen_dir/chrome/browser/resources/chromeos/accessibility/common/tutorial"
+
+tutorial_out_dir =
+    "$root_out_dir/resources/chromeos/accessibility/common/tutorial/components"
+
+copy("copy_files") {
+  sources = [
+    "$tutorial_gen_dir/chromevox_tutorial.js",
+    "$tutorial_gen_dir/lesson_container.js",
+    "$tutorial_gen_dir/lesson_menu.js",
+    "$tutorial_gen_dir/main_menu.js",
+    "$tutorial_gen_dir/navigation_buttons.js",
+    "$tutorial_gen_dir/tutorial_lesson.js",
+    "constants.js",
+    "localization.js",
+    "tutorial_behavior.js",
+  ]
+
+  outputs = [ "$tutorial_out_dir/{{source_file_part}}" ]
+
+  deps = [
+    ":closure_compile",
+    ":components",
+  ]
+}
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/i_tutorial.html b/chrome/browser/resources/chromeos/accessibility/common/tutorial/chromevox_tutorial.html
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/i_tutorial.html
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/chromevox_tutorial.html
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/i_tutorial.js b/chrome/browser/resources/chromeos/accessibility/common/tutorial/chromevox_tutorial.js
similarity index 99%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/i_tutorial.js
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/chromevox_tutorial.js
index 000fbca4..97d64fc1 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/i_tutorial.js
+++ b/chrome/browser/resources/chromeos/accessibility/common/tutorial/chromevox_tutorial.js
@@ -34,7 +34,7 @@
 };
 
 Polymer({
-  is: 'i-tutorial',
+  is: 'chromevox-tutorial',
 
   _template: html`{__html_template__}`,
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/constants.js b/chrome/browser/resources/chromeos/accessibility/common/tutorial/constants.js
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/constants.js
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/constants.js
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/lesson_container.html b/chrome/browser/resources/chromeos/accessibility/common/tutorial/lesson_container.html
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/lesson_container.html
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/lesson_container.html
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/lesson_container.js b/chrome/browser/resources/chromeos/accessibility/common/tutorial/lesson_container.js
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/lesson_container.js
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/lesson_container.js
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/lesson_menu.html b/chrome/browser/resources/chromeos/accessibility/common/tutorial/lesson_menu.html
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/lesson_menu.html
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/lesson_menu.html
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/lesson_menu.js b/chrome/browser/resources/chromeos/accessibility/common/tutorial/lesson_menu.js
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/lesson_menu.js
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/lesson_menu.js
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/localization.js b/chrome/browser/resources/chromeos/accessibility/common/tutorial/localization.js
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/localization.js
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/localization.js
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/main_menu.html b/chrome/browser/resources/chromeos/accessibility/common/tutorial/main_menu.html
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/main_menu.html
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/main_menu.html
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/main_menu.js b/chrome/browser/resources/chromeos/accessibility/common/tutorial/main_menu.js
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/main_menu.js
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/main_menu.js
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/navigation_buttons.html b/chrome/browser/resources/chromeos/accessibility/common/tutorial/navigation_buttons.html
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/navigation_buttons.html
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/navigation_buttons.html
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/navigation_buttons.js b/chrome/browser/resources/chromeos/accessibility/common/tutorial/navigation_buttons.js
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/navigation_buttons.js
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/navigation_buttons.js
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/tutorial_behavior.js b/chrome/browser/resources/chromeos/accessibility/common/tutorial/tutorial_behavior.js
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/tutorial_behavior.js
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/tutorial_behavior.js
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/tutorial_lesson.html b/chrome/browser/resources/chromeos/accessibility/common/tutorial/tutorial_lesson.html
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/tutorial_lesson.html
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/tutorial_lesson.html
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/tutorial_lesson.js b/chrome/browser/resources/chromeos/accessibility/common/tutorial/tutorial_lesson.js
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/tutorial_lesson.js
rename to chrome/browser/resources/chromeos/accessibility/common/tutorial/tutorial_lesson.js
diff --git a/chrome/browser/resources/memories/.eslintrc.js b/chrome/browser/resources/memories/.eslintrc.js
new file mode 100644
index 0000000..52e5ab6
--- /dev/null
+++ b/chrome/browser/resources/memories/.eslintrc.js
@@ -0,0 +1,11 @@
+// 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.exports = {
+  'env': {
+    'browser': true,
+    'es6': true,
+  },
+  'rules': {'eqeqeq': ['error', 'always', {'null': 'ignore'}]},
+};
diff --git a/chrome/browser/resources/memories/BUILD.gn b/chrome/browser/resources/memories/BUILD.gn
new file mode 100644
index 0000000..68be419
--- /dev/null
+++ b/chrome/browser/resources/memories/BUILD.gn
@@ -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.
+
+import("//chrome/common/features.gni")
+import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/grit/grit_rule.gni")
+import("//tools/grit/preprocess_if_expr.gni")
+import("//ui/webui/resources/tools/generate_grd.gni")
+
+js_type_check("closure_compile") {
+  is_polymer3 = true
+  closure_flags = default_closure_args + mojom_js_args
+  deps = [ ":memories" ]
+}
+
+js_library("memories") {
+  deps = [ ":browser_proxy" ]
+}
+
+js_library("browser_proxy") {
+  deps = [
+    "//chrome/browser/ui/webui/memories:mojo_bindings_js_library_for_compile",
+    "//ui/webui/resources/js:cr.m",
+  ]
+}
+
+grd_prefix = "memories"
+preprocess_folder = "preprocessed"
+preprocess_manifest = "preprocessed_manifest.json"
+
+preprocess_if_expr("preprocess") {
+  defines = chrome_grit_defines + [ "is_official_build=$is_official_build" ]
+  in_folder = "./"
+  out_folder = "$target_gen_dir/$preprocess_folder"
+  out_manifest = "$target_gen_dir/$preprocess_manifest"
+  in_files = [
+    "browser_proxy.js",
+    "memories.js",
+  ]
+}
+
+generate_grd("build_memories_mojo_grdp") {
+  grd_prefix = "$grd_prefix"
+  out_grd = "$target_gen_dir/memories_mojo_resources.grdp"
+  input_files = [ "memories.mojom-lite.js" ]
+  input_files_base_dir =
+      rebase_path("$root_gen_dir/chrome/browser/ui/webui/memories",
+                  root_build_dir)
+}
+
+generate_grd("build_grd") {
+  grd_prefix = "$grd_prefix"
+  out_grd = "$target_gen_dir/resources.grd"
+  input_files = [ "memories.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+  grdp_files = [ "$target_gen_dir/memories_mojo_resources.grdp" ]
+  deps = [
+    ":build_memories_mojo_grdp",
+    ":preprocess",
+  ]
+  manifest_files = [ "$target_gen_dir/$preprocess_manifest" ]
+}
+
+grit("resources") {
+  defines = chrome_grit_defines + [ "is_official_build=$is_official_build" ]
+  enable_input_discovery_for_gn_analyze = false
+  source = "$target_gen_dir/resources.grd"
+  deps = [
+    ":build_grd",
+    "//chrome/browser/ui/webui/memories:mojo_bindings_js",
+  ]
+  outputs = [
+    "grit/memories_resources.h",
+    "grit/memories_resources_map.cc",
+    "grit/memories_resources_map.h",
+    "memories_resources.pak",
+  ]
+  output_dir = "$root_gen_dir/chrome"
+}
diff --git a/chrome/browser/resources/memories/DIR_METADATA b/chrome/browser/resources/memories/DIR_METADATA
new file mode 100644
index 0000000..88f25f6
--- /dev/null
+++ b/chrome/browser/resources/memories/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Memories"
+}
diff --git a/chrome/browser/resources/memories/OWNERS b/chrome/browser/resources/memories/OWNERS
new file mode 100644
index 0000000..100d7c6
--- /dev/null
+++ b/chrome/browser/resources/memories/OWNERS
@@ -0,0 +1 @@
+file://components/memories/OWNERS
diff --git a/chrome/browser/resources/memories/browser_proxy.js b/chrome/browser/resources/memories/browser_proxy.js
new file mode 100644
index 0000000..ccdb769
--- /dev/null
+++ b/chrome/browser/resources/memories/browser_proxy.js
@@ -0,0 +1,28 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
+
+import './memories.mojom-lite.js';
+
+import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
+
+/**
+ * @fileoverview This file provides a singleton class that exposes the Mojo
+ * handler interface used for bidirectional communication between the page and
+ * the browser.
+ */
+
+export class BrowserProxy {
+  constructor() {
+    /** @type {!memories.mojom.PageHandlerRemote} */
+    this.handler = memories.mojom.PageHandler.getRemote();
+
+    /** @type {!memories.mojom.PageCallbackRouter} */
+    this.callbackRouter = new memories.mojom.PageCallbackRouter();
+    this.handler.setPage(this.callbackRouter.$.bindNewPipeAndPassRemote());
+  }
+}
+
+addSingletonGetter(BrowserProxy);
diff --git a/chrome/browser/resources/memories/memories.html b/chrome/browser/resources/memories/memories.html
new file mode 100644
index 0000000..35ab054e
--- /dev/null
+++ b/chrome/browser/resources/memories/memories.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
+<head>
+  <meta charset="utf-8">
+  <meta name="color-scheme" content="light dark">
+  <title>$i18n{title}</title>
+  <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
+  <style>
+    html {
+      background: var(--md-background-color);
+      overflow: hidden;
+    }
+
+    html,
+    body {
+      height: 100%;
+      margin: 0;
+    }
+  </style>
+</head>
+<body>
+  <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
+  <script type="module" src="memories.js"></script>
+  <memories-app></memories-app>
+</body>
+</html>
diff --git a/chrome/browser/resources/memories/memories.js b/chrome/browser/resources/memories/memories.js
new file mode 100644
index 0000000..7b6998b
--- /dev/null
+++ b/chrome/browser/resources/memories/memories.js
@@ -0,0 +1,7 @@
+// 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 {BrowserProxy} from './browser_proxy.js';
+
+BrowserProxy.getInstance();
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index 9e27eaad1..fe8e6228 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -1177,6 +1177,7 @@
     "os_about_page:closure_compile_module",
 
     #"os_apps_page:closure_compile_module",
+    #"os_apps_page/app_management_page:closure_compile_module",
     #"os_apps_page/app_management_page/plugin_vm_page:closure_compile_module",
     "on_startup_page:closure_compile_module",
     "os_files_page:closure_compile_module",
@@ -1324,6 +1325,7 @@
     "os_a11y_page:polymer3_elements",
     "os_about_page:polymer3_elements",
     "os_apps_page:polymer3_elements",
+    "os_apps_page/app_management_page:polymer3_elements",
     "os_apps_page/app_management_page/plugin_vm_page:polymer3_elements",
     "os_files_page:polymer3_elements",
     "os_languages_page:polymer3_elements",
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/BUILD.gn
index 064c870..5e8076f 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/BUILD.gn
@@ -3,6 +3,8 @@
 # found in the LICENSE file.
 
 import("//third_party/closure_compiler/compile_js.gni")
+import("//ui/webui/resources/tools/js_modulizer.gni")
+import("../../os_settings.gni")
 
 js_type_check("closure_compile") {
   deps = [
@@ -107,6 +109,7 @@
 }
 
 js_library("dom_switch") {
+  externs_list = [ "$externs_path/pending_polymer.js" ]
 }
 
 js_library("fake_page_handler") {
@@ -218,3 +221,356 @@
     "//ui/webui/resources/js:cr",
   ]
 }
+
+# TODO: Uncomment as Polymer 3 migration makes progress
+# js_type_check("closure_compile_module") {
+#   is_polymer3 = true
+#   deps = [
+#     ":actions.m",
+#     ":api_listener.m",
+#     ":app_detail_view.m",
+#     ":app_item.m",
+#     ":app_management_page.m",
+#     ":arc_detail_view.m",
+#     ":browser_proxy.m",
+#     ":chrome_app_detail_view.m",
+#     ":constants.m",
+#     ":dom_switch.m",
+#     ":fake_page_handler.m",
+#     ":icons.m",
+#     ":main_view.m",
+#     ":permission_item.m",
+#     ":pin_to_shelf_item.m",
+#     ":pwa_detail_view.m",
+#     ":reducers.m",
+#     ":shared_style.m",
+#     ":shared_vars.m",
+#     ":store.m",
+#     ":store_client.m",
+#     ":toggle_row.m",
+#     ":types.m",
+#     ":uninstall_button.m",
+#     ":util.m",
+#   ]
+# }
+
+js_library("actions.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/actions.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("api_listener.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/api_listener.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("app_detail_view.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/app_detail_view.m.js" ]
+  deps = []
+  extra_deps = [ ":app_detail_view_module" ]
+}
+
+js_library("app_item.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/app_item.m.js" ]
+  deps = []
+  extra_deps = [ ":app_item_module" ]
+}
+
+js_library("app_management_page.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/app_management_page.m.js" ]
+  deps = []
+  extra_deps = [ ":app_management_page_module" ]
+}
+
+js_library("arc_detail_view.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/arc_detail_view.m.js" ]
+  deps = []
+  extra_deps = [ ":arc_detail_view_module" ]
+}
+
+js_library("browser_proxy.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/browser_proxy.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("chrome_app_detail_view.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/chrome_app_detail_view.m.js" ]
+  deps = []
+  extra_deps = [ ":chrome_app_detail_view_module" ]
+}
+
+js_library("constants.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/constants.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("dom_switch.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/dom_switch.m.js" ]
+  deps = [
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/js:assert.m",
+    "//ui/webui/resources/js:promise_resolver.m",
+  ]
+  extra_deps = [ ":dom_switch_module" ]
+}
+
+js_library("fake_page_handler.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/fake_page_handler.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("icons.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/icons.m.js" ]
+  deps = []
+  extra_deps = [ ":icons_module" ]
+}
+
+js_library("main_view.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/main_view.m.js" ]
+  deps = []
+  extra_deps = [ ":main_view_module" ]
+}
+
+js_library("permission_item.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/permission_item.m.js" ]
+  deps = []
+  extra_deps = [ ":permission_item_module" ]
+}
+
+js_library("pin_to_shelf_item.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/pin_to_shelf_item.m.js" ]
+  deps = []
+  extra_deps = [ ":pin_to_shelf_item_module" ]
+}
+
+js_library("pwa_detail_view.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/pwa_detail_view.m.js" ]
+  deps = []
+  extra_deps = [ ":pwa_detail_view_module" ]
+}
+
+js_library("reducers.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/reducers.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("store.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/store.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("shared_style.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_style.m.js" ]
+  deps = []
+  extra_deps = [ ":shared_style_module" ]
+}
+
+js_library("shared_vars.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_vars.m.js" ]
+  deps = []
+  extra_deps = [ ":shared_vars_module" ]
+}
+
+js_library("store_client.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/store_client.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("toggle_row.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/toggle_row.m.js" ]
+  deps = []
+  extra_deps = [ ":toggle_row_module" ]
+}
+
+js_library("types.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/types.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("uninstall_button.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/uninstall_button.m.js" ]
+  deps = []
+  extra_deps = [ ":uninstall_button_module" ]
+}
+
+js_library("util.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/util.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+import("//tools/polymer/polymer.gni")
+
+group("polymer3_elements") {
+  public_deps = [
+    ":app_detail_view_module",
+    ":app_item_module",
+    ":app_management_page_module",
+    ":arc_detail_view_module",
+    ":chrome_app_detail_view_module",
+    ":dom_switch_module",
+    ":icons_module",
+    ":main_view_module",
+    ":modulize",
+    ":permission_item_module",
+    ":pin_to_shelf_item_module",
+    ":pwa_detail_view_module",
+    ":shared_style_module",
+    ":shared_vars_module",
+    ":toggle_row_module",
+    ":uninstall_button_module",
+  ]
+}
+
+polymer_modulizer("app_detail_view") {
+  js_file = "app_detail_view.js"
+  html_file = "app_detail_view.html"
+  html_type = "dom-module"
+  migrated_imports = settings_migrated_imports
+  namespace_rewrites = os_settings_namespace_rewrites
+  auto_imports = os_settings_auto_imports
+}
+
+polymer_modulizer("app_item") {
+  js_file = "app_item.js"
+  html_file = "app_item.html"
+  html_type = "dom-module"
+  migrated_imports = settings_migrated_imports
+  namespace_rewrites = os_settings_namespace_rewrites
+  auto_imports = os_settings_auto_imports
+}
+
+polymer_modulizer("app_management_page") {
+  js_file = "app_management_page.js"
+  html_file = "app_management_page.html"
+  html_type = "dom-module"
+  migrated_imports = settings_migrated_imports
+  namespace_rewrites = os_settings_namespace_rewrites
+  auto_imports = os_settings_auto_imports
+}
+
+polymer_modulizer("arc_detail_view") {
+  js_file = "arc_detail_view.js"
+  html_file = "arc_detail_view.html"
+  html_type = "dom-module"
+  migrated_imports = settings_migrated_imports
+  namespace_rewrites = os_settings_namespace_rewrites
+  auto_imports = os_settings_auto_imports
+}
+
+polymer_modulizer("chrome_app_detail_view") {
+  js_file = "chrome_app_detail_view.js"
+  html_file = "chrome_app_detail_view.html"
+  html_type = "dom-module"
+  migrated_imports = settings_migrated_imports
+  namespace_rewrites = os_settings_namespace_rewrites
+  auto_imports = os_settings_auto_imports
+}
+
+polymer_modulizer("dom_switch") {
+  js_file = "dom_switch.js"
+  html_file = "dom_switch.html"
+  html_type = "dom-module"
+  migrated_imports = settings_migrated_imports
+  namespace_rewrites = os_settings_namespace_rewrites
+  auto_imports = os_settings_auto_imports
+}
+
+polymer_modulizer("icons") {
+  js_file = "icons.m.js"
+  html_file = "icons.html"
+  html_type = "iron-iconset"
+}
+
+polymer_modulizer("main_view") {
+  js_file = "main_view.js"
+  html_file = "main_view.html"
+  html_type = "dom-module"
+  migrated_imports = settings_migrated_imports
+  namespace_rewrites = os_settings_namespace_rewrites
+  auto_imports = os_settings_auto_imports
+}
+
+polymer_modulizer("permission_item") {
+  js_file = "permission_item.js"
+  html_file = "permission_item.html"
+  html_type = "dom-module"
+  migrated_imports = settings_migrated_imports
+  namespace_rewrites = os_settings_namespace_rewrites
+  auto_imports = os_settings_auto_imports
+}
+
+polymer_modulizer("pin_to_shelf_item") {
+  js_file = "pin_to_shelf_item.js"
+  html_file = "pin_to_shelf_item.html"
+  html_type = "dom-module"
+  migrated_imports = settings_migrated_imports
+  namespace_rewrites = os_settings_namespace_rewrites
+  auto_imports = os_settings_auto_imports
+}
+
+polymer_modulizer("pwa_detail_view") {
+  js_file = "pwa_detail_view.js"
+  html_file = "pwa_detail_view.html"
+  html_type = "dom-module"
+  migrated_imports = settings_migrated_imports
+  namespace_rewrites = os_settings_namespace_rewrites
+  auto_imports = os_settings_auto_imports
+}
+
+polymer_modulizer("shared_style") {
+  js_file = "shared_style.m.js"
+  html_file = "shared_style.html"
+  html_type = "style-module"
+}
+
+polymer_modulizer("shared_vars") {
+  js_file = "shared_vars.m.js"
+  html_file = "shared_vars.html"
+  html_type = "custom-style"
+}
+
+polymer_modulizer("toggle_row") {
+  js_file = "toggle_row.js"
+  html_file = "toggle_row.html"
+  html_type = "dom-module"
+  migrated_imports = settings_migrated_imports
+  namespace_rewrites = os_settings_namespace_rewrites
+  auto_imports = os_settings_auto_imports
+}
+
+polymer_modulizer("uninstall_button") {
+  js_file = "uninstall_button.js"
+  html_file = "uninstall_button.html"
+  html_type = "dom-module"
+  migrated_imports = settings_migrated_imports
+  namespace_rewrites = os_settings_namespace_rewrites
+  auto_imports = os_settings_auto_imports
+}
+
+import("//ui/webui/resources/tools/js_modulizer.gni")
+
+js_modulizer("modulize") {
+  input_files = [
+    "actions.js",
+    "api_listener.js",
+    "browser_proxy.js",
+    "constants.js",
+    "fake_page_handler.js",
+    "reducers.js",
+    "store.js",
+    "store_client.js",
+    "types.js",
+    "util.js",
+  ]
+  namespace_rewrites = os_settings_namespace_rewrites
+}
diff --git a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc
index cd9cf355..0b6f04b 100644
--- a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc
+++ b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc
@@ -36,8 +36,8 @@
 namespace safe_browsing {
 
 namespace {
-// MIME-type for APKs.
-const char kApkMimeType[] = "application/vnd.android.package-archive";
+// File suffix for APKs.
+const base::FilePath::CharType kApkSuffix[] = FILE_PATH_LITERAL(".apk");
 
 // The number of user gestures to trace back for the referrer chain.
 const int kAndroidTelemetryUserGestureLimit = 2;
@@ -108,7 +108,7 @@
 
 void AndroidTelemetryService::OnDownloadUpdated(download::DownloadItem* item) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DCHECK_EQ(kApkMimeType, item->GetMimeType());
+  DCHECK(item->GetTargetFilePath().MatchesExtension(kApkSuffix));
 
   if (item->GetState() == download::DownloadItem::COMPLETE) {
     // Download completed. Send report.
@@ -128,11 +128,12 @@
 }
 
 bool AndroidTelemetryService::CanSendPing(download::DownloadItem* item) {
-  if (item->GetMimeType() != kApkMimeType) {
+  if (!item->GetTargetFilePath().MatchesExtension(kApkSuffix)) {
     // This case is not recorded since we are not interested here in finding out
     // how often people download non-APK files.
     return false;
   }
+  // TODO(crbug.com/1173145): Add a metric to check if the MIME type is APK.
 
   if (!IsSafeBrowsingEnabled(*GetPrefs())) {
     RecordApkDownloadTelemetryOutcome(
diff --git a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc
index 8b364d0e..9589558 100644
--- a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc
+++ b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/files/file_path.h"
 #include "base/task/post_task.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
@@ -115,8 +116,9 @@
   profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled,
                                     true);
   // Simulate non-APK download.
-  ON_CALL(*download_item_, GetMimeType())
-      .WillByDefault(testing::Return("text/plain"));
+  ON_CALL(*download_item_, GetTargetFilePath())
+      .WillByDefault(testing::ReturnRefOfCopy(
+          base::FilePath(FILE_PATH_LITERAL("file.txt"))));
 
   EXPECT_FALSE(CanSendPing(download_item_.get()));
 
@@ -132,9 +134,9 @@
   profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled,
                                     true);
   // Simulate APK download.
-  ON_CALL(*download_item_, GetMimeType())
-      .WillByDefault(
-          testing::Return("application/vnd.android.package-archive"));
+  ON_CALL(*download_item_, GetTargetFilePath())
+      .WillByDefault(testing::ReturnRefOfCopy(
+          base::FilePath(FILE_PATH_LITERAL("file.apk"))));
 
   EXPECT_FALSE(CanSendPing(download_item_.get()));
 
@@ -154,9 +156,9 @@
   profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled,
                                     true);
   // Simulate APK download.
-  ON_CALL(*download_item_, GetMimeType())
-      .WillByDefault(
-          testing::Return("application/vnd.android.package-archive"));
+  ON_CALL(*download_item_, GetTargetFilePath())
+      .WillByDefault(testing::ReturnRefOfCopy(
+          base::FilePath(FILE_PATH_LITERAL("file.apk"))));
 
   EXPECT_FALSE(CanSendPing(download_item_.get()));
 
@@ -178,9 +180,9 @@
   // Enable Safe Browsing.
   profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, true);
   // Simulate APK download.
-  ON_CALL(*download_item_, GetMimeType())
-      .WillByDefault(
-          testing::Return("application/vnd.android.package-archive"));
+  ON_CALL(*download_item_, GetTargetFilePath())
+      .WillByDefault(testing::ReturnRefOfCopy(
+          base::FilePath(FILE_PATH_LITERAL("file.apk"))));
 
   EXPECT_FALSE(CanSendPing(download_item_.get()));
 
@@ -197,14 +199,39 @@
   profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled,
                                     true);
   // Simulate APK download.
-  ON_CALL(*download_item_, GetMimeType())
-      .WillByDefault(
-          testing::Return("application/vnd.android.package-archive"));
+  ON_CALL(*download_item_, GetTargetFilePath())
+      .WillByDefault(testing::ReturnRefOfCopy(
+          base::FilePath(FILE_PATH_LITERAL("file.apk"))));
 
   // The ping should be sent.
   EXPECT_TRUE(CanSendPing(download_item_.get()));
 
-  // No metric is logged in this case.
+  // No metric is logged in this case, because SENT is logged in another
+  // function.
+  get_histograms()->ExpectTotalCount(kApkDownloadTelemetryOutcomeMetric, 0);
+}
+
+TEST_F(AndroidTelemetryServiceTest,
+       CanSendPing_AllConditionsMetMimeTypeNotApk) {
+  // Enable Safe Browsing.
+  profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, true);
+  // Enable Scout Reporting.
+  profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled,
+                                    true);
+  // Simulate APK download.
+  ON_CALL(*download_item_, GetTargetFilePath())
+      .WillByDefault(testing::ReturnRefOfCopy(
+          base::FilePath(FILE_PATH_LITERAL("file.apk"))));
+
+  // Set MIME type to non-APK.
+  ON_CALL(*download_item_, GetMimeType())
+      .WillByDefault(testing::Return("text/plain"));
+
+  // The ping should be sent even though the MIME type is not apk.
+  EXPECT_TRUE(CanSendPing(download_item_.get()));
+
+  // No metric is logged in this case, because SENT is logged in another
+  // function.
   get_histograms()->ExpectTotalCount(kApkDownloadTelemetryOutcomeMetric, 0);
 }
 
diff --git a/chrome/browser/spellchecker/spell_check_host_chrome_impl.cc b/chrome/browser/spellchecker/spell_check_host_chrome_impl.cc
index cb170a0..e67de10 100644
--- a/chrome/browser/spellchecker/spell_check_host_chrome_impl.cc
+++ b/chrome/browser/spellchecker/spell_check_host_chrome_impl.cc
@@ -27,7 +27,7 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif
 
 namespace {
diff --git a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
index f648102..6db2a6a 100644
--- a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
+++ b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
@@ -348,14 +348,14 @@
 
   // Verify that we are not evaluating subframe loads.
   EXPECT_FALSE(observer.GetSubframeLoadPolicy(ad_url).has_value());
-  EXPECT_FALSE(*observer.GetIsAdSubframe(ad_frame->GetFrameTreeNodeId()));
+  EXPECT_FALSE(observer.GetIsAdSubframe(ad_frame->GetFrameTreeNodeId()));
 
   // Child frame created by ad script.
   RenderFrameHost* ad_frame_tagged_by_script = CreateSrcFrameFromAdScript(
       GetWebContents(), GetURL("frame_factory.html?1"));
 
   // No frames should be detected by script heuristics.
-  EXPECT_FALSE(*observer.GetIsAdSubframe(
+  EXPECT_FALSE(observer.GetIsAdSubframe(
       ad_frame_tagged_by_script->GetFrameTreeNodeId()));
 }
 
@@ -375,14 +375,14 @@
 
   // Verify that we are evaluating subframe loads.
   EXPECT_TRUE(observer.GetSubframeLoadPolicy(ad_url).has_value());
-  EXPECT_TRUE(*observer.GetIsAdSubframe(ad_frame->GetFrameTreeNodeId()));
+  EXPECT_TRUE(observer.GetIsAdSubframe(ad_frame->GetFrameTreeNodeId()));
 
   // Child frame created by ad script.
   RenderFrameHost* ad_frame_tagged_by_script = CreateSrcFrameFromAdScript(
       GetWebContents(), GetURL("frame_factory.html?1"));
 
   // Frames should be detected by script heuristics.
-  EXPECT_TRUE(*observer.GetIsAdSubframe(
+  EXPECT_TRUE(observer.GetIsAdSubframe(
       ad_frame_tagged_by_script->GetFrameTreeNodeId()));
 }
 
@@ -391,18 +391,18 @@
 
   // Main frame.
   ui_test_utils::NavigateToURL(browser(), GetURL("frame_factory.html"));
-  EXPECT_FALSE(*observer.GetIsAdSubframe(
+  EXPECT_FALSE(observer.GetIsAdSubframe(
       GetWebContents()->GetMainFrame()->GetFrameTreeNodeId()));
 
   // (1) Vanilla child.
   content::RenderFrameHost* vanilla_child =
       CreateSrcFrame(GetWebContents(), GetURL("frame_factory.html?1"));
-  EXPECT_FALSE(*observer.GetIsAdSubframe(vanilla_child->GetFrameTreeNodeId()));
+  EXPECT_FALSE(observer.GetIsAdSubframe(vanilla_child->GetFrameTreeNodeId()));
 
   // (2) Ad child.
   RenderFrameHost* ad_child =
       CreateSrcFrame(GetWebContents(), GetURL("frame_factory.html?2&ad=true"));
-  EXPECT_TRUE(*observer.GetIsAdSubframe(ad_child->GetFrameTreeNodeId()));
+  EXPECT_TRUE(observer.GetIsAdSubframe(ad_child->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       ad_child, /*parent_is_ad=*/false,
       FilterListEvidence::kMatchedBlockingRule,
@@ -411,7 +411,7 @@
   // (3) Ad child of 2.
   RenderFrameHost* ad_child_2 =
       CreateSrcFrame(ad_child, GetURL("frame_factory.html?sub=1&3&ad=true"));
-  EXPECT_TRUE(*observer.GetIsAdSubframe(ad_child_2->GetFrameTreeNodeId()));
+  EXPECT_TRUE(observer.GetIsAdSubframe(ad_child_2->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       ad_child_2, /*parent_is_ad=*/true, FilterListEvidence::kNeverChecked,
       ScriptHeuristicEvidence::kCreatedByAdScript);
@@ -419,7 +419,7 @@
   // (4) Vanilla child of 2.
   RenderFrameHost* vanilla_child_2 =
       CreateSrcFrame(ad_child, GetURL("frame_factory.html?4"));
-  EXPECT_TRUE(*observer.GetIsAdSubframe(vanilla_child_2->GetFrameTreeNodeId()));
+  EXPECT_TRUE(observer.GetIsAdSubframe(vanilla_child_2->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       vanilla_child_2, /*parent_is_ad=*/true, FilterListEvidence::kNeverChecked,
       ScriptHeuristicEvidence::kCreatedByAdScript);
@@ -431,8 +431,7 @@
   // it's able to create an iframe that's not labeled as an ad.
   RenderFrameHost* vanilla_child_3 =
       CreateSrcFrame(vanilla_child, GetURL("frame_factory.html?5"));
-  EXPECT_FALSE(
-      *observer.GetIsAdSubframe(vanilla_child_3->GetFrameTreeNodeId()));
+  EXPECT_FALSE(observer.GetIsAdSubframe(vanilla_child_3->GetFrameTreeNodeId()));
 }
 
 const char kSubresourceFilterOriginStatusHistogram[] =
@@ -530,7 +529,7 @@
   // Child frame created by ad script.
   RenderFrameHost* ad_child = CreateSrcFrameFromAdScript(
       GetWebContents(), GetURL("frame_factory.html?1"));
-  EXPECT_TRUE(*observer.GetIsAdSubframe(ad_child->GetFrameTreeNodeId()));
+  EXPECT_TRUE(observer.GetIsAdSubframe(ad_child->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       ad_child, /*parent_is_ad=*/false, FilterListEvidence::kNeverChecked,
       ScriptHeuristicEvidence::kCreatedByAdScript);
@@ -546,7 +545,7 @@
   // (1) Vanilla child.
   content::RenderFrameHost* vanilla_frame =
       CreateDocWrittenFrame(GetWebContents());
-  EXPECT_FALSE(*observer.GetIsAdSubframe(vanilla_frame->GetFrameTreeNodeId()));
+  EXPECT_FALSE(observer.GetIsAdSubframe(vanilla_frame->GetFrameTreeNodeId()));
 
   // (2) Ad child.
   content::RenderFrameHost* ad_frame =
@@ -568,17 +567,17 @@
   // Vanilla frame and descendants
   content::RenderFrameHost* vanilla_frame =
       CreateDocWrittenFrame(GetWebContents());
-  EXPECT_FALSE(*observer.GetIsAdSubframe(vanilla_frame->GetFrameTreeNodeId()));
+  EXPECT_FALSE(observer.GetIsAdSubframe(vanilla_frame->GetFrameTreeNodeId()));
 
   content::RenderFrameHost* vanilla_child_of_vanilla =
       CreateSrcFrame(vanilla_frame, GetURL("frame_factory.html"));
-  EXPECT_FALSE(*observer.GetIsAdSubframe(
-      vanilla_child_of_vanilla->GetFrameTreeNodeId()));
+  EXPECT_FALSE(
+      observer.GetIsAdSubframe(vanilla_child_of_vanilla->GetFrameTreeNodeId()));
 
   content::RenderFrameHost* ad_child_of_vanilla =
       CreateSrcFrameFromAdScript(vanilla_frame, GetURL("frame_factory.html"));
   EXPECT_TRUE(
-      *observer.GetIsAdSubframe(ad_child_of_vanilla->GetFrameTreeNodeId()));
+      observer.GetIsAdSubframe(ad_child_of_vanilla->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       ad_child_of_vanilla, /*parent_is_ad=*/false,
       FilterListEvidence::kNeverChecked,
@@ -594,7 +593,7 @@
   content::RenderFrameHost* vanilla_child_of_ad =
       CreateSrcFrame(ad_frame, GetURL("frame_factory.html"));
   EXPECT_TRUE(
-      *observer.GetIsAdSubframe(vanilla_child_of_ad->GetFrameTreeNodeId()));
+      observer.GetIsAdSubframe(vanilla_child_of_ad->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       vanilla_child_of_ad, /*parent_is_ad=*/true,
       FilterListEvidence::kNeverChecked,
@@ -602,7 +601,7 @@
 
   content::RenderFrameHost* ad_child_of_ad =
       CreateSrcFrameFromAdScript(ad_frame, GetURL("frame_factory.html"));
-  EXPECT_TRUE(*observer.GetIsAdSubframe(ad_child_of_ad->GetFrameTreeNodeId()));
+  EXPECT_TRUE(observer.GetIsAdSubframe(ad_child_of_ad->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       ad_child_of_ad, /*parent_is_ad=*/true, FilterListEvidence::kNeverChecked,
       ScriptHeuristicEvidence::kCreatedByAdScript);
@@ -620,13 +619,13 @@
   // Vanilla child.
   content::RenderFrameHost* vanilla_frame_with_aborted_load =
       CreateFrameWithDocWriteAbortedLoad(GetWebContents());
-  EXPECT_FALSE(*observer.GetIsAdSubframe(
+  EXPECT_FALSE(observer.GetIsAdSubframe(
       vanilla_frame_with_aborted_load->GetFrameTreeNodeId()));
 
   // Child created by ad script.
   content::RenderFrameHost* ad_frame_with_aborted_load =
       CreateFrameWithDocWriteAbortedLoadFromAdScript(GetWebContents());
-  EXPECT_TRUE(*observer.GetIsAdSubframe(
+  EXPECT_TRUE(observer.GetIsAdSubframe(
       ad_frame_with_aborted_load->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       ad_frame_with_aborted_load, /*parent_is_ad=*/false,
@@ -638,8 +637,8 @@
       GetWebContents(), GetURL("frame_factory.html"));
   content::RenderFrameHost* child_frame_of_ad_with_aborted_load =
       CreateFrameWithDocWriteAbortedLoad(ad_frame);
-  EXPECT_TRUE(*observer.GetIsAdSubframe(ad_frame->GetFrameTreeNodeId()));
-  EXPECT_TRUE(*observer.GetIsAdSubframe(
+  EXPECT_TRUE(observer.GetIsAdSubframe(ad_frame->GetFrameTreeNodeId()));
+  EXPECT_TRUE(observer.GetIsAdSubframe(
       child_frame_of_ad_with_aborted_load->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       child_frame_of_ad_with_aborted_load, /*parent_is_ad=*/true,
@@ -659,13 +658,13 @@
   // Vanilla child.
   content::RenderFrameHost* vanilla_frame_with_aborted_load =
       CreateFrameWithWindowStopAbortedLoad(GetWebContents());
-  EXPECT_FALSE(*observer.GetIsAdSubframe(
+  EXPECT_FALSE(observer.GetIsAdSubframe(
       vanilla_frame_with_aborted_load->GetFrameTreeNodeId()));
 
   // Child created by ad script.
   content::RenderFrameHost* ad_frame_with_aborted_load =
       CreateFrameWithWindowStopAbortedLoadFromAdScript(GetWebContents());
-  EXPECT_TRUE(*observer.GetIsAdSubframe(
+  EXPECT_TRUE(observer.GetIsAdSubframe(
       ad_frame_with_aborted_load->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       ad_frame_with_aborted_load, /*parent_is_ad=*/false,
@@ -677,8 +676,8 @@
       GetWebContents(), GetURL("frame_factory.html"));
   content::RenderFrameHost* child_frame_of_ad_with_aborted_load =
       CreateFrameWithWindowStopAbortedLoad(ad_frame);
-  EXPECT_TRUE(*observer.GetIsAdSubframe(ad_frame->GetFrameTreeNodeId()));
-  EXPECT_TRUE(*observer.GetIsAdSubframe(
+  EXPECT_TRUE(observer.GetIsAdSubframe(ad_frame->GetFrameTreeNodeId()));
+  EXPECT_TRUE(observer.GetIsAdSubframe(
       child_frame_of_ad_with_aborted_load->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       child_frame_of_ad_with_aborted_load, /*parent_is_ad=*/true,
@@ -703,13 +702,13 @@
 
   content::RenderFrameHost* vanilla_child_of_vanilla = CreateSrcFrame(
       vanilla_frame_with_aborted_load, GetURL("frame_factory.html"));
-  EXPECT_FALSE(*observer.GetIsAdSubframe(
-      vanilla_child_of_vanilla->GetFrameTreeNodeId()));
+  EXPECT_FALSE(
+      observer.GetIsAdSubframe(vanilla_child_of_vanilla->GetFrameTreeNodeId()));
 
   content::RenderFrameHost* ad_child_of_vanilla = CreateSrcFrameFromAdScript(
       vanilla_frame_with_aborted_load, GetURL("frame_factory.html"));
   EXPECT_TRUE(
-      *observer.GetIsAdSubframe(ad_child_of_vanilla->GetFrameTreeNodeId()));
+      observer.GetIsAdSubframe(ad_child_of_vanilla->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       ad_child_of_vanilla, /*parent_is_ad=*/false,
       FilterListEvidence::kNeverChecked,
@@ -719,7 +718,7 @@
   // this ad frame should be tagged as ads.
   content::RenderFrameHost* ad_frame_with_aborted_load =
       CreateFrameWithDocWriteAbortedLoadFromAdScript(GetWebContents());
-  EXPECT_TRUE(*observer.GetIsAdSubframe(
+  EXPECT_TRUE(observer.GetIsAdSubframe(
       ad_frame_with_aborted_load->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       ad_frame_with_aborted_load, /*parent_is_ad=*/false,
@@ -729,7 +728,7 @@
   content::RenderFrameHost* vanilla_child_of_ad =
       CreateSrcFrame(ad_frame_with_aborted_load, GetURL("frame_factory.html"));
   EXPECT_TRUE(
-      *observer.GetIsAdSubframe(vanilla_child_of_ad->GetFrameTreeNodeId()));
+      observer.GetIsAdSubframe(vanilla_child_of_ad->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       vanilla_child_of_ad, /*parent_is_ad=*/true,
       FilterListEvidence::kNeverChecked,
@@ -737,7 +736,7 @@
 
   content::RenderFrameHost* ad_child_of_ad = CreateSrcFrameFromAdScript(
       ad_frame_with_aborted_load, GetURL("frame_factory.html"));
-  EXPECT_TRUE(*observer.GetIsAdSubframe(ad_child_of_ad->GetFrameTreeNodeId()));
+  EXPECT_TRUE(observer.GetIsAdSubframe(ad_child_of_ad->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       ad_child_of_ad, /*parent_is_ad=*/true, FilterListEvidence::kNeverChecked,
       ScriptHeuristicEvidence::kCreatedByAdScript);
@@ -761,13 +760,13 @@
 
   content::RenderFrameHost* vanilla_child_of_vanilla = CreateSrcFrame(
       vanilla_frame_with_aborted_load, GetURL("frame_factory.html"));
-  EXPECT_FALSE(*observer.GetIsAdSubframe(
-      vanilla_child_of_vanilla->GetFrameTreeNodeId()));
+  EXPECT_FALSE(
+      observer.GetIsAdSubframe(vanilla_child_of_vanilla->GetFrameTreeNodeId()));
 
   content::RenderFrameHost* ad_child_of_vanilla = CreateSrcFrameFromAdScript(
       vanilla_frame_with_aborted_load, GetURL("frame_factory.html"));
   EXPECT_TRUE(
-      *observer.GetIsAdSubframe(ad_child_of_vanilla->GetFrameTreeNodeId()));
+      observer.GetIsAdSubframe(ad_child_of_vanilla->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       ad_child_of_vanilla, /*parent_is_ad=*/false,
       FilterListEvidence::kNeverChecked,
@@ -777,7 +776,7 @@
   // this ad frame should be tagged as ads.
   content::RenderFrameHost* ad_frame_with_aborted_load =
       CreateFrameWithWindowStopAbortedLoadFromAdScript(GetWebContents());
-  EXPECT_TRUE(*observer.GetIsAdSubframe(
+  EXPECT_TRUE(observer.GetIsAdSubframe(
       ad_frame_with_aborted_load->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       ad_frame_with_aborted_load, /*parent_is_ad=*/false,
@@ -787,7 +786,7 @@
   content::RenderFrameHost* vanilla_child_of_ad =
       CreateSrcFrame(ad_frame_with_aborted_load, GetURL("frame_factory.html"));
   EXPECT_TRUE(
-      *observer.GetIsAdSubframe(vanilla_child_of_ad->GetFrameTreeNodeId()));
+      observer.GetIsAdSubframe(vanilla_child_of_ad->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       vanilla_child_of_ad, /*parent_is_ad=*/true,
       FilterListEvidence::kNeverChecked,
@@ -795,7 +794,7 @@
 
   content::RenderFrameHost* ad_child_of_ad = CreateSrcFrameFromAdScript(
       ad_frame_with_aborted_load, GetURL("frame_factory.html"));
-  EXPECT_TRUE(*observer.GetIsAdSubframe(ad_child_of_ad->GetFrameTreeNodeId()));
+  EXPECT_TRUE(observer.GetIsAdSubframe(ad_child_of_ad->GetFrameTreeNodeId()));
   observer.VerifyEvidenceForAdSubframe(
       vanilla_child_of_ad, /*parent_is_ad=*/true,
       FilterListEvidence::kNeverChecked,
diff --git a/chrome/browser/subresource_filter/subresource_filter_unittest.cc b/chrome/browser/subresource_filter/subresource_filter_unittest.cc
index daaa211e..ea043d7 100644
--- a/chrome/browser/subresource_filter/subresource_filter_unittest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_unittest.cc
@@ -134,7 +134,7 @@
   SimulateNavigateAndCommit(GURL(allowed_url), subframe);
   EXPECT_EQ(subresource_filter::LoadPolicy::ALLOW,
             *observer.GetSubframeLoadPolicy(allowed_url));
-  EXPECT_FALSE(*observer.GetIsAdSubframe(subframe->GetFrameTreeNodeId()));
+  EXPECT_FALSE(observer.GetIsAdSubframe(subframe->GetFrameTreeNodeId()));
 }
 
 TEST_F(SubresourceFilterTest, SimpleDisallowedLoad_WithObserver) {
@@ -160,7 +160,7 @@
 
   EXPECT_EQ(subresource_filter::LoadPolicy::DISALLOW,
             *observer.GetSubframeLoadPolicy(disallowed_url));
-  EXPECT_TRUE(*observer.GetIsAdSubframe(subframe->GetFrameTreeNodeId()));
+  EXPECT_TRUE(observer.GetIsAdSubframe(subframe->GetFrameTreeNodeId()));
 }
 
 TEST_F(SubresourceFilterTest, RefreshMetadataOnActivation) {
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 6fee653..c12e8b6 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -123,6 +123,7 @@
 #endif  // defined(OS_ANDROID)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/printing/printers_sync_bridge.h"
@@ -138,7 +139,6 @@
 #include "chrome/browser/ui/app_list/arc/arc_package_sync_model_type_controller.h"
 #include "chrome/browser/ui/app_list/arc/arc_package_syncable_service.h"
 #include "chromeos/components/sync_wifi/wifi_configuration_sync_service.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/arc/arc_util.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc
index 39f723c..89e796cc 100644
--- a/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -72,9 +72,9 @@
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/chromeos/printing/synced_printers_manager_factory.h"
 #include "chrome/browser/sync/wifi_configuration_sync_service_factory.h"
-#include "chromeos/constants/chromeos_features.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace {
diff --git a/chrome/browser/sync/profile_sync_service_factory_unittest.cc b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
index f6bc10e..320b638 100644
--- a/chrome/browser/sync/profile_sync_service_factory_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
@@ -28,11 +28,11 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/sync/wifi_configuration_sync_service_factory.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
 #include "chromeos/components/sync_wifi/wifi_configuration_sync_service.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/shill/shill_clients.h"
 #include "chromeos/dbus/shill/shill_manager_client.h"
 #include "chromeos/network/network_handler.h"
diff --git a/chrome/browser/sync/sync_error_notifier_ash_unittest.cc b/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
index 9feafab0..d06a3cd1 100644
--- a/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
+++ b/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/login/users/mock_user_manager.h"
@@ -13,7 +14,6 @@
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/sync/driver/test_sync_service.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc
index 8e1c59e..3c0b3320b 100644
--- a/chrome/browser/sync/sync_ui_util.cc
+++ b/chrome/browser/sync/sync_ui_util.cc
@@ -25,7 +25,7 @@
 #include "net/base/url_util.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif
 
 namespace sync_ui_util {
diff --git a/chrome/browser/sync/sync_ui_util_unittest.cc b/chrome/browser/sync/sync_ui_util_unittest.cc
index dbff9d92..a873857 100644
--- a/chrome/browser/sync/sync_ui_util_unittest.cc
+++ b/chrome/browser/sync/sync_ui_util_unittest.cc
@@ -19,8 +19,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #endif
 
 namespace sync_ui_util {
diff --git a/chrome/browser/sync/test/integration/os_sync_test.cc b/chrome/browser/sync/test/integration/os_sync_test.cc
index d2c55f60..219d710 100644
--- a/chrome/browser/sync/test/integration/os_sync_test.cc
+++ b/chrome/browser/sync/test/integration/os_sync_test.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/sync/test/integration/os_sync_test.h"
 
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 
 OsSyncTest::OsSyncTest(TestType type) : SyncTest(type) {
   settings_feature_list_.InitAndEnableFeature(
diff --git a/chrome/browser/sync/test/integration/single_client_app_list_sync_test.cc b/chrome/browser/sync/test/integration/single_client_app_list_sync_test.cc
index 0181dd9..e6dedb3 100644
--- a/chrome/browser/sync/test/integration/single_client_app_list_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_app_list_sync_test.cc
@@ -4,6 +4,7 @@
 
 #include <stddef.h>
 
+#include "ash/constants/ash_features.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
@@ -18,7 +19,6 @@
 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
 #include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h"
 #include "chrome/browser/ui/app_list/page_break_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/sync/base/user_selectable_type.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/driver/sync_user_settings.h"
diff --git a/chrome/browser/sync/test/integration/single_client_app_settings_sync_test.cc b/chrome/browser/sync/test/integration/single_client_app_settings_sync_test.cc
index 35f2edd..f02a3a46 100644
--- a/chrome/browser/sync/test/integration/single_client_app_settings_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_app_settings_sync_test.cc
@@ -12,8 +12,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/sync/test/integration/os_sync_test.h"
-#include "chromeos/constants/chromeos_features.h"
 #endif
 
 using syncer::UserSelectableType;
diff --git a/chrome/browser/sync/test/integration/single_client_arc_package_sync_test.cc b/chrome/browser/sync/test/integration/single_client_arc_package_sync_test.cc
index e7213ed..221c49f 100644
--- a/chrome/browser/sync/test/integration/single_client_arc_package_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_arc_package_sync_test.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/constants/ash_features.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/test/integration/os_sync_test.h"
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
@@ -9,7 +10,6 @@
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
 #include "chrome/browser/ui/app_list/arc/arc_package_syncable_service.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/test/fake_server/fake_server.h"
diff --git a/chrome/browser/sync/test/integration/single_client_extension_apps_sync_test.cc b/chrome/browser/sync/test/integration/single_client_extension_apps_sync_test.cc
index 817f7a8a..46093a8 100644
--- a/chrome/browser/sync/test/integration/single_client_extension_apps_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_extension_apps_sync_test.cc
@@ -12,8 +12,8 @@
 #include "content/public/test/browser_test.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/sync/test/integration/os_sync_test.h"
-#include "chromeos/constants/chromeos_features.h"
 #endif
 
 using apps_helper::AllProfilesHaveSameApps;
diff --git a/chrome/browser/sync/test/integration/single_client_os_preferences_sync_test.cc b/chrome/browser/sync/test/integration/single_client_os_preferences_sync_test.cc
index 7a62a30..43964844 100644
--- a/chrome/browser/sync/test/integration/single_client_os_preferences_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_os_preferences_sync_test.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 "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/shelf_prefs.h"
 #include "chrome/browser/sync/test/integration/os_sync_test.h"
 #include "chrome/browser/sync/test/integration/preferences_helper.h"
 #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/driver/sync_service.h"
diff --git a/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc b/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
index 3ef7486c..e251d2384 100644
--- a/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
@@ -22,8 +22,8 @@
 #include "content/public/test/browser_test.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/sync/test/integration/os_sync_test.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/browser_sync/browser_sync_switches.h"
 #endif
 
diff --git a/chrome/browser/sync/test/integration/single_client_web_apps_sync_test.cc b/chrome/browser/sync/test/integration/single_client_web_apps_sync_test.cc
index 004caf6..bbc9bcee 100644
--- a/chrome/browser/sync/test/integration/single_client_web_apps_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_web_apps_sync_test.cc
@@ -12,8 +12,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/sync/test/integration/os_sync_test.h"
-#include "chromeos/constants/chromeos_features.h"
 #endif
 
 using syncer::UserSelectableType;
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index b9b2862..8940bd9 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -86,11 +86,11 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/components/account_manager/account_manager.h"
 #include "ash/components/account_manager/account_manager_factory.h"
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/sync/test/integration/printers_helper.h"
 #include "chrome/browser/sync/test/integration/sync_arc_package_helper.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
 #include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/arc/arc_util.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/sync/test/integration/two_client_app_list_sync_test.cc b/chrome/browser/sync/test/integration/two_client_app_list_sync_test.cc
index e342d01..e4ca656 100644
--- a/chrome/browser/sync/test/integration/two_client_app_list_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_app_list_sync_test.cc
@@ -4,6 +4,7 @@
 
 #include <stddef.h>
 
+#include "ash/constants/ash_features.h"
 #include "base/macros.h"
 #include "base/one_shot_event.h"
 #include "base/run_loop.h"
@@ -19,7 +20,6 @@
 #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/base/user_selectable_type.h"
diff --git a/chrome/browser/sync/test/integration/two_client_extension_settings_and_app_settings_sync_test.cc b/chrome/browser/sync/test/integration/two_client_extension_settings_and_app_settings_sync_test.cc
index 9b868d69..781c815 100644
--- a/chrome/browser/sync/test/integration/two_client_extension_settings_and_app_settings_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_extension_settings_and_app_settings_sync_test.cc
@@ -15,8 +15,8 @@
 #include "content/public/test/browser_test.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/sync/test/integration/os_sync_test.h"
-#include "chromeos/constants/chromeos_features.h"
 #endif
 
 namespace {
diff --git a/chrome/browser/tflite_experiment/tflite_experiment_keyed_service_browsertest.cc b/chrome/browser/tflite_experiment/tflite_experiment_keyed_service_browsertest.cc
index 87e9d441..7a6a8243 100644
--- a/chrome/browser/tflite_experiment/tflite_experiment_keyed_service_browsertest.cc
+++ b/chrome/browser/tflite_experiment/tflite_experiment_keyed_service_browsertest.cc
@@ -95,15 +95,18 @@
   ~TFLiteExperimentKeyedServiceBrowserTest() override = default;
 
   void SetUpCommandLine(base::CommandLine* cmd) override {
-    // Location of test data.
-    base::FilePath g_test_data_directory;
+    base::FilePath model_file_path;
 
-    // Set TFLite model path.
-    base::PathService::Get(chrome::DIR_TEST_DATA, &g_test_data_directory);
-    g_test_data_directory =
-        g_test_data_directory.Append(FILE_PATH_LITERAL("simple_test.tflite"));
+    EXPECT_TRUE(
+        base::PathService::Get(base::DIR_SOURCE_ROOT, &model_file_path));
+
+    model_file_path = model_file_path.Append(FILE_PATH_LITERAL("components"))
+                          .Append(FILE_PATH_LITERAL("test"))
+                          .Append(FILE_PATH_LITERAL("data"))
+                          .Append(FILE_PATH_LITERAL("optimization_guide"))
+                          .Append(FILE_PATH_LITERAL("simple_test.tflite"));
     cmd->AppendSwitchASCII(tflite_experiment::switches::kTFLiteModelPath,
-                           g_test_data_directory.MaybeAsASCII());
+                           model_file_path.MaybeAsASCII());
 
     // Set TFLite experiment log path.
     cmd->AppendSwitchASCII(
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index b71d042..42dd7f8 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -384,6 +384,7 @@
     "//chrome/browser/safe_browsing",
     "//chrome/browser/ui/webui/bluetooth_internals",
     "//chrome/browser/ui/webui/downloads:mojo_bindings",
+    "//chrome/browser/ui/webui/memories:mojo_bindings",
     "//chrome/browser/ui/webui/new_tab_page:mojo_bindings",
     "//chrome/browser/ui/webui/omnibox:mojo_bindings",
     "//chrome/browser/ui/webui/read_later:mojo_bindings",
@@ -1387,6 +1388,10 @@
       "webui/media_router/media_router_internals_webui_message_handler.cc",
       "webui/media_router/media_router_internals_webui_message_handler.h",
       "webui/media_router/web_contents_display_observer.h",
+      "webui/memories/memories_handler.cc",
+      "webui/memories/memories_handler.h",
+      "webui/memories/memories_ui.cc",
+      "webui/memories/memories_ui.h",
       "webui/new_tab_page/new_tab_page_handler.cc",
       "webui/new_tab_page/new_tab_page_handler.h",
       "webui/new_tab_page/new_tab_page_ui.cc",
diff --git a/chrome/browser/ui/app_list/app_context_menu_unittest.cc b/chrome/browser/ui/app_list/app_context_menu_unittest.cc
index aefbeb35..51edabb 100644
--- a/chrome/browser/ui/app_list/app_context_menu_unittest.cc
+++ b/chrome/browser/ui/app_list/app_context_menu_unittest.cc
@@ -8,6 +8,7 @@
 #include <unordered_set>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_menu_constants.h"
 #include "base/bind.h"
 #include "base/json/json_file_value_serializer.h"
@@ -39,7 +40,6 @@
 #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/arc/test/fake_app_instance.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/services/app_service/public/cpp/app_update.h"
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
index b34d37e..be969be8 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -9,6 +9,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/containers/contains.h"
 #include "base/containers/flat_set.h"
@@ -36,7 +37,6 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
diff --git a/chrome/browser/ui/app_list/arc/arc_package_sync_model_type_controller.cc b/chrome/browser/ui/app_list/arc/arc_package_sync_model_type_controller.cc
index 7924884..b9f6fb9 100644
--- a/chrome/browser/ui/app_list/arc/arc_package_sync_model_type_controller.cc
+++ b/chrome/browser/ui/app_list/arc/arc_package_sync_model_type_controller.cc
@@ -7,11 +7,11 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/driver/sync_service.h"
diff --git a/chrome/browser/ui/app_list/search/arc/arc_app_reinstall_search_provider.cc b/chrome/browser/ui/app_list/search/arc/arc_app_reinstall_search_provider.cc
index 4afdd2d7..0a7e1364 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_app_reinstall_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/arc/arc_app_reinstall_search_provider.cc
@@ -8,6 +8,7 @@
 #include <unordered_set>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/metrics/field_trial_params.h"
@@ -22,7 +23,6 @@
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
 #include "chrome/browser/ui/app_list/search/common/url_icon_source.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/session/arc_bridge_service.h"
diff --git a/chrome/browser/ui/app_list/search/arc/arc_app_reinstall_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/arc/arc_app_reinstall_search_provider_unittest.cc
index 0098ca7..5cb4c7c 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_app_reinstall_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/arc/arc_app_reinstall_search_provider_unittest.cc
@@ -7,6 +7,7 @@
 #include <map>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
@@ -21,7 +22,6 @@
 #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/arc/mojom/app.mojom.h"
 #include "components/arc/test/fake_app_instance.h"
 #include "components/prefs/scoped_user_pref_update.h"
diff --git a/chrome/browser/ui/ash/DEPS b/chrome/browser/ui/ash/DEPS
index ab683be..e4113bb 100644
--- a/chrome/browser/ui/ash/DEPS
+++ b/chrome/browser/ui/ash/DEPS
@@ -9,14 +9,15 @@
 
 specific_include_rules = {
   ".*test.*": [
-   "!ash",
-   "+ash/shortcut_viewer",
-   "+ash/shortcut_viewer/strings/grit/shortcut_viewer_strings.h",
-   "+ash/keyboard/ui",
-   "+ash/public",
-   "+ash/assistant/ui/assistant_ui_constants.h",
-   "+ash/assistant/ui/main_stage/assistant_ui_element_view.h",
-   "+ui/message_center/message_center.h",
+    "!ash",
+    "+ash/constants",
+    "+ash/shortcut_viewer",
+    "+ash/shortcut_viewer/strings/grit/shortcut_viewer_strings.h",
+    "+ash/keyboard/ui",
+    "+ash/public",
+    "+ash/assistant/ui/assistant_ui_constants.h",
+    "+ash/assistant/ui/main_stage/assistant_ui_element_view.h",
+    "+ui/message_center/message_center.h",
   ],
   "ash_shell_init\.cc": [
     "+ash",
diff --git a/chrome/browser/ui/ash/ambient/ambient_client_impl.cc b/chrome/browser/ui/ash/ambient/ambient_client_impl.cc
index b6fc4cc..2f32899 100644
--- a/chrome/browser/ui/ash/ambient/ambient_client_impl.cc
+++ b/chrome/browser/ui/ash/ambient/ambient_client_impl.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ambient/ambient_prefs.h"
 #include "base/callback.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
@@ -14,7 +15,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/common/channel_info.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/account_id/account_id.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/access_token_fetcher.h"
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
index b4e669c..da3da4d 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/media_notification_provider.h"
 #include "ash/public/cpp/shelf_model.h"
@@ -50,7 +51,6 @@
 #include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "chrome/browser/ui/views/select_file_dialog_extension.h"
 #include "chrome/browser/ui/views/select_file_dialog_extension_factory.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/network/network_connect.h"
 #include "chromeos/network/portal_detector/network_portal_detector.h"
 #include "components/session_manager/core/session_manager.h"
diff --git a/chrome/browser/ui/ash/chrome_launcher_prefs.cc b/chrome/browser/ui/ash/chrome_launcher_prefs.cc
index ee22c2b3..f8c09a4b9 100644
--- a/chrome/browser/ui/ash/chrome_launcher_prefs.cc
+++ b/chrome/browser/ui/ash/chrome_launcher_prefs.cc
@@ -9,6 +9,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/internal_app_id_constants.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "base/values.h"
@@ -30,7 +31,6 @@
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/crx_file/id_util.h"
 #include "components/pref_registry/pref_registry_syncable.h"
diff --git a/chrome/browser/ui/ash/clipboard_history_browsertest.cc b/chrome/browser/ui/ash/clipboard_history_browsertest.cc
index 237a3a5..600e135 100644
--- a/chrome/browser/ui/ash/clipboard_history_browsertest.cc
+++ b/chrome/browser/ui/ash/clipboard_history_browsertest.cc
@@ -11,6 +11,7 @@
 #include "ash/clipboard/clipboard_history_menu_model_adapter.h"
 #include "ash/clipboard/views/clipboard_history_delete_button.h"
 #include "ash/clipboard/views/clipboard_history_item_view.h"
+#include "ash/constants/ash_features.h"
 #include "ash/shell.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -22,7 +23,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.cc b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.cc
index 7fb165b..d0e3dd5 100644
--- a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.cc
+++ b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_types.h"
 #include "ash/public/cpp/multi_user_window_manager.h"
 #include "ash/public/cpp/shelf_item_delegate.h"
@@ -31,7 +32,6 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_helper.h"
 #include "chrome/common/chrome_features.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/views/widget/widget.h"
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_browsertest.cc b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_browsertest.cc
index 09fed9d..af1cb80 100644
--- a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_browsertest.cc
@@ -5,6 +5,7 @@
 #include <memory>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/shelf_model.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/shell.h"
@@ -29,7 +30,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/web_applications/components/web_application_info.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/session/arc_bridge_service.h"
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 8eae90b..46c69539 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -8,6 +8,7 @@
 #include <set>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_types.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/multi_user_window_manager.h"
@@ -78,7 +79,6 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "components/account_id/account_id.h"
 #include "components/arc/arc_prefs.h"
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index 8e74bc86..126a5e8 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -14,6 +14,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/display/display_configuration_controller.h"
 #include "ash/multi_user/multi_user_window_manager_impl.h"
 #include "ash/public/cpp/app_list/internal_app_id_constants.h"
@@ -101,7 +102,6 @@
 #include "chrome/test/base/test_browser_window_aura.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/account_id/account_id.h"
 #include "components/arc/arc_prefs.h"
diff --git a/chrome/browser/ui/ash/launcher_drag_interactive_uitest.cc b/chrome/browser/ui/ash/launcher_drag_interactive_uitest.cc
index 3972a204..b5bc3529c 100644
--- a/chrome/browser/ui/ash/launcher_drag_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/launcher_drag_interactive_uitest.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/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_types.h"
 #include "ash/public/cpp/ash_features.h"
@@ -17,7 +18,6 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/test/base/perf/drag_event_generator.h"
 #include "chrome/test/base/perf/performance_test.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "content/public/test/browser_test.h"
 #include "ui/base/test/ui_controls.h"
diff --git a/chrome/browser/ui/ash/media_client_impl.cc b/chrome/browser/ui/ash/media_client_impl.cc
index 6df17f3f..8292df42 100644
--- a/chrome/browser/ui/ash/media_client_impl.cc
+++ b/chrome/browser/ui/ash/media_client_impl.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/media_controller.h"
 #include "ash/public/cpp/notification_utils.h"
 #include "ash/public/cpp/toast_data.h"
@@ -35,7 +36,6 @@
 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/user_manager/user_manager.h"
 #include "components/vector_icons/vector_icons.h"
 #include "content/public/browser/media_session.h"
diff --git a/chrome/browser/ui/ash/system_tray_client.cc b/chrome/browser/ui/ash/system_tray_client.cc
index 6324682..5ad67b0 100644
--- a/chrome/browser/ui/ash/system_tray_client.cc
+++ b/chrome/browser/ui/ash/system_tray_client.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/ash/system_tray_client.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/locale_update_controller.h"
 #include "ash/public/cpp/system_tray.h"
 #include "ash/public/cpp/update_types.h"
@@ -38,7 +39,6 @@
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
 #include "chrome/browser/web_applications/components/web_app_id_constants.h"
 #include "chrome/common/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc
index a186a744..e1adfc11 100644
--- a/chrome/browser/ui/chrome_pages.cc
+++ b/chrome/browser/ui/chrome_pages.cc
@@ -60,13 +60,13 @@
 #include "url/url_util.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/browser/ui/webui/settings/chromeos/app_management/app_management_uma.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes_util.h"
 #include "chromeos/components/connectivity_diagnostics/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #else
 #include "chrome/browser/ui/signin_view_controller.h"
 #endif
diff --git a/chrome/browser/ui/views/DEPS b/chrome/browser/ui/views/DEPS
index 35bccc4..429d19a 100644
--- a/chrome/browser/ui/views/DEPS
+++ b/chrome/browser/ui/views/DEPS
@@ -22,6 +22,7 @@
   ],
   ".*test.*": [
    "!ash",
+   "+ash/constants",
    "+ash/public",
   ],
 }
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
index b29578c..496a83d 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -89,8 +89,7 @@
     const AppWindow::CreateParams& create_params) {
   ChromeNativeAppWindowViewsAura::InitializeWindow(app_window, create_params);
   aura::Window* window = GetNativeWindow();
-  window->SetProperty(aura::client::kAppType,
-                      static_cast<int>(ash::AppType::CHROME_APP));
+
   // Fullscreen doesn't always imply immersive mode (see
   // ShouldEnableImmersive()).
   window->SetProperty(chromeos::kImmersiveImpliedByFullscreen, false);
@@ -143,6 +142,8 @@
       full_restore::kWindowIdKey, app_window()->session_id().id());
   init_params->init_properties_container.SetProperty(
       full_restore::kAppIdKey, app_window()->extension_id());
+  init_params->init_properties_container.SetProperty(
+      aura::client::kAppType, static_cast<int>(ash::AppType::CHROME_APP));
 }
 
 std::unique_ptr<views::NonClientFrameView>
diff --git a/chrome/browser/ui/views/frame/DEPS b/chrome/browser/ui/views/frame/DEPS
index 1ab82166..e15cd24 100644
--- a/chrome/browser/ui/views/frame/DEPS
+++ b/chrome/browser/ui/views/frame/DEPS
@@ -3,11 +3,9 @@
   "browser_non_client_frame_view_chromeos\.*": [
     "+ash",
   ],
-  "browser_frame\.cc": [
-    "+components/full_restore/full_restore_utils.h",
-  ],
   "browser_frame_ash\.*": [
     "+ash",
+    "+components/full_restore/full_restore_utils.h",
   ],
   "dbus_appmenu\.*": [
     "+dbus",
diff --git a/chrome/browser/ui/views/frame/browser_frame.cc b/chrome/browser/ui/views/frame/browser_frame.cc
index 19bc732..2e1e5a88 100644
--- a/chrome/browser/ui/views/frame/browser_frame.cc
+++ b/chrome/browser/ui/views/frame/browser_frame.cc
@@ -38,7 +38,6 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/desks_helper.h"
-#include "components/full_restore/full_restore_utils.h"
 #include "components/user_manager/user_manager.h"
 #endif
 
@@ -84,29 +83,22 @@
   views::Widget::InitParams params = native_browser_frame_->GetWidgetParams();
   params.name = "BrowserFrame";
   params.delegate = browser_view_;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  params.init_properties_container.SetProperty(
-      full_restore::kWindowIdKey, browser_view_->browser()->session_id().id());
-  params.init_properties_container.SetProperty(
-      full_restore::kRestoreWindowIdKey,
-      browser_view_->browser()->create_params().restore_id);
-#endif
-  if (browser_view_->browser()->is_type_normal() ||
-      browser_view_->browser()->is_type_devtools() ||
-      browser_view_->browser()->is_type_app()) {
+
+  Browser* browser = browser_view_->browser();
+  if (browser->is_type_normal() || browser->is_type_devtools() ||
+      browser->is_type_app()) {
     // Typed panel/popup can only return a size once the widget has been
     // created.
     // DevTools counts as a popup, but DevToolsWindow::CreateDevToolsBrowser
     // ensures there is always a size available. Without this, the tools
     // launch on the wrong display and can have sizing issues when
     // repositioned to the saved bounds in Widget::SetInitialBounds.
-    chrome::GetSavedWindowBoundsAndShowState(browser_view_->browser(),
-                                             &params.bounds,
+    chrome::GetSavedWindowBoundsAndShowState(browser, &params.bounds,
                                              &params.show_state);
 
-    params.workspace = browser_view_->browser()->initial_workspace();
+    params.workspace = browser->initial_workspace();
     params.visible_on_all_workspaces =
-        browser_view_->browser()->initial_visible_on_all_workspaces_state();
+        browser->initial_visible_on_all_workspaces_state();
     const base::CommandLine& parsed_command_line =
         *base::CommandLine::ForCurrentProcess();
 
diff --git a/chrome/browser/ui/views/frame/browser_frame_ash.cc b/chrome/browser/ui/views/frame/browser_frame_ash.cc
index 36ec6e0..30c1e3a4 100644
--- a/chrome/browser/ui/views/frame/browser_frame_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_ash.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/public/cpp/app_types.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/shell.h"
 #include "ash/wm/window_properties.h"
@@ -18,6 +19,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chromeos/ui/base/window_state_type.h"
+#include "components/full_restore/full_restore_utils.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
@@ -140,6 +142,19 @@
   views::Widget::InitParams params;
   params.native_widget = this;
   params.context = ash::Shell::GetPrimaryRootWindow();
+
+  Browser* browser = browser_view_->browser();
+  params.init_properties_container.SetProperty(full_restore::kWindowIdKey,
+                                               browser->session_id().id());
+  params.init_properties_container.SetProperty(
+      full_restore::kRestoreWindowIdKey, browser->create_params().restore_id);
+
+  // This is only needed for ash. For lacros, Exo tags the associated
+  // ShellSurface as being of AppType::LACROS.
+  params.init_properties_container.SetProperty(
+      aura::client::kAppType,
+      static_cast<int>(browser->deprecated_is_app() ? ash::AppType::CHROME_APP
+                                                    : ash::AppType::BROWSER));
   return params;
 }
 
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
index 3df6e33..062c18f 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
@@ -62,7 +62,6 @@
 #endif  // BUILDFLAG(ENABLE_WEBUI_TAB_STRIP)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/public/cpp/app_types.h"
 #include "ash/wm/window_util.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_helper.h"
 #include "chrome/browser/ui/ash/session_util.h"
@@ -136,22 +135,14 @@
 
   UpdateProfileIcons();
 
-  aura::Window* window = frame()->GetNativeWindow();
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  // This is only needed for ash. For lacros, Exo tags the associated
-  // ShellSurface as being of AppType::LACROS.
-  window->SetProperty(
-      aura::client::kAppType,
-      static_cast<int>(browser->deprecated_is_app() ? ash::AppType::CHROME_APP
-                                                    : ash::AppType::BROWSER));
-#endif
-
   window_observation_.Observe(GetFrameWindow());
 
   // To preserve privacy, tag incognito windows so that they won't be included
   // in screenshot sent to assistant server.
-  if (browser->profile()->IsOffTheRecord())
-    window->SetProperty(chromeos::kBlockedForAssistantSnapshotKey, true);
+  if (browser->profile()->IsOffTheRecord()) {
+    frame()->GetNativeWindow()->SetProperty(
+        chromeos::kBlockedForAssistantSnapshotKey, true);
+  }
 
   display::Screen::GetScreen()->AddObserver(this);
 
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view.cc b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
index ac076ab..84d8510 100644
--- a/chrome/browser/ui/views/frame/tab_strip_region_view.cc
+++ b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
@@ -121,6 +121,11 @@
     canvas->DrawRect(GetContentsBounds(), flags);
   }
 
+  void OnThemeChanged() override {
+    View::OnThemeChanged();
+    SchedulePaint();
+  }
+
  private:
   TabStrip* tab_strip_;
   views::OverflowIndicatorAlignment side_;
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
index 72a99a3..d332adb 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
@@ -21,7 +21,7 @@
 #include "ui/base/resource/resource_bundle.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif
 
 namespace {
diff --git a/chrome/browser/ui/views/read_later/read_later_button.cc b/chrome/browser/ui/views/read_later/read_later_button.cc
index d894f98c..165cf9e 100644
--- a/chrome/browser/ui/views/read_later/read_later_button.cc
+++ b/chrome/browser/ui/views/read_later/read_later_button.cc
@@ -9,10 +9,12 @@
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/string16.h"
+#include "base/time/time.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/read_later/reading_list_model_factory.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/bubble/webui_bubble_dialog_view.h"
 #include "chrome/browser/ui/views/bubble/webui_bubble_view.h"
@@ -31,9 +33,11 @@
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/animation/flood_fill_ink_drop_ripple.h"
+#include "ui/views/animation/ink_drop.h"
 #include "ui/views/animation/ink_drop_highlight.h"
 #include "ui/views/animation/ink_drop_impl.h"
 #include "ui/views/animation/ink_drop_mask.h"
+#include "ui/views/background.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/button/button_controller.h"
@@ -75,6 +79,15 @@
       "Bookmarks.BookmarksBarStatus.OnReadingListOpened", state);
 }
 
+// Note this matches the background base layer alpha used in ToolbarButton.
+constexpr SkAlpha kBackgroundBaseLayerAlpha = 204;
+constexpr base::TimeDelta kHighlightShowDuration =
+    base::TimeDelta::FromMilliseconds(150);
+constexpr base::TimeDelta kHighlightHideDuration =
+    base::TimeDelta::FromMilliseconds(650);
+constexpr base::TimeDelta kHighlightDuration =
+    base::TimeDelta::FromMilliseconds(2250);
+
 }  // namespace
 
 ReadLaterButton::ReadLaterButton(Browser* browser)
@@ -91,7 +104,14 @@
       widget_open_timer_(base::BindRepeating([](base::TimeDelta time_elapsed) {
         base::UmaHistogramMediumTimes("ReadingList.WindowDisplayedDuration",
                                       time_elapsed);
-      })) {
+      })),
+      highlight_color_animation_(
+          std::make_unique<HighlightColorAnimation>(this)) {
+  reading_list_model_ =
+      ReadingListModelFactory::GetForBrowserContext(browser_->profile());
+  if (reading_list_model_)
+    reading_list_model_scoped_observation_.Observe(reading_list_model_);
+
   SetImageLabelSpacing(ChromeLayoutProvider::Get()->GetDistanceMetric(
       DISTANCE_RELATED_LABEL_HORIZONTAL_LIST));
 
@@ -135,11 +155,15 @@
   const ui::ThemeProvider* theme_provider = GetThemeProvider();
   if (!theme_provider)
     return;
-  const SkColor color =
-      theme_provider->GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON);
-  SetEnabledTextColors(color);
-  SetImageModel(views::Button::STATE_NORMAL,
-                ui::ImageModel::FromVectorIcon(kReadLaterIcon, color));
+  highlight_color_animation_->SetColor(
+      ToolbarButton::AdjustHighlightColorForContrast(
+          theme_provider, gfx::kGoogleBlue300, gfx::kGoogleBlue600,
+          gfx::kGoogleBlue050, gfx::kGoogleBlue900));
+  SetEnabledTextColors(highlight_color_animation_->GetTextColor());
+  SetImageModel(
+      views::Button::STATE_NORMAL,
+      ui::ImageModel::FromVectorIcon(
+          kReadLaterIcon, highlight_color_animation_->GetIconColor()));
 
   LabelButton::OnThemeChanged();
 }
@@ -151,9 +175,28 @@
   bubble_widget_observation_.Reset();
 }
 
+void ReadLaterButton::ReadingListModelBeingDeleted(
+    const ReadingListModel* model) {
+  DCHECK(model == reading_list_model_);
+  DCHECK(reading_list_model_scoped_observation_.IsObservingSource(
+      reading_list_model_));
+  reading_list_model_scoped_observation_.Reset();
+  reading_list_model_ = nullptr;
+}
+
+void ReadLaterButton::ReadingListDidAddEntry(const ReadingListModel* model,
+                                             const GURL& url,
+                                             reading_list::EntrySource source) {
+  if (source == reading_list::EntrySource::ADDED_VIA_CURRENT_APP &&
+      BrowserView::GetBrowserViewForBrowser(browser_)->IsActive()) {
+    highlight_color_animation_->Show();
+  }
+}
+
 void ReadLaterButton::ButtonPressed() {
   BrowserView* const browser_view =
       BrowserView::GetBrowserViewForBrowser(browser_);
+  highlight_color_animation_->Hide();
 
   if (browser_view->side_panel()) {
     if (!read_later_side_panel_bubble_) {
@@ -191,5 +234,129 @@
   }
 }
 
+void ReadLaterButton::UpdateColors() {
+  if (!GetThemeProvider())
+    return;
+
+  const int highlight_radius =
+      ChromeLayoutProvider::Get()->GetCornerRadiusMetric(
+          views::EMPHASIS_MAXIMUM, size());
+  SetEnabledTextColors(highlight_color_animation_->GetTextColor());
+  SetImageModel(
+      views::Button::STATE_NORMAL,
+      ui::ImageModel::FromVectorIcon(
+          kReadLaterIcon, highlight_color_animation_->GetIconColor()));
+  base::Optional<SkColor> background_color =
+      highlight_color_animation_->GetBackgroundColor();
+  if (background_color) {
+    SetBackground(views::CreateBackgroundFromPainter(
+        views::Painter::CreateSolidRoundRectPainter(
+            *background_color, highlight_radius, gfx::Insets(0))));
+  } else {
+    SetBackground(nullptr);
+  }
+}
+
+ReadLaterButton::HighlightColorAnimation::HighlightColorAnimation(
+    ReadLaterButton* parent)
+    : parent_(parent),
+      highlight_color_animation_(
+          std::vector<gfx::MultiAnimation::Part>{
+              gfx::MultiAnimation::Part(kHighlightShowDuration,
+                                        gfx::Tween::FAST_OUT_SLOW_IN),
+              gfx::MultiAnimation::Part(kHighlightDuration,
+                                        gfx::Tween::Type::LINEAR),
+              gfx::MultiAnimation::Part(kHighlightHideDuration,
+                                        gfx::Tween::FAST_OUT_SLOW_IN)},
+          gfx::MultiAnimation::kDefaultTimerInterval) {
+  highlight_color_animation_.set_delegate(this);
+  highlight_color_animation_.set_continuous(false);
+}
+
+ReadLaterButton::HighlightColorAnimation::~HighlightColorAnimation() = default;
+
+void ReadLaterButton::HighlightColorAnimation::Show() {
+  // Do nothing if an animation is already showing.
+  if (highlight_color_animation_.is_animating())
+    return;
+
+  highlight_color_animation_.Start();
+  parent_->UpdateColors();
+}
+
+void ReadLaterButton::HighlightColorAnimation::Hide() {
+  ClearHighlightColor();
+}
+
+SkColor ReadLaterButton::HighlightColorAnimation::GetTextColor() const {
+  SkColor original_text_color = color_utils::GetColorWithMaxContrast(
+      parent_->GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR));
+  return FadeWithAnimation(highlight_color_, original_text_color);
+}
+
+base::Optional<SkColor>
+ReadLaterButton::HighlightColorAnimation::GetBackgroundColor() const {
+  if (!highlight_color_animation_.is_animating())
+    return base::nullopt;
+  SkColor original_bg_color = SkColorSetA(
+      ToolbarButton::GetDefaultBackgroundColor(parent_->GetThemeProvider()),
+      kBackgroundBaseLayerAlpha);
+  SkColor highlight_bg_color = color_utils::GetResultingPaintColor(
+      SkColorSetA(highlight_color_, SkColorGetA(highlight_color_) *
+                                        kToolbarInkDropHighlightVisibleOpacity),
+      original_bg_color);
+  return FadeWithAnimation(highlight_bg_color, original_bg_color);
+}
+
+SkColor ReadLaterButton::HighlightColorAnimation::GetIconColor() const {
+  SkColor original_icon_color = parent_->GetThemeProvider()->GetColor(
+      ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON);
+  return FadeWithAnimation(highlight_color_, original_icon_color);
+}
+
+void ReadLaterButton::HighlightColorAnimation::AnimationEnded(
+    const gfx::Animation* animation) {
+  ClearHighlightColor();
+}
+
+void ReadLaterButton::HighlightColorAnimation::AnimationProgressed(
+    const gfx::Animation* animation) {
+  parent_->UpdateColors();
+}
+
+SkColor ReadLaterButton::HighlightColorAnimation::FadeWithAnimation(
+    SkColor target_color,
+    SkColor original_color) const {
+  if (!highlight_color_animation_.is_animating())
+    return original_color;
+
+  switch (highlight_color_animation_.current_part_index()) {
+    case 0:
+      // Fade in.
+      return gfx::Tween::ColorValueBetween(
+          highlight_color_animation_.GetCurrentValue(), original_color,
+          target_color);
+      break;
+    case 1:
+      // Highlight shown.
+      return target_color;
+      break;
+    case 2:
+      // Fade out.
+      return gfx::Tween::ColorValueBetween(
+          highlight_color_animation_.GetCurrentValue(), target_color,
+          original_color);
+      break;
+    default:
+      NOTREACHED();
+  }
+  return original_color;
+}
+
+void ReadLaterButton::HighlightColorAnimation::ClearHighlightColor() {
+  highlight_color_animation_.Stop();
+  parent_->UpdateColors();
+}
+
 BEGIN_METADATA(ReadLaterButton, views::LabelButton)
 END_METADATA
diff --git a/chrome/browser/ui/views/read_later/read_later_button.h b/chrome/browser/ui/views/read_later/read_later_button.h
index 4ce8cb0..278bc393 100644
--- a/chrome/browser/ui/views/read_later/read_later_button.h
+++ b/chrome/browser/ui/views/read_later/read_later_button.h
@@ -5,8 +5,14 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_READ_LATER_READ_LATER_BUTTON_H_
 #define CHROME_BROWSER_UI_VIEWS_READ_LATER_READ_LATER_BUTTON_H_
 
+#include "base/scoped_observation.h"
 #include "chrome/browser/ui/views/bubble/webui_bubble_manager.h"
 #include "chrome/browser/ui/webui/read_later/read_later_ui.h"
+#include "components/reading_list/core/reading_list_model.h"
+#include "components/reading_list/core/reading_list_model_observer.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/animation/animation_delegate.h"
+#include "ui/gfx/animation/multi_animation.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/metadata/metadata_header_macros.h"
 #include "ui/views/widget/widget_observer.h"
@@ -19,7 +25,8 @@
 // read later menu.
 // TODO(corising): Handle the the async presentation of the UI bubble.
 class ReadLaterButton : public views::LabelButton,
-                        public views::WidgetObserver {
+                        public views::WidgetObserver,
+                        public ReadingListModelObserver {
  public:
   METADATA_HEADER(ReadLaterButton);
   explicit ReadLaterButton(Browser* browser);
@@ -30,6 +37,41 @@
   void CloseBubble();
 
  private:
+  class HighlightColorAnimation : gfx::AnimationDelegate {
+   public:
+    explicit HighlightColorAnimation(ReadLaterButton* parent);
+    HighlightColorAnimation(const HighlightColorAnimation&) = delete;
+    HighlightColorAnimation& operator=(const HighlightColorAnimation&) = delete;
+    ~HighlightColorAnimation() override;
+
+    void Show();
+    void Hide();
+    void SetColor(SkColor color) { highlight_color_ = color; }
+
+    // Returns current text / background / icon color based on
+    // |highlight_color_| and on the current animation state (which
+    // influences the alpha channel).
+    SkColor GetTextColor() const;
+    base::Optional<SkColor> GetBackgroundColor() const;
+    SkColor GetIconColor() const;
+
+    void AnimationEnded(const gfx::Animation* animation) override;
+    void AnimationProgressed(const gfx::Animation* animation) override;
+
+   private:
+    SkColor FadeWithAnimation(SkColor target_color,
+                              SkColor original_color) const;
+    void ClearHighlightColor();
+
+    ReadLaterButton* const parent_;
+
+    SkColor highlight_color_ = SK_ColorTRANSPARENT;
+
+    // Animation for showing the highlight color (in icon, text, and
+    // background).
+    gfx::MultiAnimation highlight_color_animation_;
+  };
+
   // LabelButton:
   std::unique_ptr<views::InkDrop> CreateInkDrop() override;
   std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
@@ -40,19 +82,34 @@
   // views::WidgetObserver:
   void OnWidgetDestroying(views::Widget* widget) override;
 
+  // ReadingListModelObserver:
+  void ReadingListModelLoaded(const ReadingListModel* model) override {}
+  void ReadingListModelBeingDeleted(const ReadingListModel* model) override;
+  void ReadingListDidAddEntry(const ReadingListModel* model,
+                              const GURL& url,
+                              reading_list::EntrySource source) override;
+
   void ButtonPressed();
 
+  void UpdateColors();
+
   Browser* const browser_;
 
   // TODO(pbos): Figure out a better way to handle this.
   WebUIBubbleDialogView* read_later_side_panel_bubble_ = nullptr;
 
+  ReadingListModel* reading_list_model_ = nullptr;
+  base::ScopedObservation<ReadingListModel, ReadingListModelObserver>
+      reading_list_model_scoped_observation_{this};
+
   std::unique_ptr<WebUIBubbleManager<ReadLaterUI>> webui_bubble_manager_;
 
   views::WidgetOpenTimer widget_open_timer_;
 
   base::ScopedObservation<views::Widget, views::WidgetObserver>
       bubble_widget_observation_{this};
+
+  std::unique_ptr<HighlightColorAnimation> highlight_color_animation_;
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_READ_LATER_READ_LATER_BUTTON_H_
diff --git a/chrome/browser/ui/views/select_file_dialog_extension.cc b/chrome/browser/ui/views/select_file_dialog_extension.cc
index 9c285825..447d0c5 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension.cc
+++ b/chrome/browser/ui/views/select_file_dialog_extension.cc
@@ -9,6 +9,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/feature_list.h"
@@ -40,7 +41,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/extensions/extension_dialog.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/native_app_window.h"
 #include "extensions/browser/extension_system.h"
diff --git a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
index 310f83a..a395eff7 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
+++ b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/keyboard/keyboard_switches.h"
 #include "ash/public/cpp/test/shell_test_api.h"
 #include "base/callback_helpers.h"
@@ -32,7 +33,6 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/ui/base/window_properties.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/render_frame_host.h"
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index d98fc055..62d518d 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -1787,11 +1787,13 @@
                                : source_context_->GetTabStripModel();
     ui::ListSelectionModel selection;
     int index = model->GetIndexOfWebContents(drag_data_[1].contents);
-    DCHECK_NE(-1, index);
-    selection.AddIndexToSelection(index);
-    selection.set_active(index);
-    selection.set_anchor(index);
-    model->SetSelectionFromModel(selection);
+    // The tabs in the group may have been closed during the drag.
+    if (index != TabStripModel::kNoTab) {
+      selection.AddIndexToSelection(index);
+      selection.set_active(index);
+      selection.set_anchor(index);
+      model->SetSelectionFromModel(selection);
+    }
   }
 }
 
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index 77910b9..2d7dfd8d 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -100,7 +100,7 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #else
 #include "chrome/browser/signin/signin_global_error_factory.h"
 #include "chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h"
diff --git a/chrome/browser/ui/web_applications/web_app_menu_model.cc b/chrome/browser/ui/web_applications/web_app_menu_model.cc
index 8b6c7db..59b5fec 100644
--- a/chrome/browser/ui/web_applications/web_app_menu_model.cc
+++ b/chrome/browser/ui/web_applications/web_app_menu_model.cc
@@ -49,6 +49,7 @@
       return base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu) &&
              base::FeatureList::IsEnabled(
                  features::kDesktopPWAsElidedExtensionsMenu) &&
+             browser()->window()->GetExtensionsContainer() &&
              browser()->window()->GetExtensionsContainer()->HasAnyExtensions();
     default:
       return AppMenuModel::IsCommandIdEnabled(command_id);
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 d9f0c3b..00b3f17b 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -55,6 +55,7 @@
 #include "chrome/browser/ui/webui/media/media_feeds_ui.h"
 #include "chrome/browser/ui/webui/media/media_history_ui.h"
 #include "chrome/browser/ui/webui/media/webrtc_logs_ui.h"
+#include "chrome/browser/ui/webui/memories/memories_ui.h"
 #include "chrome/browser/ui/webui/memory_internals_ui.h"
 #include "chrome/browser/ui/webui/net_export_ui.h"
 #include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
@@ -82,6 +83,7 @@
 #include "components/favicon_base/select_favicon_frames.h"
 #include "components/grit/components_scaled_resources.h"
 #include "components/history/core/browser/history_types.h"
+#include "components/memories/common/memories_features.h"
 #include "components/nacl/common/buildflags.h"
 #include "components/prefs/pref_service.h"
 #include "components/reading_list/features/reading_list_switches.h"
@@ -151,6 +153,7 @@
 #endif  // defined(OS_ANDROID)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "base/system/sys_info.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/device_sync/device_sync_client_factory.h"
@@ -219,7 +222,6 @@
 #include "chromeos/components/print_management/url_constants.h"
 #include "chromeos/components/scanning/scanning_ui.h"
 #include "chromeos/components/scanning/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/services/multidevice_setup/multidevice_setup_service.h"
 #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
@@ -625,6 +627,10 @@
     return &NewWebUI<NewTabUI>;
   if (url.host_piece() == chrome::kChromeUINewTabPageHost)
     return &NewWebUI<NewTabPageUI>;
+  if (base::FeatureList::IsEnabled(memories::kChromeMemories)) {
+    if (url.host_piece() == chrome::kChromeUIMemoriesHost)
+      return &NewWebUI<MemoriesUI>;
+  }
   if (base::FeatureList::IsEnabled(reading_list::switches::kReadLater)) {
     if (url.host_piece() == chrome::kChromeUIReadLaterHost)
       return &NewWebUI<ReadLaterUI>;
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
index 63997eb..ac8093c 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/shelf_config.h"
 #include "base/bind.h"
 #include "base/macros.h"
@@ -24,7 +25,6 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "chromeos/assistant/buildflags.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
 #include "chromeos/services/assistant/public/cpp/features.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_dialog_launcher.cc b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_dialog_launcher.cc
index 191e0385d..c212f68c 100644
--- a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_dialog_launcher.cc
+++ b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_dialog_launcher.cc
@@ -4,9 +4,9 @@
 
 #include "chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_dialog_launcher.h"
 
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/ui/ash/system_tray_client.h"
 #include "chrome/browser/ui/webui/chromeos/cellular_setup/mobile_setup_dialog.h"
-#include "chromeos/constants/chromeos_features.h"
 
 namespace chromeos {
 
diff --git a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc
index f7448c6f..2bf7180 100644
--- a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc
@@ -4,13 +4,13 @@
 
 #include "chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/containers/span.h"
 #include "base/feature_list.h"
 #include "base/no_destructor.h"
 #include "base/values.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/login/localized_values_builder.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_ui_data_source.h"
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.cc b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.cc
index 306b66c..05862999 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/optional.h"
 #include "base/strings/utf_string_conversions.h"
@@ -19,7 +20,6 @@
 #include "chrome/browser/chromeos/crostini/crostini_installer_ui_delegate.h"
 #include "chrome/browser/chromeos/crostini/crostini_types.mojom.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/text/bytes_formatting.h"
 
 namespace chromeos {
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc
index e8900fa..4f923da 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/strings/string16.h"
@@ -21,7 +22,6 @@
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
diff --git a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.cc b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.cc
index 912699d..2268bdbc 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/strings/string16.h"
 #include "base/system/sys_info.h"
@@ -18,7 +19,6 @@
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
diff --git a/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.cc b/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.cc
index 3333a85..04d7fd9d 100644
--- a/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.cc
+++ b/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.cc
@@ -24,6 +24,8 @@
       ui::IMEBridge::Get()->GetInputContextHandler()->GetInputMethod();
   input_client = input_method->GetTextInputClient();
   input_client->GetEditableSelectionRange(&selection_range);
+
+  set_can_resize(false);
 }
 
 void EmojiPickerDialog::Show() {
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
index f3bf0ce..ab591486 100644
--- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
@@ -6,6 +6,7 @@
 
 #include <type_traits>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/ash_interfaces.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/event_rewriter_controller.h"
@@ -42,7 +43,6 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/constants/chromeos_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/login/base_screen_handler_utils.h"
 #include "components/login/localized_values_builder.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 77e2ac0c..52645c1 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/login_screen.h"
 #include "base/bind.h"
 #include "base/callback.h"
@@ -68,7 +69,6 @@
 #include "chrome/installer/util/google_update_settings.h"
 #include "chromeos/components/security_token_pin/constants.h"
 #include "chromeos/components/security_token_pin/error_generator.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/constants/devicetype.h"
 #include "chromeos/dbus/util/version_loader.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 6ad767a..b78228a 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -10,6 +10,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/network_config_service.h"
 #include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
 #include "base/bind.h"
@@ -103,7 +104,6 @@
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/component_extension_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/services/multidevice_setup/multidevice_setup_service.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"  // nogncheck
diff --git a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc
index 10dc2255..78941b8 100644
--- a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc
@@ -4,12 +4,12 @@
 
 #include "chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/login/screens/sync_consent_screen.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/login/localized_values_builder.h"
 #include "components/user_manager/user_manager.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
index 845374be0..5b53004 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/values.h"
 #include "build/branding_buildflags.h"
 #include "chrome/browser/ash/accessibility/accessibility_manager.h"
@@ -13,7 +14,6 @@
 #include "chrome/browser/chromeos/login/screens/update_screen.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/login/localized_values_builder.h"
 #include "ui/chromeos/devicetype_utils.h"
 
diff --git a/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_ui.cc b/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_ui.cc
index 2d7cd2b..4198f65 100644
--- a/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_ui.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_ui.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/containers/span.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_logs_handler.h"
@@ -12,7 +13,6 @@
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/multidevice_internals_resources.h"
 #include "chrome/grit/multidevice_internals_resources_map.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "ui/base/webui/web_ui_util.h"
diff --git a/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_localized_strings_provider.cc b/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_localized_strings_provider.cc
index 53bab12b..b233999 100644
--- a/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_localized_strings_provider.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_localized_strings_provider.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/no_destructor.h"
 #include "base/strings/utf_string_conversions.h"
@@ -16,7 +17,6 @@
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/multidevice_setup_resources.h"
 #include "chrome/grit/multidevice_setup_resources_map.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/grit/chromeos_resources.h"
 #include "chromeos/services/multidevice_setup/public/cpp/url_provider.h"
 #include "components/login/localized_values_builder.h"
diff --git a/chrome/browser/ui/webui/memories/BUILD.gn b/chrome/browser/ui/webui/memories/BUILD.gn
new file mode 100644
index 0000000..8f3eec0
--- /dev/null
+++ b/chrome/browser/ui/webui/memories/BUILD.gn
@@ -0,0 +1,9 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojo_bindings") {
+  sources = [ "memories.mojom" ]
+}
diff --git a/chrome/browser/ui/webui/memories/OWNERS b/chrome/browser/ui/webui/memories/OWNERS
new file mode 100644
index 0000000..d9c1030
--- /dev/null
+++ b/chrome/browser/ui/webui/memories/OWNERS
@@ -0,0 +1,4 @@
+file://components/memories/OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/ui/webui/memories/memories.mojom b/chrome/browser/ui/webui/memories/memories.mojom
new file mode 100644
index 0000000..8b4cd6d1
--- /dev/null
+++ b/chrome/browser/ui/webui/memories/memories.mojom
@@ -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.
+
+module memories.mojom;
+
+// Browser-side handler for requests from WebUI page.
+interface PageHandler {
+  // The MemoriesBrowserProxy singleton calls this when it's first initialized.
+  SetPage(pending_remote<Page> page);
+};
+
+// WebUI-side handler for requests from the browser.
+interface Page {
+};
diff --git a/chrome/browser/ui/webui/memories/memories_handler.cc b/chrome/browser/ui/webui/memories/memories_handler.cc
new file mode 100644
index 0000000..495886ca
--- /dev/null
+++ b/chrome/browser/ui/webui/memories/memories_handler.cc
@@ -0,0 +1,26 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/memories/memories_handler.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/web_contents.h"
+
+MemoriesHandler::MemoriesHandler(
+    mojo::PendingReceiver<memories::mojom::PageHandler> pending_page_handler,
+    Profile* profile,
+    content::WebContents* web_contents)
+    : profile_(profile),
+      web_contents_(web_contents),
+      page_handler_(this, std::move(pending_page_handler)) {
+  DCHECK(profile_);
+  DCHECK(web_contents_);
+}
+
+MemoriesHandler::~MemoriesHandler() = default;
+
+void MemoriesHandler::SetPage(
+    mojo::PendingRemote<memories::mojom::Page> pending_page) {
+  page_.Bind(std::move(pending_page));
+}
diff --git a/chrome/browser/ui/webui/memories/memories_handler.h b/chrome/browser/ui/webui/memories/memories_handler.h
new file mode 100644
index 0000000..b398eea1
--- /dev/null
+++ b/chrome/browser/ui/webui/memories/memories_handler.h
@@ -0,0 +1,44 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_MEMORIES_MEMORIES_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_MEMORIES_MEMORIES_HANDLER_H_
+
+#include "chrome/browser/ui/webui/memories/memories.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+class Profile;
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+// Handles bidirectional communication between memories page and the browser.
+class MemoriesHandler : public memories::mojom::PageHandler {
+ public:
+  MemoriesHandler(
+      mojo::PendingReceiver<memories::mojom::PageHandler> pending_page_handler,
+      Profile* profile,
+      content::WebContents* web_contents);
+  ~MemoriesHandler() override;
+
+  MemoriesHandler(const MemoriesHandler&) = delete;
+  MemoriesHandler& operator=(const MemoriesHandler&) = delete;
+
+  // memories::mojom::PageHandler:
+  void SetPage(
+      mojo::PendingRemote<memories::mojom::Page> pending_page) override;
+
+ private:
+  Profile* profile_;
+  content::WebContents* web_contents_;
+
+  mojo::Remote<memories::mojom::Page> page_;
+  mojo::Receiver<memories::mojom::PageHandler> page_handler_;
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_MEMORIES_MEMORIES_HANDLER_H_
diff --git a/chrome/browser/ui/webui/memories/memories_ui.cc b/chrome/browser/ui/webui/memories/memories_ui.cc
new file mode 100644
index 0000000..1461f82e
--- /dev/null
+++ b/chrome/browser/ui/webui/memories/memories_ui.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 "chrome/browser/ui/webui/memories/memories_ui.h"
+
+#include "base/logging.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/memories/memories_handler.h"
+#include "chrome/browser/ui/webui/webui_util.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/memories_resources.h"
+#include "chrome/grit/memories_resources_map.h"
+#include "components/strings/grit/components_strings.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui_controller.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "ui/base/webui/web_ui_util.h"
+
+namespace {
+
+content::WebUIDataSource* CreateAndSetupWebUIDataSource() {
+  content::WebUIDataSource* source =
+      content::WebUIDataSource::Create(chrome::kChromeUIMemoriesHost);
+
+  static constexpr webui::LocalizedString kStrings[] = {
+      {"title", IDS_MEMORIES_PAGE_TITLE},
+  };
+  AddLocalizedStringsBulk(source, kStrings);
+
+  webui::SetupWebUIDataSource(
+      source, base::make_span(kMemoriesResources, kMemoriesResourcesSize),
+      IDR_MEMORIES_MEMORIES_HTML);
+
+  return source;
+}
+
+}  // namespace
+
+MemoriesUI::MemoriesUI(content::WebUI* web_ui)
+    : ui::MojoWebUIController(web_ui, /*enable_chrome_send=*/true),
+      profile_(Profile::FromWebUI(web_ui)),
+      web_contents_(web_ui->GetWebContents()) {
+  DCHECK(profile_);
+  DCHECK(web_contents_);
+
+  auto* source = CreateAndSetupWebUIDataSource();
+  content::WebUIDataSource::Add(profile_, source);
+}
+
+WEB_UI_CONTROLLER_TYPE_IMPL(MemoriesUI)
+
+MemoriesUI::~MemoriesUI() = default;
+
+void MemoriesUI::BindInterface(
+    mojo::PendingReceiver<memories::mojom::PageHandler> pending_page_handler) {
+  memories_handler_ = std::make_unique<MemoriesHandler>(
+      std::move(pending_page_handler), profile_, web_contents_);
+}
diff --git a/chrome/browser/ui/webui/memories/memories_ui.h b/chrome/browser/ui/webui/memories/memories_ui.h
new file mode 100644
index 0000000..df7f2a0a
--- /dev/null
+++ b/chrome/browser/ui/webui/memories/memories_ui.h
@@ -0,0 +1,42 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_MEMORIES_MEMORIES_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_MEMORIES_MEMORIES_UI_H_
+
+#include "chrome/browser/ui/webui/memories/memories.mojom-forward.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "ui/webui/mojo_web_ui_controller.h"
+
+class Profile;
+class MemoriesHandler;
+
+namespace content {
+class WebContents;
+class WebUI;
+}  // namespace content
+
+// The UI for chrome://memories/
+class MemoriesUI : public ui::MojoWebUIController {
+ public:
+  explicit MemoriesUI(content::WebUI* contents);
+  ~MemoriesUI() override;
+
+  MemoriesUI(const MemoriesUI&) = delete;
+  MemoriesUI& operator=(const MemoriesUI&) = delete;
+
+  // Instantiates the implementor of the memories::mojom::PageHandler mojo
+  // interface passing to it the pending receiver that will be internally bound.
+  void BindInterface(
+      mojo::PendingReceiver<memories::mojom::PageHandler> pending_page_handler);
+
+ private:
+  Profile* profile_;
+  content::WebContents* web_contents_;
+  std::unique_ptr<MemoriesHandler> memories_handler_;
+
+  WEB_UI_CONTROLLER_TYPE_DECL();
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_MEMORIES_MEMORIES_UI_H_
diff --git a/chrome/browser/ui/webui/print_preview/DEPS b/chrome/browser/ui/webui/print_preview/DEPS
new file mode 100644
index 0000000..fe0f7d53
--- /dev/null
+++ b/chrome/browser/ui/webui/print_preview/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+  "local_printer_handler_default_unittest.cc": [
+    "+chrome/services/printing/print_backend_service_test_impl.h",
+  ],
+}
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc
index bc7ef0c..3497b336 100644
--- a/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc
@@ -16,10 +16,12 @@
 #include "base/task/thread_pool.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/printing/print_backend_service.h"
 #include "chrome/browser/ui/webui/print_preview/print_preview_utils.h"
 #include "chrome/common/printing/printer_capabilities.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
+#include "printing/printing_features.h"
 
 #if defined(OS_MAC)
 #include "chrome/common/printing/printer_capabilities_mac.h"
@@ -54,6 +56,32 @@
 #endif
 }
 
+void OnDidFetchCapabilities(
+    const std::string& device_name,
+    bool has_secure_protocol,
+    LocalPrinterHandlerDefault::GetCapabilityCallback callback,
+    const base::Optional<PrinterBasicInfo>& printer_info,
+    const base::Optional<PrinterSemanticCapsAndDefaults::Papers>&
+        user_defined_papers,
+    const base::Optional<PrinterSemanticCapsAndDefaults>& caps_and_defaults) {
+  const bool has_values = printer_info.has_value() &&
+                          user_defined_papers.has_value() &&
+                          caps_and_defaults.has_value();
+  if (!has_values) {
+    LOG(WARNING) << "Failure fetching printer capabilities for  "
+                 << device_name;
+    std::move(callback).Run(base::Value());
+    return;
+  }
+
+  VLOG(1) << "Received printer info & capabilities for " << device_name;
+  PrinterSemanticCapsAndDefaults caps = caps_and_defaults.value();
+  base::Value settings = AssemblePrinterSettings(
+      device_name, std::move(printer_info.value()),
+      std::move(user_defined_papers.value()), has_secure_protocol, &caps);
+  std::move(callback).Run(std::move(settings));
+}
+
 }  // namespace
 
 // static
@@ -159,11 +187,22 @@
     GetCapabilityCallback cb) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  base::PostTaskAndReplyWithResult(
-      task_runner_.get(), FROM_HERE,
-      base::BindOnce(&FetchCapabilitiesAsync, device_name,
-                     g_browser_process->GetApplicationLocale()),
-      std::move(cb));
+  if (base::FeatureList::IsEnabled(features::kEnableOopPrintDrivers)) {
+    VLOG(1) << "Getting printer capabilities via service for " << device_name;
+    GetPrintBackendService(g_browser_process->GetApplicationLocale(),
+                           device_name)
+        ->FetchCapabilities(
+            device_name,
+            base::BindOnce(&OnDidFetchCapabilities, device_name,
+                           /*has_secure_protocol=*/false, std::move(cb)));
+  } else {
+    VLOG(1) << "Getting printer capabilities in-process for " << device_name;
+    base::PostTaskAndReplyWithResult(
+        task_runner_.get(), FROM_HERE,
+        base::BindOnce(&FetchCapabilitiesAsync, device_name,
+                       g_browser_process->GetApplicationLocale()),
+        std::move(cb));
+  }
 }
 
 void LocalPrinterHandlerDefault::StartPrint(
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_default_unittest.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_default_unittest.cc
index 408f207..33617f8 100644
--- a/chrome/browser/ui/webui/print_preview/local_printer_handler_default_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_default_unittest.cc
@@ -4,17 +4,21 @@
 
 #include "chrome/browser/ui/webui/print_preview/local_printer_handler_default.h"
 
+#include <functional>
 #include <memory>
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/values.h"
+#include "chrome/browser/printing/print_backend_service.h"
 #include "chrome/common/printing/printer_capabilities.h"
+#include "chrome/services/printing/print_backend_service_test_impl.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_task_environment.h"
 #include "printing/backend/print_backend.h"
 #include "printing/backend/test_print_backend.h"
+#include "printing/printing_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace printing {
@@ -30,7 +34,7 @@
 
 }  // namespace
 
-class LocalPrinterHandlerDefaultTest : public testing::Test {
+class LocalPrinterHandlerDefaultTest : public testing::TestWithParam<bool> {
  public:
   LocalPrinterHandlerDefaultTest() = default;
   LocalPrinterHandlerDefaultTest(const LocalPrinterHandlerDefaultTest&) =
@@ -51,6 +55,14 @@
     PrintBackend::SetPrintBackendForTesting(test_backend_.get());
     local_printer_handler_ =
         std::make_unique<LocalPrinterHandlerDefault>(initiator);
+
+    // Choose between running with local test runner or via a service.
+    const bool use_backend_service = GetParam();
+    if (use_backend_service) {
+      feature_list_.InitAndEnableFeature(features::kEnableOopPrintDrivers);
+      print_backend_service_ = PrintBackendServiceTestImpl::LaunchForTesting(
+          test_remote_, test_backend_);
+    }
   }
 
  protected:
@@ -59,16 +71,28 @@
   std::unique_ptr<content::WebContents> initiator_web_contents_;
   scoped_refptr<TestPrintBackend> test_backend_;
   std::unique_ptr<LocalPrinterHandlerDefault> local_printer_handler_;
+
+  // Support for testing via a service instead of with a local task runner.
+  base::test::ScopedFeatureList feature_list_;
+  mojo::Remote<mojom::PrintBackendService> test_remote_;
+  std::unique_ptr<PrintBackendServiceTestImpl> print_backend_service_;
 };
 
+INSTANTIATE_TEST_SUITE_P(All, LocalPrinterHandlerDefaultTest, testing::Bool());
+
 // Tests that fetching capabilities for an existing installed printer is
 // successful.
-TEST_F(LocalPrinterHandlerDefaultTest, StartGetCapabilityValidPrinter) {
+TEST_P(LocalPrinterHandlerDefaultTest, StartGetCapabilityValidPrinter) {
   // Add printer to `test_backend`.
   const std::string kDestinationId = "printer1";
-  print_backend()->AddValidPrinter(
-      kDestinationId, std::make_unique<PrinterSemanticCapsAndDefaults>(),
-      std::make_unique<PrinterBasicInfo>());
+  auto caps = std::make_unique<PrinterSemanticCapsAndDefaults>();
+  caps->papers.push_back({"foo", "vendor", {600, 600}});
+  auto basic_info = std::make_unique<PrinterBasicInfo>(
+      kDestinationId, /*display_name=*/"foo", /*printer_description=*/"",
+      /*printer_status=*/0, /*is_default=*/true, PrinterBasicInfoOptions{});
+
+  print_backend()->AddValidPrinter(kDestinationId, std::move(caps),
+                                   std::move(basic_info));
 
   bool did_fetch_caps = false;
   base::Value fetched_caps;
@@ -87,7 +111,7 @@
 
 // Tests that fetching capabilities bails early when the provided printer
 // can't be found.
-TEST_F(LocalPrinterHandlerDefaultTest, StartGetCapabilityInvalidPrinter) {
+TEST_P(LocalPrinterHandlerDefaultTest, StartGetCapabilityInvalidPrinter) {
   bool did_fetch_caps = false;
   base::Value fetched_caps;
   local_printer_handler_->StartGetCapability(
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 0f39a5e..c556036d 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -80,12 +80,12 @@
 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/ash/account_manager/account_manager_util.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
 #include "chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/account_manager_core/account_manager_facade.h"
 #endif
 
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.cc
index fe9ce77f..bdaa69da 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.cc
@@ -11,6 +11,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/lazy_instance.h"
@@ -28,7 +29,6 @@
 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
 #include "chrome/browser/ui/webui/print_preview/printer_handler.h"
 #include "chrome/common/printing/printer_capabilities.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/printing/printer_configuration.h"
 #include "components/cloud_devices/common/cloud_devices_urls.h"
 #include "components/signin/public/identity_manager/scope_set.h"
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos_unittest.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos_unittest.cc
index bb8bef69..a776952 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
@@ -16,7 +17,6 @@
 #include "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_web_ui.h"
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index 5b87f180e..a04c218 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/base_paths.h"
 #include "base/bind.h"
 #include "base/containers/flat_map.h"
@@ -54,7 +55,6 @@
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/print_preview_resources.h"
 #include "chrome/grit/print_preview_resources_map.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "components/printing/browser/print_composite_client.h"
 #include "components/printing/browser/print_manager_utils.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/about_section.cc b/chrome/browser/ui/webui/settings/chromeos/about_section.cc
index 556adc7..18a2e42 100644
--- a/chrome/browser/ui/webui/settings/chromeos/about_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/about_section.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/about_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/i18n/message_formatter.h"
@@ -24,7 +25,6 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/constants/dbus_switches.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_chromium_strings.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/ambient_mode_handler.cc b/chrome/browser/ui/webui/settings/chromeos/ambient_mode_handler.cc
index bc2c7d83..f4e541f 100644
--- a/chrome/browser/ui/webui/settings/chromeos/ambient_mode_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/ambient_mode_handler.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ambient/ambient_backend_controller.h"
 #include "ash/public/cpp/ambient/ambient_metrics.h"
 #include "ash/public/cpp/ambient/ambient_prefs.h"
@@ -25,7 +26,6 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/apps_section.cc b/chrome/browser/ui/webui/settings/chromeos/apps_section.cc
index c9e20c5..72dc443 100644
--- a/chrome/browser/ui/webui/settings/chromeos/apps_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/apps_section.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/apps_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/no_destructor.h"
 #include "base/strings/utf_string_conversions.h"
@@ -21,7 +22,6 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/os_settings_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/arc/arc_prefs.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/web_ui_data_source.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/crostini_section.cc b/chrome/browser/ui/webui/settings/chromeos/crostini_section.cc
index c94e19d..d7765cb 100644
--- a/chrome/browser/ui/webui/settings/chromeos/crostini_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/crostini_section.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/crostini_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/no_destructor.h"
 #include "base/strings/utf_string_conversions.h"
@@ -20,7 +21,6 @@
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/arc/arc_prefs.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/web_ui.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
index 61b72d8..9e831c7 100644
--- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -7,6 +7,7 @@
 #include <set>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/containers/flat_map.h"
@@ -44,7 +45,6 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/components/scanning/scanning_uma.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/debug_daemon/debug_daemon_client.h"
 #include "chromeos/printing/ppd_line_reader.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_section.cc b/chrome/browser/ui/webui/settings/chromeos/device_section.cc
index cc52c88..6dba4fb3 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/device_section.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/device_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/ash_interfaces.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/night_light_controller.h"
@@ -28,7 +29,6 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/internet_section.cc b/chrome/browser/ui/webui/settings/chromeos/internet_section.cc
index 8f4816a..8ff22186b 100644
--- a/chrome/browser/ui/webui/settings/chromeos/internet_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/internet_section.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/internet_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/network_config_service.h"
 #include "base/bind.h"
@@ -20,7 +21,6 @@
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_ui_data_source.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc b/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc
index e49ec10..98f03c7 100644
--- a/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
@@ -20,7 +21,6 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/kerberos_section.cc b/chrome/browser/ui/webui/settings/chromeos/kerberos_section.cc
index 784a9bd..ea6d108 100644
--- a/chrome/browser/ui/webui/settings/chromeos/kerberos_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/kerberos_section.cc
@@ -4,12 +4,12 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/kerberos_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/search/search_tag_registry.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/languages_section.cc b/chrome/browser/ui/webui/settings/chromeos/languages_section.cc
index 08e674a..2ed54ed2 100644
--- a/chrome/browser/ui/webui/settings/chromeos/languages_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/languages_section.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/languages_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/no_destructor.h"
 #include "base/strings/utf_string_conversions.h"
@@ -14,7 +15,6 @@
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/spellcheck/browser/pref_names.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/main_section.cc b/chrome/browser/ui/webui/settings/chromeos/main_section.cc
index 0897c77d..6133cb8 100644
--- a/chrome/browser/ui/webui/settings/chromeos/main_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/main_section.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/main_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
 #include "base/feature_list.h"
 #include "base/i18n/message_formatter.h"
@@ -28,7 +29,6 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/os_settings_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/web_ui_data_source.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/multidevice_handler.cc b/chrome/browser/ui/webui/settings/chromeos/multidevice_handler.cc
index 07c0a5c5..c37e9948 100644
--- a/chrome/browser/ui/webui/settings/chromeos/multidevice_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/multidevice_handler.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/multidevice_handler.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/logging.h"
@@ -18,7 +19,6 @@
 #include "chromeos/components/multidevice/logging/logging.h"
 #include "chromeos/components/phonehub/util/histogram_util.h"
 #include "chromeos/components/proximity_auth/proximity_auth_pref_names.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/multidevice_handler_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/multidevice_handler_unittest.cc
index fa14f1a..2ead054 100644
--- a/chrome/browser/ui/webui/settings/chromeos/multidevice_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/multidevice_handler_unittest.cc
@@ -6,13 +6,13 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/macros.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/android_sms/android_sms_urls.h"
 #include "chrome/browser/chromeos/android_sms/fake_android_sms_app_manager.h"
 #include "chromeos/components/multidevice/remote_device_test_util.h"
 #include "chromeos/components/phonehub/fake_notification_access_manager.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/multidevice_setup/public/cpp/fake_android_sms_pairing_state_tracker.h"
 #include "chromeos/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc b/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc
index f7e6e75..6ee0a428 100644
--- a/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/multidevice_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/no_destructor.h"
 #include "base/strings/utf_string_conversions.h"
@@ -21,7 +22,6 @@
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/components/phonehub/phone_hub_manager.h"
 #include "chromeos/components/phonehub/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
 #include "chromeos/services/multidevice_setup/public/cpp/url_provider.h"
 #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_section.cc b/chrome/browser/ui/webui/settings/chromeos/os_settings_section.cc
index 6ae3dd1c..a600d86 100644
--- a/chrome/browser/ui/webui/settings/chromeos/os_settings_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_section.cc
@@ -4,11 +4,11 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/os_settings_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/check.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace chromeos {
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_section_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/os_settings_section_unittest.cc
index 7408442..747c7c3 100644
--- a/chrome/browser/ui/webui/settings/chromeos/os_settings_section_unittest.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_section_unittest.cc
@@ -4,9 +4,9 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/os_settings_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
index f645868..a696624 100644
--- a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/esim_manager.h"
 #include "ash/public/cpp/network_config_service.h"
 #include "base/metrics/histogram_functions.h"
@@ -25,7 +26,6 @@
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/os_settings_resources.h"
 #include "chrome/grit/os_settings_resources_map.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/cellular_setup/cellular_setup_impl.h"
 #include "chromeos/services/cellular_setup/public/mojom/esim_manager.mojom.h"
 #include "components/pref_registry/pref_registry_syncable.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/people_section.cc b/chrome/browser/ui/webui/settings/chromeos/people_section.cc
index cdbe21d..917b287 100644
--- a/chrome/browser/ui/webui/settings/chromeos/people_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/people_section.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/settings/chromeos/people_section.h"
 
 #include "ash/components/account_manager/account_manager_factory.h"
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "base/bind.h"
 #include "base/i18n/number_formatting.h"
@@ -39,7 +40,6 @@
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/google/core/common/google_util.h"
 #include "components/omnibox/common/omnibox_features.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc b/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc
index 0412c9c4..2f5dbf7 100644
--- a/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/personalization_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ambient/ambient_client.h"
 #include "ash/public/cpp/ambient/ambient_prefs.h"
 #include "base/bind.h"
@@ -20,7 +21,6 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/printing_section.cc b/chrome/browser/ui/webui/settings/chromeos/printing_section.cc
index 8a52c5b..e6c04ed 100644
--- a/chrome/browser/ui/webui/settings/chromeos/printing_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/printing_section.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/printing_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/no_destructor.h"
 #include "chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h"
@@ -12,7 +13,6 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/printing/printer_configuration.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/privacy_section.cc b/chrome/browser/ui/webui/settings/chromeos/privacy_section.cc
index 1199615..5791f2f 100644
--- a/chrome/browser/ui/webui/settings/chromeos/privacy_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/privacy_section.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/privacy_section.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/no_destructor.h"
 #include "build/branding_buildflags.h"
@@ -15,7 +16,6 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 862ff2c5..5616deb 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -95,6 +95,7 @@
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "chrome/browser/ash/account_manager/account_manager_util.h"
 #include "chrome/browser/chromeos/assistant/assistant_util.h"
@@ -105,7 +106,6 @@
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
 #include "chrome/common/webui_url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/user_manager/user_manager.h"
 #include "ui/chromeos/devicetype_utils.h"
 #else  // !BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index bd0fbd5..d33e236 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -96,6 +96,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/components/account_manager/account_manager.h"
 #include "ash/components/account_manager/account_manager_factory.h"
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/ash/account_manager/account_manager_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
@@ -111,7 +112,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/grit/browser_resources.h"
 #include "chromeos/components/phonehub/phone_hub_manager.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/login/auth/password_visibility_utils.h"
 #include "components/arc/arc_util.h"
 #include "components/user_manager/user.h"
diff --git a/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.cc
index 2850b6e6..e8e527e 100644
--- a/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/window_backdrop.h"
 #include "ash/public/cpp/window_properties.h"
 #include "base/callback_helpers.h"
@@ -22,7 +23,6 @@
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
 #include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h"
 #include "chrome/common/webui_url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/session_manager/core/session_manager.h"
diff --git a/chrome/browser/ui/webui/signin/inline_login_ui.cc b/chrome/browser/ui/webui/signin/inline_login_ui.cc
index d50206e3..06b1ae29 100644
--- a/chrome/browser/ui/webui/signin/inline_login_ui.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_ui.cc
@@ -35,6 +35,7 @@
 #include "ui/resources/grit/webui_resources.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/supervised_user/supervised_user_features.h"
 #include "chrome/browser/ui/chrome_pages.h"
@@ -42,7 +43,6 @@
 #include "chrome/browser/ui/webui/chromeos/edu_coexistence_login_handler_chromeos.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
 #include "chrome/browser/ui/webui/signin/inline_login_handler_chromeos.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/vr/animation.cc b/chrome/browser/vr/animation.cc
index 3e44f2d8..ffebccd 100644
--- a/chrome/browser/vr/animation.cc
+++ b/chrome/browser/vr/animation.cc
@@ -92,8 +92,8 @@
   return base::IsApproximatelyEqual(lhs, rhs, kTolerance);
 }
 
-bool SufficientlyEqual(const cc::TransformOperations& lhs,
-                       const cc::TransformOperations& rhs) {
+bool SufficientlyEqual(const gfx::TransformOperations& lhs,
+                       const gfx::TransformOperations& rhs) {
   return lhs.ApproximatelyEqual(rhs, kTolerance);
 }
 
@@ -129,7 +129,7 @@
   }
 
 DEFINE_ANIMATION_TRAITS(float, Float, Float);
-DEFINE_ANIMATION_TRAITS(cc::TransformOperations,
+DEFINE_ANIMATION_TRAITS(gfx::TransformOperations,
                         Transform,
                         TransformOperations);
 DEFINE_ANIMATION_TRAITS(gfx::SizeF, Size, Size);
@@ -232,10 +232,10 @@
 void Animation::TransitionTransformOperationsTo(
     base::TimeTicks monotonic_time,
     int target_property,
-    const cc::TransformOperations& current,
-    const cc::TransformOperations& target) {
-  TransitionValueTo<cc::TransformOperations>(monotonic_time, target_property,
-                                             current, target);
+    const gfx::TransformOperations& current,
+    const gfx::TransformOperations& target) {
+  TransitionValueTo<gfx::TransformOperations>(monotonic_time, target_property,
+                                              current, target);
 }
 
 void Animation::TransitionSizeTo(base::TimeTicks monotonic_time,
@@ -266,11 +266,11 @@
   return GetTargetValue<float>(target_property, default_value);
 }
 
-cc::TransformOperations Animation::GetTargetTransformOperationsValue(
+gfx::TransformOperations Animation::GetTargetTransformOperationsValue(
     int target_property,
-    const cc::TransformOperations& default_value) const {
-  return GetTargetValue<cc::TransformOperations>(target_property,
-                                                 default_value);
+    const gfx::TransformOperations& default_value) const {
+  return GetTargetValue<gfx::TransformOperations>(target_property,
+                                                  default_value);
 }
 
 gfx::SizeF Animation::GetTargetSizeValue(
diff --git a/chrome/browser/vr/animation.h b/chrome/browser/vr/animation.h
index 80ee37b..646cd68 100644
--- a/chrome/browser/vr/animation.h
+++ b/chrome/browser/vr/animation.h
@@ -16,11 +16,11 @@
 
 namespace cc {
 class AnimationTarget;
-class TransformOperations;
 }  // namespace cc
 
 namespace gfx {
 class SizeF;
+class TransformOperations;
 }  // namespace gfx
 
 namespace vr {
@@ -74,8 +74,8 @@
                          float target);
   void TransitionTransformOperationsTo(base::TimeTicks monotonic_time,
                                        int target_property,
-                                       const cc::TransformOperations& current,
-                                       const cc::TransformOperations& target);
+                                       const gfx::TransformOperations& current,
+                                       const gfx::TransformOperations& target);
   void TransitionSizeTo(base::TimeTicks monotonic_time,
                         int target_property,
                         const gfx::SizeF& current,
@@ -88,9 +88,9 @@
   bool IsAnimatingProperty(int property) const;
 
   float GetTargetFloatValue(int target_property, float default_value) const;
-  cc::TransformOperations GetTargetTransformOperationsValue(
+  gfx::TransformOperations GetTargetTransformOperationsValue(
       int target_property,
-      const cc::TransformOperations& default_value) const;
+      const gfx::TransformOperations& default_value) const;
   gfx::SizeF GetTargetSizeValue(int target_property,
                                 const gfx::SizeF& default_value) const;
   SkColor GetTargetColorValue(int target_property, SkColor default_value) const;
diff --git a/chrome/browser/vr/animation_unittest.cc b/chrome/browser/vr/animation_unittest.cc
index b792532..268e440 100644
--- a/chrome/browser/vr/animation_unittest.cc
+++ b/chrome/browser/vr/animation_unittest.cc
@@ -28,8 +28,8 @@
   }
 
   const gfx::SizeF& size() const { return size_; }
-  const cc::TransformOperations& operations() const { return operations_; }
-  const cc::TransformOperations& layout_offset() const {
+  const gfx::TransformOperations& operations() const { return operations_; }
+  const gfx::TransformOperations& layout_offset() const {
     return layout_offset_;
   }
   float opacity() const { return opacity_; }
@@ -42,7 +42,7 @@
   }
 
   void NotifyClientTransformOperationsAnimated(
-      const cc::TransformOperations& operations,
+      const gfx::TransformOperations& operations,
       int target_property_id,
       cc::KeyframeModel* keyframe_model) override {
     if (target_property_id == LAYOUT_OFFSET) {
@@ -72,8 +72,8 @@
       cc::KeyframeModel* keyframe_model) override {}
 
  private:
-  cc::TransformOperations layout_offset_;
-  cc::TransformOperations operations_;
+  gfx::TransformOperations layout_offset_;
+  gfx::TransformOperations operations_;
   gfx::SizeF size_ = {10.0f, 10.0f};
   float opacity_ = 1.0f;
   SkColor background_color_ = SK_ColorRED;
@@ -89,9 +89,9 @@
   EXPECT_EQ(1ul, animation.keyframe_models().size());
   EXPECT_EQ(BOUNDS, animation.keyframe_models()[0]->target_property_type());
 
-  cc::TransformOperations from_operations;
+  gfx::TransformOperations from_operations;
   from_operations.AppendTranslate(10, 100, 1000);
-  cc::TransformOperations to_operations;
+  gfx::TransformOperations to_operations;
   to_operations.AppendTranslate(20, 200, 2000);
   animation.AddKeyframeModel(CreateTransformAnimation(
       2, 2, from_operations, to_operations, MicrosecondsToDelta(10000)));
@@ -164,9 +164,9 @@
                                                    gfx::SizeF(20, 200),
                                                    MicrosecondsToDelta(10000)));
 
-  cc::TransformOperations from_operations;
+  gfx::TransformOperations from_operations;
   from_operations.AppendTranslate(10, 100, 1000);
-  cc::TransformOperations to_operations;
+  gfx::TransformOperations to_operations;
   to_operations.AppendTranslate(20, 200, 2000);
   animation.AddKeyframeModel(CreateTransformAnimation(
       3, 2, from_operations, to_operations, MicrosecondsToDelta(10000)));
@@ -307,9 +307,9 @@
   base::TimeTicks start_time = MicrosecondsToTicks(1000000);
   animation.Tick(start_time);
 
-  cc::TransformOperations from = target.layout_offset();
+  gfx::TransformOperations from = target.layout_offset();
 
-  cc::TransformOperations to;
+  gfx::TransformOperations to;
   to.AppendTranslate(8, 0, 0);
 
   animation.TransitionTransformOperationsTo(start_time, LAYOUT_OFFSET, from,
@@ -320,7 +320,7 @@
 
   // Scheduling a redundant, approximately equal transition should be ignored.
   int keyframe_model_id = animation.keyframe_models().front()->id();
-  cc::TransformOperations nearby = to;
+  gfx::TransformOperations nearby = to;
   nearby.at(0).translate.x += kNoise;
   animation.TransitionTransformOperationsTo(start_time, LAYOUT_OFFSET, from,
                                             nearby);
@@ -347,9 +347,9 @@
   base::TimeTicks start_time = MicrosecondsToTicks(1000000);
   animation.Tick(start_time);
 
-  cc::TransformOperations from = target.operations();
+  gfx::TransformOperations from = target.operations();
 
-  cc::TransformOperations to;
+  gfx::TransformOperations to;
   to.AppendTranslate(8, 0, 0);
   to.AppendRotate(1, 0, 0, 0);
   to.AppendScale(1, 1, 1);
@@ -361,7 +361,7 @@
 
   // Scheduling a redundant, approximately equal transition should be ignored.
   int keyframe_model_id = animation.keyframe_models().front()->id();
-  cc::TransformOperations nearby = to;
+  gfx::TransformOperations nearby = to;
   nearby.at(0).translate.x += kNoise;
   animation.TransitionTransformOperationsTo(start_time, TRANSFORM, from,
                                             nearby);
@@ -388,9 +388,9 @@
   base::TimeTicks start_time = MicrosecondsToTicks(1000000);
   animation.Tick(start_time);
 
-  cc::TransformOperations from = target.operations();
+  gfx::TransformOperations from = target.operations();
 
-  cc::TransformOperations to;
+  gfx::TransformOperations to;
   to.AppendTranslate(8, 0, 0);
   to.AppendRotate(1, 0, 0, 0);
   to.AppendScale(1, 1, 1);
@@ -401,7 +401,7 @@
   animation.Tick(start_time);
 
   animation.Tick(start_time + MicrosecondsToDelta(1000));
-  cc::TransformOperations value_before_reversing = target.operations();
+  gfx::TransformOperations value_before_reversing = target.operations();
   EXPECT_LT(from.at(0).translate.x, target.operations().at(0).translate.x);
   EXPECT_GT(to.at(0).translate.x, target.operations().at(0).translate.x);
 
@@ -657,9 +657,9 @@
   gfx::SizeF to_bounds = gfx::SizeF(20, 200);
   SkColor from_color = SK_ColorRED;
   SkColor to_color = SK_ColorGREEN;
-  cc::TransformOperations from_transform;
+  gfx::TransformOperations from_transform;
   from_transform.AppendTranslate(10, 100, 1000);
-  cc::TransformOperations to_transform;
+  gfx::TransformOperations to_transform;
   to_transform.AppendTranslate(20, 200, 2000);
 
   // Verify the default value is returned if there's no running animations.
diff --git a/chrome/browser/vr/elements/disc_button_unittest.cc b/chrome/browser/vr/elements/disc_button_unittest.cc
index 7b8df43..d3e8de2d 100644
--- a/chrome/browser/vr/elements/disc_button_unittest.cc
+++ b/chrome/browser/vr/elements/disc_button_unittest.cc
@@ -4,8 +4,6 @@
 
 #include "chrome/browser/vr/elements/disc_button.h"
 
-#include "cc/animation/transform_operation.h"
-#include "cc/animation/transform_operations.h"
 #include "cc/test/geometry_test_utils.h"
 #include "chrome/browser/vr/elements/rect.h"
 #include "chrome/browser/vr/elements/ui_element.h"
@@ -14,6 +12,8 @@
 #include "components/vector_icons/vector_icons.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/transform_operation.h"
+#include "ui/gfx/transform_operations.h"
 
 namespace vr {
 
@@ -23,19 +23,19 @@
   button.SetSize(1.0f, 1.0f);
   button.set_hover_offset(0.5f);
 
-  cc::TransformOperation foreground_op =
+  gfx::TransformOperation foreground_op =
       button.foreground()->GetTargetTransform().at(UiElement::kTranslateIndex);
-  cc::TransformOperation background_op =
+  gfx::TransformOperation background_op =
       button.background()->GetTargetTransform().at(UiElement::kTranslateIndex);
-  cc::TransformOperation hit_plane_op =
+  gfx::TransformOperation hit_plane_op =
       button.hit_plane()->GetTargetTransform().at(UiElement::kScaleIndex);
 
   button.OnHoverEnter(gfx::PointF(0.5f, 0.5f), base::TimeTicks());
-  cc::TransformOperation foreground_op_hover =
+  gfx::TransformOperation foreground_op_hover =
       button.foreground()->GetTargetTransform().at(UiElement::kTranslateIndex);
-  cc::TransformOperation background_op_hover =
+  gfx::TransformOperation background_op_hover =
       button.background()->GetTargetTransform().at(UiElement::kTranslateIndex);
-  cc::TransformOperation hit_plane_op_hover =
+  gfx::TransformOperation hit_plane_op_hover =
       button.hit_plane()->GetTargetTransform().at(UiElement::kScaleIndex);
 
   EXPECT_TRUE(background_op_hover.translate.z - background_op.translate.z >
diff --git a/chrome/browser/vr/elements/spinner.cc b/chrome/browser/vr/elements/spinner.cc
index f6fc9f0..4aa19a94 100644
--- a/chrome/browser/vr/elements/spinner.cc
+++ b/chrome/browser/vr/elements/spinner.cc
@@ -6,13 +6,13 @@
 
 #include "cc/animation/keyframed_animation_curve.h"
 #include "cc/animation/timing_function.h"
-#include "cc/animation/transform_operations.h"
 #include "cc/paint/skia_paint_canvas.h"
 #include "chrome/browser/vr/animation.h"
 #include "chrome/browser/vr/elements/ui_texture.h"
 #include "chrome/browser/vr/target_property.h"
 #include "third_party/skia/include/core/SkPaint.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/transform_operations.h"
 
 namespace vr {
 
diff --git a/chrome/browser/vr/elements/throbber.cc b/chrome/browser/vr/elements/throbber.cc
index def9258..7d36ca62 100644
--- a/chrome/browser/vr/elements/throbber.cc
+++ b/chrome/browser/vr/elements/throbber.cc
@@ -6,8 +6,8 @@
 
 #include "cc/animation/keyframed_animation_curve.h"
 #include "cc/animation/timing_function.h"
-#include "cc/animation/transform_operations.h"
 #include "chrome/browser/vr/target_property.h"
+#include "ui/gfx/transform_operations.h"
 
 namespace vr {
 
diff --git a/chrome/browser/vr/elements/throbber.h b/chrome/browser/vr/elements/throbber.h
index 34f97f1..c05288c3 100644
--- a/chrome/browser/vr/elements/throbber.h
+++ b/chrome/browser/vr/elements/throbber.h
@@ -5,9 +5,9 @@
 #ifndef CHROME_BROWSER_VR_ELEMENTS_THROBBER_H_
 #define CHROME_BROWSER_VR_ELEMENTS_THROBBER_H_
 
-#include "cc/animation/transform_operation.h"
 #include "chrome/browser/vr/elements/rect.h"
 #include "chrome/browser/vr/vr_ui_export.h"
+#include "ui/gfx/transform_operation.h"
 
 namespace vr {
 
@@ -25,7 +25,7 @@
   void SetCircleGrowAnimationEnabled(bool enabled);
 
  private:
-  cc::TransformOperation scale_before_animation_;
+  gfx::TransformOperation scale_before_animation_;
   float opacity_before_animation_ = 0.f;
 
   DISALLOW_COPY_AND_ASSIGN(Throbber);
diff --git a/chrome/browser/vr/elements/throbber_unittest.cc b/chrome/browser/vr/elements/throbber_unittest.cc
index 115744a1..8a93ce7 100644
--- a/chrome/browser/vr/elements/throbber_unittest.cc
+++ b/chrome/browser/vr/elements/throbber_unittest.cc
@@ -6,14 +6,14 @@
 
 #include <memory>
 
-#include "cc/animation/transform_operation.h"
-#include "cc/animation/transform_operations.h"
 #include "chrome/browser/vr/elements/ui_element.h"
 #include "chrome/browser/vr/target_property.h"
 #include "chrome/browser/vr/test/animation_utils.h"
 #include "chrome/browser/vr/test/constants.h"
 #include "chrome/browser/vr/ui_scene.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/transform_operation.h"
+#include "ui/gfx/transform_operations.h"
 
 namespace vr {
 
diff --git a/chrome/browser/vr/elements/ui_element.cc b/chrome/browser/vr/elements/ui_element.cc
index b1df55bc..579e60a09 100644
--- a/chrome/browser/vr/elements/ui_element.cc
+++ b/chrome/browser/vr/elements/ui_element.cc
@@ -55,7 +55,7 @@
 constexpr char kYellow[] = "\x1b[33m";
 constexpr char kReset[] = "\x1b[0m";
 
-void DumpTransformOperations(const cc::TransformOperations& ops,
+void DumpTransformOperations(const gfx::TransformOperations& ops,
                              std::ostringstream* os) {
   if (!ops.at(0).IsIdentity()) {
     const auto& translate = ops.at(0).translate;
@@ -380,8 +380,8 @@
     return;
   }
 
-  cc::TransformOperations operations = layout_offset_;
-  cc::TransformOperation& op = operations.at(0);
+  gfx::TransformOperations operations = layout_offset_;
+  gfx::TransformOperation& op = operations.at(0);
   op.translate = {x, y, 0};
   op.Bake();
   animation_.TransitionTransformOperationsTo(last_frame_time_, LAYOUT_OFFSET,
@@ -396,8 +396,8 @@
     return;
   }
 
-  cc::TransformOperations operations = transform_operations_;
-  cc::TransformOperation& op = operations.at(kTranslateIndex);
+  gfx::TransformOperations operations = transform_operations_;
+  gfx::TransformOperation& op = operations.at(kTranslateIndex);
   op.translate = {x, y, z};
   op.Bake();
   animation_.TransitionTransformOperationsTo(last_frame_time_, TRANSFORM,
@@ -415,8 +415,8 @@
     return;
   }
 
-  cc::TransformOperations operations = transform_operations_;
-  cc::TransformOperation& op = operations.at(kRotateIndex);
+  gfx::TransformOperations operations = transform_operations_;
+  gfx::TransformOperation& op = operations.at(kRotateIndex);
   op.rotate.axis = {x, y, z};
   op.rotate.angle = degrees;
   op.Bake();
@@ -432,8 +432,8 @@
     return;
   }
 
-  cc::TransformOperations operations = transform_operations_;
-  cc::TransformOperation& op = operations.at(kScaleIndex);
+  gfx::TransformOperations operations = transform_operations_;
+  gfx::TransformOperation& op = operations.at(kScaleIndex);
   op.scale = {x, y, z};
   op.Bake();
   animation_.TransitionTransformOperationsTo(last_frame_time_, TRANSFORM,
@@ -455,7 +455,7 @@
   return animation_.GetTargetSizeValue(TargetProperty::BOUNDS, size_);
 }
 
-cc::TransformOperations UiElement::GetTargetTransform() const {
+gfx::TransformOperations UiElement::GetTargetTransform() const {
   return animation_.GetTargetTransformOperationsValue(TargetProperty::TRANSFORM,
                                                       transform_operations_);
 }
@@ -772,7 +772,7 @@
 }
 
 void UiElement::NotifyClientTransformOperationsAnimated(
-    const cc::TransformOperations& operations,
+    const gfx::TransformOperations& operations,
     int target_property_id,
     cc::KeyframeModel* keyframe_model) {
   if (target_property_id == TRANSFORM) {
diff --git a/chrome/browser/vr/elements/ui_element.h b/chrome/browser/vr/elements/ui_element.h
index 52cbc0e..61ebe85 100644
--- a/chrome/browser/vr/elements/ui_element.h
+++ b/chrome/browser/vr/elements/ui_element.h
@@ -13,7 +13,6 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "cc/animation/animation_target.h"
-#include "cc/animation/transform_operations.h"
 #include "chrome/browser/vr/animation.h"
 #include "chrome/browser/vr/audio_delegate.h"
 #include "chrome/browser/vr/databinding/binding_base.h"
@@ -33,6 +32,7 @@
 #include "ui/gfx/geometry/size_f.h"
 #include "ui/gfx/geometry/vector3d_f.h"
 #include "ui/gfx/transform.h"
+#include "ui/gfx/transform_operations.h"
 
 namespace base {
 class TimeTicks;
@@ -251,7 +251,7 @@
   // Returns the target value of the animation if the corresponding property is
   // being animated, or the current value otherwise.
   gfx::SizeF GetTargetSize() const;
-  cc::TransformOperations GetTargetTransform() const;
+  gfx::TransformOperations GetTargetTransform() const;
   float GetTargetOpacity() const;
 
   float opacity() const { return opacity_; }
@@ -395,7 +395,7 @@
                                  int target_property_id,
                                  cc::KeyframeModel* keyframe_model) override;
   void NotifyClientTransformOperationsAnimated(
-      const cc::TransformOperations& operations,
+      const gfx::TransformOperations& operations,
       int target_property_id,
       cc::KeyframeModel* keyframe_model) override;
   void NotifyClientSizeAnimated(const gfx::SizeF& size,
@@ -648,13 +648,13 @@
   // stored as a list of operations rather than a baked transform to make
   // transitions easier to implement (you may, for example, want to animate just
   // the translation, but leave the rotation and scale in tact).
-  cc::TransformOperations transform_operations_;
+  gfx::TransformOperations transform_operations_;
 
   // This is a cached version of the local transform.
   gfx::Transform local_transform_;
 
   // This is set by the parent and is combined into LocalTransform()
-  cc::TransformOperations layout_offset_;
+  gfx::TransformOperations layout_offset_;
 
   // This is the combined, local to world transform. It includes
   // |inheritable_transform_|, |transform_|, and anchoring adjustments.
diff --git a/chrome/browser/vr/elements/ui_element_unittest.cc b/chrome/browser/vr/elements/ui_element_unittest.cc
index 628bd01..8589c40 100644
--- a/chrome/browser/vr/elements/ui_element_unittest.cc
+++ b/chrome/browser/vr/elements/ui_element_unittest.cc
@@ -273,9 +273,9 @@
   UiElement* rect_ptr = rect.get();
   scene.AddUiElement(kRoot, std::move(rect));
 
-  cc::TransformOperations from_operations;
+  gfx::TransformOperations from_operations;
   from_operations.AppendTranslate(10, 100, 1000);
-  cc::TransformOperations to_operations;
+  gfx::TransformOperations to_operations;
   to_operations.AppendTranslate(20, 200, 2000);
   rect_ptr->AddKeyframeModel(CreateTransformAnimation(
       2, 2, from_operations, to_operations, MicrosecondsToDelta(10000)));
diff --git a/chrome/browser/vr/test/animation_utils.cc b/chrome/browser/vr/test/animation_utils.cc
index d3f4b78..f84adba 100644
--- a/chrome/browser/vr/test/animation_utils.cc
+++ b/chrome/browser/vr/test/animation_utils.cc
@@ -12,8 +12,8 @@
 std::unique_ptr<cc::KeyframeModel> CreateTransformAnimation(
     int id,
     int group,
-    const cc::TransformOperations& from,
-    const cc::TransformOperations& to,
+    const gfx::TransformOperations& from,
+    const gfx::TransformOperations& to,
     base::TimeDelta duration) {
   std::unique_ptr<cc::KeyframedTransformAnimationCurve> curve(
       cc::KeyframedTransformAnimationCurve::Create());
diff --git a/chrome/browser/vr/test/animation_utils.h b/chrome/browser/vr/test/animation_utils.h
index 3e07e48..4a959507 100644
--- a/chrome/browser/vr/test/animation_utils.h
+++ b/chrome/browser/vr/test/animation_utils.h
@@ -18,8 +18,8 @@
 std::unique_ptr<cc::KeyframeModel> CreateTransformAnimation(
     int id,
     int group,
-    const cc::TransformOperations& from,
-    const cc::TransformOperations& to,
+    const gfx::TransformOperations& from,
+    const gfx::TransformOperations& to,
     base::TimeDelta duration);
 
 std::unique_ptr<cc::KeyframeModel> CreateBoundsAnimation(
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index 48bd2b5..e2774536 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -981,21 +981,21 @@
   std::unique_ptr<cc::KeyframedTransformAnimationCurve> curve(
       cc::KeyframedTransformAnimationCurve::Create());
 
-  cc::TransformOperations value_1;
+  gfx::TransformOperations value_1;
   value_1.AppendTranslate(0, kWebVrPermissionOffsetStart, 0);
   curve->AddKeyframe(cc::TransformKeyframe::Create(
       base::TimeDelta(), value_1,
       cc::CubicBezierTimingFunction::CreatePreset(
           cc::CubicBezierTimingFunction::EaseType::EASE)));
 
-  cc::TransformOperations value_2;
+  gfx::TransformOperations value_2;
   value_2.AppendTranslate(0, kWebVrPermissionOffsetOvershoot, 0);
   curve->AddKeyframe(cc::TransformKeyframe::Create(
       base::TimeDelta::FromMilliseconds(kWebVrPermissionOffsetMs), value_2,
       cc::CubicBezierTimingFunction::CreatePreset(
           cc::CubicBezierTimingFunction::EaseType::EASE)));
 
-  cc::TransformOperations value_3;
+  gfx::TransformOperations value_3;
   value_3.AppendTranslate(0, kWebVrPermissionOffsetFinal, 0);
   curve->AddKeyframe(cc::TransformKeyframe::Create(
       base::TimeDelta::FromMilliseconds(kWebVrPermissionAnimationDurationMs),
@@ -1067,21 +1067,21 @@
   std::unique_ptr<cc::KeyframedTransformAnimationCurve> curve(
       cc::KeyframedTransformAnimationCurve::Create());
 
-  cc::TransformOperations value_1;
+  gfx::TransformOperations value_1;
   value_1.AppendTranslate(0, kWebVrPermissionOffsetStart, 0);
   curve->AddKeyframe(cc::TransformKeyframe::Create(
       base::TimeDelta(), value_1,
       cc::CubicBezierTimingFunction::CreatePreset(
           cc::CubicBezierTimingFunction::EaseType::EASE)));
 
-  cc::TransformOperations value_2;
+  gfx::TransformOperations value_2;
   value_2.AppendTranslate(0, kWebVrPermissionOffsetOvershoot, 0);
   curve->AddKeyframe(cc::TransformKeyframe::Create(
       base::TimeDelta::FromMilliseconds(kWebVrPermissionOffsetMs), value_2,
       cc::CubicBezierTimingFunction::CreatePreset(
           cc::CubicBezierTimingFunction::EaseType::EASE)));
 
-  cc::TransformOperations value_3;
+  gfx::TransformOperations value_3;
   value_3.AppendTranslate(0, kWebVrPermissionOffsetFinal, 0);
   curve->AddKeyframe(cc::TransformKeyframe::Create(
       base::TimeDelta::FromMilliseconds(kWebVrPermissionAnimationDurationMs),
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index 1571e816..68afc82 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -135,6 +135,13 @@
     ]
   }
 
+  if (is_win || is_mac || (is_linux && !is_chromeos_lacros)) {
+    sources += [
+      "url_handler_prefs.cc",
+      "url_handler_prefs.h",
+    ]
+  }
+
   public_deps =
       [ "//components/services/app_service/public/cpp:app_share_target" ]
 
@@ -166,6 +173,13 @@
   if (is_win) {
     deps += [ "//chrome/browser/web_applications/chrome_pwa_launcher:util" ]
   }
+
+  if (is_win || is_mac || (is_linux && !is_chromeos_lacros)) {
+    deps += [
+      "//base/util/values:values_util",
+      "//components/services/app_service/public/cpp:app_url_handling",
+    ]
+  }
 }
 
 source_set("unit_tests") {
@@ -213,6 +227,10 @@
     ]
   }
 
+  if (is_win || is_mac || (is_linux && !is_chromeos_lacros)) {
+    sources += [ "url_handler_prefs_unittest.cc" ]
+  }
+
   deps = [
     ":components",
     "//base/test:test_support",
@@ -241,6 +259,10 @@
   if (is_win) {
     deps += [ "//chrome/browser/web_applications/chrome_pwa_launcher:util" ]
   }
+
+  if (is_win || is_mac || (is_linux && !is_chromeos_lacros)) {
+    deps += [ "//components/services/app_service/public/cpp:app_url_handling" ]
+  }
 }
 
 source_set("browser_tests") {
diff --git a/chrome/browser/web_applications/components/url_handler_prefs.cc b/chrome/browser/web_applications/components/url_handler_prefs.cc
new file mode 100644
index 0000000..94441306
--- /dev/null
+++ b/chrome/browser/web_applications/components/url_handler_prefs.cc
@@ -0,0 +1,314 @@
+// 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/web_applications/components/url_handler_prefs.h"
+
+#include <algorithm>
+
+#include "base/files/file_path.h"
+#include "base/strings/strcat.h"
+#include "base/util/values/values_util.h"
+#include "base/values.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
+#include "url/gurl.h"
+
+namespace web_app {
+namespace {
+
+constexpr const char* kAppId = "app_id";
+constexpr const char* kExcludePaths = "exclude_paths";
+constexpr const char* kHasOriginWildcard = "has_origin_wildcard";
+constexpr const char* kPaths = "paths";
+constexpr const char* kProfilePath = "profile_path";
+
+// Returns true if |url| has the same origin as origin_str. If
+// |look_for_subdomains| is true, url must have an origin that extends
+// |origin_str| by at least one sub-domain.
+bool UrlMatchesOrigin(const GURL& url,
+                      const std::string& origin_str,
+                      const bool look_for_subdomains) {
+  url::Origin origin = url::Origin::Create(GURL(origin_str));
+  url::Origin url_origin = url::Origin::Create(url);
+  if (origin.scheme() != url_origin.scheme() ||
+      origin.port() != url_origin.port())
+    return false;
+
+  const std::string& origin_host = origin.host();
+  const std::string& url_origin_host = url_origin.host();
+  if (look_for_subdomains) {
+    size_t pos = url_origin_host.find(origin_host);
+    if (pos == std::string::npos || pos == 0)
+      return false;
+
+    return url_origin_host.substr(pos) == origin_host;
+  } else {
+    return origin_host == url_origin_host;
+  }
+}
+
+// Given a list of handlers that matched an origin, apply the rules in each
+// handler against |url| and return only handlers that match |url|.
+// |origin_trimmed| indicates if the input URL's origin had to be shortened to
+// find a matching key. If true, filter out and matches that did not allow an
+// origin prefix wildcard in their manifest.
+base::Optional<std::vector<UrlHandlerPrefs::Match>> FilterMatches(
+    const base::Value& all_handlers,
+    const GURL& url,
+    bool origin_trimmed) {
+  if (!all_handlers.is_list())
+    return base::nullopt;
+
+  std::vector<UrlHandlerPrefs::Match> matches;
+  for (auto& handler : all_handlers.GetList()) {
+    if (!handler.is_dict())
+      continue;
+
+    const std::string* const app_id = handler.FindStringKey(kAppId);
+    if (!app_id || app_id->empty())
+      continue;
+
+    base::Optional<base::FilePath> profile_path =
+        util::ValueToFilePath(handler.FindKey(kProfilePath));
+    if (!profile_path)
+      continue;
+
+    if (origin_trimmed) {
+      base::Optional<bool> has_wildcard =
+          handler.FindBoolKey(kHasOriginWildcard);
+      if (!has_wildcard || !*has_wildcard)
+        continue;
+    }
+
+    // TODO(crbug/1072058): Filter results by matching against "paths" and
+    // "exclude_paths" lists. This would give developers finer control of what
+    // URLs trigger URL handling behavior.
+
+    matches.emplace_back(*app_id, *profile_path);
+  }
+  return matches;
+}
+
+// Returns the URL handlers stored in |pref_value| that match |url|'s origin.
+base::Optional<std::vector<UrlHandlerPrefs::Match>> FindMatches(
+    const base::Value& pref_value,
+    const GURL& url) {
+  if (!pref_value.is_dict())
+    return base::nullopt;
+
+  url::Origin origin = url::Origin::Create(url);
+  if (origin.opaque())
+    return base::nullopt;
+
+  if (origin.scheme() != "https")
+    return base::nullopt;
+
+  std::string origin_str = origin.Serialize();
+  bool origin_trimmed(false);
+  std::vector<UrlHandlerPrefs::Match> matches;
+  for (;;) {
+    const base::Value* const all_handlers = pref_value.FindListKey(origin_str);
+    if (all_handlers) {
+      DCHECK(UrlMatchesOrigin(url, origin_str, origin_trimmed));
+      base::Optional<std::vector<UrlHandlerPrefs::Match>> matches_local =
+          FilterMatches(*all_handlers, url, origin_trimmed);
+      if (matches_local) {
+        matches.insert(matches.end(),
+                       std::make_move_iterator(matches_local->begin()),
+                       std::make_move_iterator(matches_local->end()));
+      }
+    }
+    // If a key matching the input URL's origin is not found, shorten the origin
+    // by sub-domain and try again. This enables matching against manifest
+    // "url_handlers" origins that contain wildcard prefixes.
+    auto found = origin_str.find('.');
+    if (found != std::string::npos) {
+      // Trim origin to after next '.' character if there is one.
+      origin_str = base::StrCat({"https://", origin_str.substr(found + 1)});
+      origin_trimmed = true;
+    } else {
+      // There is no more '.'. Stop looking.
+      break;
+    }
+  }
+  return matches;
+}
+
+base::Value NewHandler(const AppId& app_id,
+                       const base::FilePath& profile_path,
+                       const apps::UrlHandlerInfo& info) {
+  base::Value value(base::Value::Type::DICTIONARY);
+  value.SetStringKey(kAppId, app_id);
+  value.SetKey(kProfilePath, util::FilePathToValue(profile_path));
+  value.SetBoolKey(kHasOriginWildcard, info.has_origin_wildcard);
+  // TODO(crbug/1072058): Set paths and exclude paths from origin association
+  // data when it is available.
+  base::Value paths(base::Value::Type::LIST);
+  base::Value exclude_paths(base::Value::Type::LIST);
+  value.SetKey(kPaths, std::move(paths));
+  value.SetKey(kExcludePaths, std::move(exclude_paths));
+  // TODO(crbug/1072058): Set "user_permission" field when implementing user
+  // settings in the chrome://settings page.
+  return value;
+}
+
+// If |match_app_id| is true, returns true if |handler| has dict. values equal
+// to |app_id| and |profile_path|. If |match_app_id| is false, only compare
+// |profile_path|.
+bool IsHandlerForApp(const AppId& app_id,
+                     const base::FilePath& profile_path,
+                     bool match_app_id,
+                     const base::Value& handler) {
+  const std::string* const app_id_local = handler.FindStringKey(kAppId);
+  base::Optional<base::FilePath> profile_path_local =
+      util::ValueToFilePath(handler.FindKey(kProfilePath));
+
+  if (!app_id_local || !profile_path_local)
+    return false;
+
+  if (*profile_path_local != profile_path)
+    return false;
+
+  return !match_app_id || *app_id_local == app_id;
+}
+
+// Removes entries that match |profile_path| and |app_id|.
+// |profile_path| is always compared while |app_id| is only compared when it is
+// not empty.
+void RemoveEntries(base::Value& pref_value,
+                   const AppId& app_id,
+                   const base::FilePath& profile_path) {
+  if (!pref_value.is_dict())
+    return;
+
+  for (auto origin_value : pref_value.DictItems()) {
+    base::Value::ListStorage handlers = origin_value.second.TakeList();
+    handlers.erase(
+        std::remove_if(handlers.begin(), handlers.end(),
+                       [&app_id, &profile_path](const base::Value& handler) {
+                         return IsHandlerForApp(
+                             app_id, profile_path,
+                             /*match_app_id=*/!app_id.empty(), handler);
+                       }),
+        handlers.end());
+    // Replace list if any entries remain.
+    if (!handlers.empty()) {
+      origin_value.second = base::Value(std::move(handlers));
+    } else {
+      pref_value.RemoveKey(origin_value.first);
+    }
+  }
+}
+}  // namespace
+
+UrlHandlerPrefs::Match::Match(const AppId& app_id,
+                              const base::FilePath& profile_path)
+    : app_id(app_id), profile_path(profile_path) {
+  // Match should either be default constructed with both fields empty, or using
+  // this constructor with both fields non-empty.
+  DCHECK(!app_id.empty());
+  DCHECK(!profile_path.empty());
+}
+
+UrlHandlerPrefs::UrlHandlerPrefs(PrefService* pref_service)
+    : pref_service_(pref_service) {
+  DCHECK(pref_service_);
+}
+
+void UrlHandlerPrefs::RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
+  DCHECK(registry);
+  registry->RegisterDictionaryPref(prefs::kWebAppsUrlHandlerInfo);
+}
+
+void UrlHandlerPrefs::AddWebApp(const AppId& app_id,
+                                const base::FilePath& profile_path,
+                                const apps::UrlHandlers& url_handlers) {
+  if (profile_path.empty() || url_handlers.empty())
+    return;
+
+  DictionaryPrefUpdate update(pref_service_, prefs::kWebAppsUrlHandlerInfo);
+  base::Value* const pref_value = update.Get();
+  if (!pref_value || !pref_value->is_dict())
+    return;
+
+  for (const apps::UrlHandlerInfo& handler_info : url_handlers) {
+    const url::Origin& origin = handler_info.origin;
+    if (origin.opaque())
+      continue;
+
+    base::Value new_handler(NewHandler(app_id, profile_path, handler_info));
+    base::Value* const handlers_mutable =
+        pref_value->FindListKey(origin.Serialize());
+    // One or more apps are already associated with this origin.
+    if (handlers_mutable) {
+      base::Value::ListStorage handlers = handlers_mutable->TakeList();
+      auto it =
+          std::find_if(handlers.begin(), handlers.end(),
+                       [&app_id, &profile_path](const base::Value& handler) {
+                         return IsHandlerForApp(app_id, profile_path,
+                                                /*match_app_id=*/true, handler);
+                       });
+      // If there is already an entry with the same app_id and profile, replace
+      // it. Otherwise, add new entry to the end.
+      if (it != handlers.end()) {
+        *it = std::move(new_handler);
+      } else {
+        handlers.push_back(std::move(new_handler));
+      }
+      *handlers_mutable = base::Value(std::move(handlers));
+    } else {
+      base::Value new_handlers(base::Value::Type::LIST);
+      new_handlers.Append(std::move(new_handler));
+      pref_value->SetKey(origin.Serialize(), std::move(new_handlers));
+    }
+  }
+}
+
+void UrlHandlerPrefs::RemoveWebApp(const AppId& app_id,
+                                   const base::FilePath& profile_path) {
+  if (app_id.empty() || profile_path.empty())
+    return;
+
+  DictionaryPrefUpdate update(pref_service_, prefs::kWebAppsUrlHandlerInfo);
+  base::Value* const pref_value = update.Get();
+  if (!pref_value || !pref_value->is_dict())
+    return;
+
+  RemoveEntries(*pref_value, app_id, profile_path);
+}
+
+void UrlHandlerPrefs::RemoveProfile(const base::FilePath& profile_path) {
+  if (profile_path.empty())
+    return;
+
+  DictionaryPrefUpdate update(pref_service_, prefs::kWebAppsUrlHandlerInfo);
+  base::Value* const pref_value = update.Get();
+  if (!pref_value || !pref_value->is_dict())
+    return;
+
+  RemoveEntries(*pref_value, /*app_id*/ "", profile_path);
+}
+
+void UrlHandlerPrefs::Clear() {
+  DictionaryPrefUpdate update(pref_service_, prefs::kWebAppsUrlHandlerInfo);
+  base::Value* const pref_value = update.Get();
+  pref_value->DictClear();
+}
+
+base::Optional<std::vector<UrlHandlerPrefs::Match>>
+UrlHandlerPrefs::FindMatchingUrlHandlers(const GURL& url) const {
+  if (!url.is_valid())
+    return base::nullopt;
+
+  const base::Value* const pref_value =
+      pref_service_->Get(prefs::kWebAppsUrlHandlerInfo);
+  if (!pref_value || !pref_value->is_dict())
+    return base::nullopt;
+
+  return FindMatches(*pref_value, url);
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/components/url_handler_prefs.h b/chrome/browser/web_applications/components/url_handler_prefs.h
new file mode 100644
index 0000000..acd573a
--- /dev/null
+++ b/chrome/browser/web_applications/components/url_handler_prefs.h
@@ -0,0 +1,111 @@
+// 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_WEB_APPLICATIONS_COMPONENTS_URL_HANDLER_PREFS_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_URL_HANDLER_PREFS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/optional.h"
+#include "chrome/browser/web_applications/components/web_app_id.h"
+#include "components/prefs/pref_service.h"
+#include "components/services/app_service/public/cpp/url_handler_info.h"
+#include "url/gurl.h"
+
+class PrefRegistrySimple;
+
+namespace base {
+class FilePath;
+}  // namespace base
+
+namespace web_app {
+
+// This class manages web app URL handler information in local state prefs.
+// These prefs aggregate information from web apps installed to all user
+// profiles.
+//
+// TODO(crbug/1072058): Deduplicate this with the the App Service's intent
+// handling system. For eg., this could be replaced with a cache of App Service
+// information implemented with local state prefs and managed by App Service
+// itself.
+//
+// The information stored here can be accessed when user profiles and
+// |WebAppRegistrar|s are not yet loaded, for example during browser startup.
+// At the topmost level, prefs are mapped by origin. If an app manifest
+// contained a "url_handlers" field with an "*.contoso.com" origin, an entry
+// will be added here under the "https://contoso.com" key. The mapped value
+// contains a list of handlers, each of which identifies the app_id and profile
+// of the app that could be launched. It also contains "paths" and
+// "exclude_paths" patterns for more specific matches. it also contains
+// information about user permissions and saved defaults.
+//
+// An example of the information stored using this model:
+// {
+//     "https://contoso.com":
+//     [
+//         {
+//             "app_id": "dslkfjweiourasdalfjkdslkfjowiesdfwee",
+//             "profile_path": "C:\\Users\\alias\\Profile\\Default",
+//             "origin": "https://contoso.com",
+//             "has_origin_wildcard": false,
+//             "paths": ["/*"],
+//             "exclude_paths": ["/abc"],
+//             "user_permission": true
+//         },
+//         {
+//             "app_id": "qruhrugqrgjdsdfhjghjrghjhdfgaaamenww",
+//             "profile_path": "C:\\Users\\alias\\Profile\\Default",
+//             "origin": "https://contoso.com",
+//             "has_origin_wildcard": true,
+//             "paths": [],
+//             "exclude_paths": [],
+//             "user_permission": false
+//         }
+//     ],
+//     "https://www.en.osotnoc.org": [...]
+// }
+class UrlHandlerPrefs {
+ public:
+  struct Match {
+    Match() = default;
+    Match(const AppId& app_id, const base::FilePath& profile_path);
+
+    AppId app_id;
+    base::FilePath profile_path;
+  };
+
+  explicit UrlHandlerPrefs(PrefService* pref_service);
+  UrlHandlerPrefs() = delete;
+  UrlHandlerPrefs(const UrlHandlerPrefs&) = delete;
+  UrlHandlerPrefs& operator=(const UrlHandlerPrefs&) = delete;
+
+  static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
+
+  void AddWebApp(const AppId& app_id,
+                 const base::FilePath& profile_path,
+                 const apps::UrlHandlers& url_handlers);
+
+  void RemoveWebApp(const AppId& app_id, const base::FilePath& profile_path);
+
+  void RemoveProfile(const base::FilePath& profile_path);
+
+  void Clear();
+
+  // Search for all (app, profile) combinations that have active URL handlers
+  // that matches |url|.
+  // |url| is a fully specified URL, eg. "https://contoso.com/abc/def".
+  // TODO(crbug/1072058): Filter out inactive handlers when user permission is
+  // implemented.
+  base::Optional<std::vector<Match>> FindMatchingUrlHandlers(
+      const GURL& url) const;
+
+ private:
+  PrefService* pref_service_;
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_URL_HANDLER_PREFS_H_
diff --git a/chrome/browser/web_applications/components/url_handler_prefs_unittest.cc b/chrome/browser/web_applications/components/url_handler_prefs_unittest.cc
new file mode 100644
index 0000000..1832ce39
--- /dev/null
+++ b/chrome/browser/web_applications/components/url_handler_prefs_unittest.cc
@@ -0,0 +1,298 @@
+// 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/web_applications/components/url_handler_prefs.h"
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/components/web_app_id.h"
+#include "chrome/browser/web_applications/web_app.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/services/app_service/public/cpp/url_handler_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace web_app {
+
+namespace {
+
+constexpr char kAppUrl1[] = "https://web-app1.com/";
+constexpr char kAppUrl2[] = "https://web-app2.com/";
+constexpr char kOriginUrl1[] = "https://origin-1.com/abc";
+constexpr char kOriginUrl2[] = "https://origin-2.com/abc";
+constexpr base::FilePath::CharType kProfile1[] = FILE_PATH_LITERAL("/profile1");
+constexpr base::FilePath::CharType kProfile2[] = FILE_PATH_LITERAL("/profile2");
+
+}  // namespace
+
+class UrlHandlerPrefsTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    UrlHandlerPrefs::RegisterLocalStatePrefs(test_pref_service_.registry());
+    prefs_ = std::make_unique<UrlHandlerPrefs>(&test_pref_service_);
+
+    app_url_1_ = GURL(kAppUrl1);
+    app_url_2_ = GURL(kAppUrl2);
+    origin_url_1_ = GURL(kOriginUrl1);
+    origin_url_2_ = GURL(kOriginUrl2);
+    origin_1_ = url::Origin::Create(origin_url_1_);
+    origin_2_ = url::Origin::Create(origin_url_2_);
+    profile_1_ = base::FilePath(kProfile1);
+    profile_2_ = base::FilePath(kProfile2);
+  }
+
+  UrlHandlerPrefs& Prefs() { return *prefs_; }
+
+  std::unique_ptr<WebApp> WebAppWithUrlHandlers(
+      const GURL& app_url,
+      const apps::UrlHandlers& url_handlers) {
+    auto web_app = std::make_unique<WebApp>(GenerateAppIdFromURL(app_url));
+    web_app->SetName("AppName");
+    web_app->SetDisplayMode(DisplayMode::kStandalone);
+    web_app->SetStartUrl(app_url);
+    web_app->SetUrlHandlers(url_handlers);
+    return web_app;
+  }
+
+  void CheckMatches(
+      const base::Optional<std::vector<UrlHandlerPrefs::Match>>& matches,
+      const std::vector<WebApp*>& apps,
+      const std::vector<base::FilePath>& profile_paths) {
+    if (!matches) {
+      EXPECT_TRUE(apps.empty());
+      EXPECT_TRUE(profile_paths.empty());
+    }
+
+    EXPECT_TRUE(matches->size() == apps.size());
+    EXPECT_TRUE(matches->size() == profile_paths.size());
+
+    for (size_t i = 0; i < matches->size(); i++) {
+      const UrlHandlerPrefs::Match& match = (*matches)[i];
+      EXPECT_EQ(match.app_id, apps[i]->app_id());
+      EXPECT_EQ(match.profile_path, profile_paths[i]);
+    }
+  }
+
+  GURL app_url_1_;
+  GURL app_url_2_;
+  GURL origin_url_1_;
+  GURL origin_url_2_;
+  url::Origin origin_1_;
+  url::Origin origin_2_;
+  base::FilePath profile_1_;
+  base::FilePath profile_2_;
+
+ private:
+  TestingPrefServiceSimple test_pref_service_;
+  std::unique_ptr<UrlHandlerPrefs> prefs_;
+};
+
+TEST_F(UrlHandlerPrefsTest, AddAndRemoveApp) {
+  const auto web_app =
+      WebAppWithUrlHandlers(app_url_1_, {apps::UrlHandlerInfo(origin_1_)});
+  Prefs().AddWebApp(web_app->app_id(), profile_1_, web_app->url_handlers());
+  auto matches = Prefs().FindMatchingUrlHandlers(origin_url_1_);
+  CheckMatches(matches, {web_app.get()}, {profile_1_});
+
+  Prefs().RemoveWebApp(web_app->app_id(), profile_1_);
+  matches = Prefs().FindMatchingUrlHandlers(origin_url_1_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(0u, matches->size());
+}
+
+TEST_F(UrlHandlerPrefsTest, RemoveAppNotFound) {
+  const auto web_app_1 =
+      WebAppWithUrlHandlers(app_url_1_, {apps::UrlHandlerInfo(origin_1_)});
+  Prefs().AddWebApp(web_app_1->app_id(), profile_1_, web_app_1->url_handlers());
+  auto matches = Prefs().FindMatchingUrlHandlers(origin_url_1_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(1u, matches->size());
+  CheckMatches(matches, {web_app_1.get()}, {profile_1_});
+
+  const GURL not_added("https://not-added.com/");
+  const auto web_app_2 =
+      WebAppWithUrlHandlers(not_added, {apps::UrlHandlerInfo(origin_1_)});
+  Prefs().RemoveWebApp(web_app_2->app_id(), profile_1_);
+  matches = Prefs().FindMatchingUrlHandlers(origin_url_1_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(1u, matches->size());
+  CheckMatches(matches, {web_app_1.get()}, {profile_1_});
+}
+
+TEST_F(UrlHandlerPrefsTest, OneAppWithManyOrigins) {
+  const auto web_app = WebAppWithUrlHandlers(
+      app_url_1_,
+      {apps::UrlHandlerInfo(origin_1_), apps::UrlHandlerInfo(origin_2_)});
+  Prefs().AddWebApp(web_app->app_id(), profile_1_, web_app->url_handlers());
+
+  auto matches = Prefs().FindMatchingUrlHandlers(origin_url_1_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(1u, matches->size());
+  CheckMatches(matches, {web_app.get()}, {profile_1_});
+
+  matches = Prefs().FindMatchingUrlHandlers(origin_url_2_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(1u, matches->size());
+  CheckMatches(matches, {web_app.get()}, {profile_1_});
+}
+
+TEST_F(UrlHandlerPrefsTest, AddAppAgainWithDifferentHandlers) {
+  const auto web_app_1 =
+      WebAppWithUrlHandlers(app_url_1_, {apps::UrlHandlerInfo(origin_1_)});
+  Prefs().AddWebApp(web_app_1->app_id(), profile_1_, web_app_1->url_handlers());
+  const auto web_app_2 = WebAppWithUrlHandlers(
+      app_url_1_,
+      {apps::UrlHandlerInfo(origin_1_), apps::UrlHandlerInfo(origin_2_)});
+  Prefs().AddWebApp(web_app_2->app_id(), profile_1_, web_app_2->url_handlers());
+
+  auto matches = Prefs().FindMatchingUrlHandlers(origin_url_1_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(1u, matches->size());
+  CheckMatches(matches, {web_app_2.get()}, {profile_1_});
+
+  matches = Prefs().FindMatchingUrlHandlers(origin_url_2_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(1u, matches->size());
+  CheckMatches(matches, {web_app_2.get()}, {profile_1_});
+}
+
+TEST_F(UrlHandlerPrefsTest, DifferentAppsWithSameHandler) {
+  const apps::UrlHandlerInfo handler(origin_1_);
+  const auto web_app_1 = WebAppWithUrlHandlers(app_url_1_, {handler});
+  Prefs().AddWebApp(web_app_1->app_id(), profile_1_, web_app_1->url_handlers());
+  const auto web_app_2 = WebAppWithUrlHandlers(app_url_2_, {handler});
+  Prefs().AddWebApp(web_app_2->app_id(), profile_1_, web_app_2->url_handlers());
+
+  const auto matches = Prefs().FindMatchingUrlHandlers(origin_url_1_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(2u, matches->size());
+  CheckMatches(matches, {web_app_1.get(), web_app_2.get()},
+               {profile_1_, profile_1_});
+}
+
+TEST_F(UrlHandlerPrefsTest, MultipleProfiles_Match) {
+  const auto web_app_1 =
+      WebAppWithUrlHandlers(app_url_1_, {apps::UrlHandlerInfo(origin_1_)});
+  Prefs().AddWebApp(web_app_1->app_id(), profile_1_, web_app_1->url_handlers());
+  Prefs().AddWebApp(web_app_1->app_id(), profile_2_, web_app_1->url_handlers());
+
+  auto matches = Prefs().FindMatchingUrlHandlers(origin_url_1_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(2u, matches->size());
+  CheckMatches(matches, {web_app_1.get(), web_app_1.get()},
+               {profile_1_, profile_2_});
+
+  Prefs().RemoveWebApp(web_app_1->app_id(), profile_1_);
+  matches = Prefs().FindMatchingUrlHandlers(origin_url_1_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(1u, matches->size());
+  CheckMatches(matches, {web_app_1.get()}, {profile_2_});
+}
+
+TEST_F(UrlHandlerPrefsTest, MultipleProfiles_RemoveProfile) {
+  const auto web_app_1 =
+      WebAppWithUrlHandlers(app_url_1_, {apps::UrlHandlerInfo(origin_1_)});
+  Prefs().AddWebApp(web_app_1->app_id(), profile_1_, web_app_1->url_handlers());
+  const auto web_app_2 =
+      WebAppWithUrlHandlers(app_url_2_, {apps::UrlHandlerInfo(origin_1_)});
+  Prefs().AddWebApp(web_app_1->app_id(), profile_2_, web_app_1->url_handlers());
+  Prefs().AddWebApp(web_app_2->app_id(), profile_2_, web_app_2->url_handlers());
+
+  Prefs().RemoveProfile(profile_2_);
+  auto matches = Prefs().FindMatchingUrlHandlers(origin_url_1_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(1u, matches->size());
+  CheckMatches(matches, {web_app_1.get()}, {profile_1_});
+
+  Prefs().RemoveProfile(profile_1_);
+  matches = Prefs().FindMatchingUrlHandlers(origin_url_1_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(0u, matches->size());
+}
+
+TEST_F(UrlHandlerPrefsTest, ClearEntries) {
+  const auto web_app_1 =
+      WebAppWithUrlHandlers(app_url_1_, {apps::UrlHandlerInfo(origin_1_)});
+  Prefs().AddWebApp(web_app_1->app_id(), profile_1_, web_app_1->url_handlers());
+  const auto web_app_2 =
+      WebAppWithUrlHandlers(app_url_2_, {apps::UrlHandlerInfo(origin_2_)});
+  Prefs().AddWebApp(web_app_2->app_id(), profile_2_, web_app_2->url_handlers());
+  Prefs().Clear();
+  auto matches = Prefs().FindMatchingUrlHandlers(origin_url_1_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(0u, matches->size());
+  matches = Prefs().FindMatchingUrlHandlers(origin_url_2_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(0u, matches->size());
+}
+
+TEST_F(UrlHandlerPrefsTest, SubdomainMatch) {
+  const auto web_app_1 = WebAppWithUrlHandlers(
+      app_url_1_,
+      {apps::UrlHandlerInfo(origin_1_, /*has_origin_wildcard*/ false)});
+  Prefs().AddWebApp(web_app_1->app_id(), profile_1_, web_app_1->url_handlers());
+
+  const auto web_app_2 = WebAppWithUrlHandlers(
+      app_url_2_,
+      {apps::UrlHandlerInfo(origin_1_, /*has_origin_wildcard*/ true)});
+  Prefs().AddWebApp(web_app_2->app_id(), profile_1_, web_app_2->url_handlers());
+
+  // Both handlers should match a URL with an exact origin.
+  auto matches = Prefs().FindMatchingUrlHandlers(origin_url_1_);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(2u, matches->size());
+  CheckMatches(matches, {web_app_1.get(), web_app_2.get()},
+               {profile_1_, profile_1_});
+
+  // Only the handler that has an origin with wildcard prefix should match a URL
+  // that has a longer origin.
+  GURL en_origin_url_1("https://en.origin-1.com/abc");
+  GURL www_en_origin_url_1("https://www.en.origin-1.com/abc");
+  matches = Prefs().FindMatchingUrlHandlers(en_origin_url_1);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(1u, matches->size());
+  CheckMatches(matches, {web_app_2.get()}, {profile_1_});
+
+  matches = Prefs().FindMatchingUrlHandlers(www_en_origin_url_1);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(1u, matches->size());
+  CheckMatches(matches, {web_app_2.get()}, {profile_1_});
+}
+
+TEST_F(UrlHandlerPrefsTest, SubdomainMatch_DifferentLevels) {
+  GURL en_origin_url_1("https://en.origin-1.com/abc");
+  GURL www_en_origin_url_1("https://www.en.origin-1.com/abc");
+
+  // This handler will match "https://*.origin-1.com" urls.
+  const auto web_app_1 = WebAppWithUrlHandlers(
+      app_url_1_,
+      {apps::UrlHandlerInfo(origin_1_, /*has_origin_wildcard*/ true)});
+  Prefs().AddWebApp(web_app_1->app_id(), profile_1_, web_app_1->url_handlers());
+
+  url::Origin en_origin_1 = url::Origin::Create(en_origin_url_1);
+  const auto web_app_2 = WebAppWithUrlHandlers(
+      app_url_2_,
+      {apps::UrlHandlerInfo(en_origin_1, /*has_origin_wildcard*/ true)});
+  Prefs().AddWebApp(web_app_2->app_id(), profile_1_, web_app_2->url_handlers());
+
+  // Both handlers should match a URL that has a longer origin.
+  auto matches = Prefs().FindMatchingUrlHandlers(en_origin_url_1);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(2u, matches->size());
+  CheckMatches(matches, {web_app_2.get(), web_app_1.get()},
+               {profile_1_, profile_1_});
+
+  matches = Prefs().FindMatchingUrlHandlers(www_en_origin_url_1);
+  EXPECT_TRUE(matches.has_value());
+  EXPECT_EQ(2u, matches->size());
+  CheckMatches(matches, {web_app_2.get(), web_app_1.get()},
+               {profile_1_, profile_1_});
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/system_web_app_manager.cc b/chrome/browser/web_applications/system_web_app_manager.cc
index c7a10e0..45bfe7c 100644
--- a/chrome/browser/web_applications/system_web_app_manager.cc
+++ b/chrome/browser/web_applications/system_web_app_manager.cc
@@ -51,6 +51,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/internal_app_id_constants.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.h"
@@ -69,7 +70,6 @@
 #include "chromeos/components/connectivity_diagnostics/url_constants.h"
 #include "chromeos/components/help_app_ui/url_constants.h"
 #include "chromeos/components/media_app_ui/url_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "components/policy/core/common/policy_pref_names.h"
diff --git a/chrome/browser/web_launch/web_launch_files_helper.cc b/chrome/browser/web_launch/web_launch_files_helper.cc
index 7642148..6c97c14 100644
--- a/chrome/browser/web_launch/web_launch_files_helper.cc
+++ b/chrome/browser/web_launch/web_launch_files_helper.cc
@@ -72,10 +72,10 @@
 namespace {
 
 // On Chrome OS paths that exist on an external mount point need to be treated
-// differently to make sure the native file system code accesses these paths via
+// differently to make sure the File System Access code accesses these paths via
 // the correct file system backend. This method checks if this is the case, and
-// updates `entry_path` to the path that should be used by the native file
-// system implementation.
+// updates `entry_path` to the path that should be used by the File System
+// Access implementation.
 content::FileSystemAccessEntryFactory::PathType MaybeRemapPath(
     base::FilePath* entry_path) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 9a5e82c5..c069c24 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1612364365-4004087cb28f5899984f6776af32ee447f340d67.profdata
+chrome-win32-master-1612374575-0d03e205c1c03ac97a6c0cba482ec5d9a6ee09b7.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 29a85f22..f813904 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1612364365-c74b74b67f7921589c07ca7b662ca77112879da1.profdata
+chrome-win64-master-1612385785-808d22cf6d008fb1ebde94dcad4d6769e1aa47e1.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index 499335ac..3208356 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -138,6 +138,7 @@
         "$root_gen_dir/chrome/gaia_auth_host_resources.pak",
         "$root_gen_dir/chrome/history_resources.pak",
         "$root_gen_dir/chrome/local_ntp_resources.pak",
+        "$root_gen_dir/chrome/memories_resources.pak",
         "$root_gen_dir/chrome/new_tab_page_resources.pak",
         "$root_gen_dir/chrome/read_later_resources.pak",
         "$root_gen_dir/chrome/settings_resources.pak",
@@ -155,6 +156,7 @@
         "//chrome/browser/resources/downloads:resources",
         "//chrome/browser/resources/gaia_auth_host:resources",
         "//chrome/browser/resources/history:resources",
+        "//chrome/browser/resources/memories:resources",
         "//chrome/browser/resources/new_tab_page:resources",
         "//chrome/browser/resources/read_later:resources",
         "//chrome/browser/resources/settings:resources",
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index cef4443..fc2f3e1 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -239,6 +239,13 @@
 // UI surfaces.
 const base::Feature kDesktopPWAsAppIconShortcutsMenuUI{
     "DesktopPWAsAppIconShortcutsMenuUI", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables attention badging for PWA icons in the shelf and launcher.
+const base::Feature kDesktopPWAsAttentionBadgingCrOS{
+    "DesktopPWAsAttentionBadgingCrOS", base::FEATURE_ENABLED_BY_DEFAULT};
+constexpr base::FeatureParam<std::string> kDesktopPWAsAttentionBadgingCrOSParam{
+    &kDesktopPWAsAttentionBadgingCrOS, "badge-source",
+    switches::kDesktopPWAsAttentionBadgingCrOSApiOnly};
 #endif
 
 // When installing default installed PWAs, we wait for service workers
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index bd26ef12..30b38a2 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -177,6 +177,12 @@
 #endif
 
 COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDesktopPWAsAttentionBadgingCrOS;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<std::string>
+    kDesktopPWAsAttentionBadgingCrOSParam;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kDesktopPWAsCacheDuringDefaultInstall;
 
 COMPONENT_EXPORT(CHROME_FEATURES)
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc
index 07111c3..34b525ff2 100644
--- a/chrome/common/chrome_paths.cc
+++ b/chrome/common/chrome_paths.cc
@@ -433,7 +433,7 @@
 #endif
 // TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
 // complete.
-#if defined(OS_CHROMEOS) ||                                  \
+#if BUILDFLAG(IS_CHROMEOS_ASH) ||                            \
     ((defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \
      BUILDFLAG(CHROMIUM_BRANDING)) ||                        \
     defined(OS_MAC)
diff --git a/chrome/common/chrome_paths.h b/chrome/common/chrome_paths.h
index 74573e0..0dfe8a66 100644
--- a/chrome/common/chrome_paths.h
+++ b/chrome/common/chrome_paths.h
@@ -53,7 +53,7 @@
 #endif
 // TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
 // complete.
-#if defined(OS_CHROMEOS) ||                                  \
+#if BUILDFLAG(IS_CHROMEOS_ASH) ||                            \
     ((defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \
      BUILDFLAG(CHROMIUM_BRANDING)) ||                        \
     defined(OS_MAC)
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 9021c751..ef6fd0273 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -158,9 +158,7 @@
 // apps.
 const char kDebugPackedApps[]               = "debug-packed-apps";
 
-// Enables attention badging for PWA icons in the shelf and launcher.
-const char kDesktopPWAsAttentionBadgingCrOS[] =
-    "desktop-pwas-attention-badging-cros";
+// Values for the enable-desktop-pwas-attention-badging-cros flag.
 const char kDesktopPWAsAttentionBadgingCrOSApiAndNotifications[] =
     "api-and-notifications";
 const char kDesktopPWAsAttentionBadgingCrOSApiOnly[] = "api-only";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 10c2ac8..df5bf330 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -65,7 +65,6 @@
 extern const char kCustomDevtoolsFrontend[];
 extern const char kDebugEnableFrameToggle[];
 extern const char kDebugPackedApps[];
-extern const char kDesktopPWAsAttentionBadgingCrOS[];
 extern const char kDesktopPWAsAttentionBadgingCrOSApiAndNotifications[];
 extern const char kDesktopPWAsAttentionBadgingCrOSApiOnly[];
 extern const char kDesktopPWAsAttentionBadgingCrOSNotificationsOnly[];
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 843f86e..0188357 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1982,6 +1982,12 @@
 // outlive the app installation and uninstallation.
 const char kWebAppsPreferences[] = "web_apps.web_app_ids";
 
+#if defined(OS_WIN) || defined(OS_MAC) || \
+    (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS))
+// Dictionary that maps origins to web apps that can act as URL handlers.
+const char kWebAppsUrlHandlerInfo[] = "web_apps.url_handler_info";
+#endif
+
 const char kWebAppsUserDisplayModeCleanedUp[] =
     "web_apps.user_display_mode_cleaned_up";
 
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 54bb9fe..4520417e7 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -663,6 +663,12 @@
 extern const char kWebAppsAppAgnosticIphState[];
 extern const char kWebAppsLastPreinstallSynchronizeVersion[];
 extern const char kWebAppsPreferences[];
+
+#if defined(OS_WIN) || defined(OS_MAC) || \
+    (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS))
+extern const char kWebAppsUrlHandlerInfo[];
+#endif
+
 extern const char kWebAppsUserDisplayModeCleanedUp[];
 extern const char kSystemWebAppLastUpdateVersion[];
 extern const char kSystemWebAppLastInstalledLocale[];
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index e4f35ab..767a9fd 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -111,6 +111,7 @@
 const char kChromeUIMediaFeedsHost[] = "media-feeds";
 const char kChromeUIMediaHistoryHost[] = "media-history";
 const char kChromeUIMediaRouterInternalsHost[] = "media-router-internals";
+const char kChromeUIMemoriesHost[] = "memories";
 const char kChromeUIMemoryInternalsHost[] = "memory-internals";
 const char kChromeUINTPTilesInternalsHost[] = "ntp-tiles-internals";
 const char kChromeUINaClHost[] = "nacl";
@@ -483,6 +484,7 @@
     kChromeUIManagementHost,
 #endif
     kChromeUIMediaEngagementHost,
+    kChromeUIMemoriesHost,
     kChromeUINetExportHost,
     kChromeUINetInternalsHost,
     kChromeUINewTabHost,
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index c538ab5..7c8b02a 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -113,6 +113,7 @@
 extern const char kChromeUIMediaFeedsHost[];
 extern const char kChromeUIMediaHistoryHost[];
 extern const char kChromeUIMediaRouterInternalsHost[];
+extern const char kChromeUIMemoriesHost[];
 extern const char kChromeUIMemoryInternalsHost[];
 extern const char kChromeUINTPTilesInternalsHost[];
 extern const char kChromeUINaClHost[];
diff --git a/chrome/renderer/media/DEPS b/chrome/renderer/media/DEPS
index f425a01..c06d13a5 100644
--- a/chrome/renderer/media/DEPS
+++ b/chrome/renderer/media/DEPS
@@ -10,6 +10,6 @@
 
 specific_include_rules = {
   "chrome_key_systems.cc" : [
-    "+chromeos/constants/chromeos_features.h",
+    "+ash/constants/ash_features.h",
   ],
-}
\ No newline at end of file
+}
diff --git a/chrome/renderer/media/chrome_key_systems.cc b/chrome/renderer/media/chrome_key_systems.cc
index 2160697..d0c14fb 100644
--- a/chrome/renderer/media/chrome_key_systems.cc
+++ b/chrome/renderer/media/chrome_key_systems.cc
@@ -41,7 +41,7 @@
 // component updated CDM on all desktop platforms and remove this.
 #include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR. // nogncheck
 #if BUILDFLAG(ENABLE_PLATFORM_HEVC) && BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC) && BUILDFLAG(IS_CHROMEOS_ASH)
 // The following must be after widevine_cdm_version.h.
 #if defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
diff --git a/chrome/services/machine_learning/BUILD.gn b/chrome/services/machine_learning/BUILD.gn
index 5587c111..e48a314 100644
--- a/chrome/services/machine_learning/BUILD.gn
+++ b/chrome/services/machine_learning/BUILD.gn
@@ -67,7 +67,7 @@
     sources += [ "in_process_tflite_predictor_unittest.cc" ]
   }
 
-  data = [ "//chrome/test/data/" ]
+  data = [ "//components/test/data/optimization_guide/" ]
 
   deps = [
     ":machine_learning",
@@ -84,7 +84,7 @@
 
 if (build_with_tflite_lib) {
   copy("tflite_simple_test") {
-    sources = [ "//chrome/test/data/simple_test.tflite" ]
+    sources = [ "//components/test/data/optimization_guide/simple_test.tflite" ]
     outputs = [ "$root_out_dir/test_data/simple_test.tflite" ]
   }
 }
diff --git a/chrome/services/machine_learning/README.md b/chrome/services/machine_learning/README.md
index fa244d9..1770b339 100644
--- a/chrome/services/machine_learning/README.md
+++ b/chrome/services/machine_learning/README.md
@@ -4,13 +4,13 @@
 ([Design doc](https://docs.google.com/document/d/1i5uSTFe3uKwHifVQ0aFs6kYfsGlCt_ZGCiOgqcYM0Tg/edit?usp=sharing))
 
 
-To build Chrome with TFLite library follow these instructions. For the unit test we use a [simple tflite model](../../test/data/simple_test.tflite). This is a simple sequential model as following:
+To build Chrome with TFLite library follow these instructions. For the unit test we use a [simple tflite model](//components/test/data/optimization_guide/simple_test.tflite). This is a simple sequential model as following:
 
 ```python
 input_shape = (32, 32, 3)
 model = tf.keras.models.Sequential([
     tf.keras.Input(shape=input_shape, dtype=np.float32),
-    tf.keras.layers.Conv2D(16, 3, strides=(1, 1), activation='relu', padding='same', 
+    tf.keras.layers.Conv2D(16, 3, strides=(1, 1), activation='relu', padding='same',
     input_shape=input_shape),
     tf.keras.layers.MaxPooling2D((2, 2)),
     tf.keras.layers.Flatten(),
@@ -25,7 +25,7 @@
   cd tensorflow
 
   for x86 architecture:
-    
+
     bazel build tensorflow/lite/c:libtensorflowlite_c.so
 
   for android:
@@ -37,12 +37,11 @@
   link the library to a soft link in system library directory under /lib/
 
 Copy libraries:
-  
+
   c_api.h and common.h [here](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/c) to into third_party/tensorflow/lite/c
 
 Build TFLite in chrome:
-  
+
   Set flag build_with_tflite_lib=true
-  
+
   Uncomment thirdparty library in [machine learning header file](./machine_learning_tflite_predictor.h).
-  
\ No newline at end of file
diff --git a/chrome/services/machine_learning/in_process_tflite_predictor_unittest.cc b/chrome/services/machine_learning/in_process_tflite_predictor_unittest.cc
index e4e2b4ff..c97c34c3 100644
--- a/chrome/services/machine_learning/in_process_tflite_predictor_unittest.cc
+++ b/chrome/services/machine_learning/in_process_tflite_predictor_unittest.cc
@@ -46,9 +46,10 @@
     EXPECT_TRUE(
         base::PathService::Get(base::DIR_SOURCE_ROOT, &model_file_path));
 
-    model_file_path = model_file_path.Append(FILE_PATH_LITERAL("chrome"))
+    model_file_path = model_file_path.Append(FILE_PATH_LITERAL("components"))
                           .Append(FILE_PATH_LITERAL("test"))
                           .Append(FILE_PATH_LITERAL("data"))
+                          .Append(FILE_PATH_LITERAL("optimization_guide"))
                           .Append(FILE_PATH_LITERAL("simple_test.tflite"));
     EXPECT_TRUE(base::PathExists(model_file_path));
     return model_file_path.AsUTF8Unsafe();
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 0c646c70..7a11bde 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -927,6 +927,7 @@
       "//chrome/browser/page_load_metrics/integration_tests/data/",
       "//components/test/data/arc/",
       "//components/test/data/autofill/",
+      "//components/test/data/optimization_guide/",
       "//components/test/data/payments/",
       "//components/test/data/update_client/",
       "//content/test/data/",
@@ -5782,6 +5783,13 @@
       "//printing/mojom",
     ]
 
+    if (is_win || is_mac || is_linux || is_chromeos) {
+      sources += [
+        "../services/printing/print_backend_service_test_impl.cc",
+        "../services/printing/print_backend_service_test_impl.h",
+      ]
+    }
+
     if (enable_print_preview) {
       sources += [
         "../browser/printing/print_preview_dialog_controller_unittest.cc",
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index e5a1cf3..b248e4a 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -113,6 +113,15 @@
       "//third_party/axe-core/axe.js",
     ]
 
+    deps = [
+      ":modulize",
+      "settings:preprocess",
+      "//build:branding_buildflags",
+      "//chrome/browser/ui",
+      "//services/network/public/cpp",
+      "//skia",
+    ]
+
     if (is_chromeos_ash) {
       gen_include_files += [
         "settings/chromeos/a11y/os_settings_accessibility_test.js",
@@ -129,6 +138,7 @@
 
     if (is_chromeos_ash || is_win) {
       sources += [ "inline_login/inline_login_browsertest.js" ]
+      deps += [ "//build:chromeos_buildflags" ]
     }
 
     if (is_chromeos_ash) {
@@ -190,14 +200,6 @@
       sources += [ "commander/commander_browsertest.js" ]
     }
 
-    deps = [
-      ":modulize",
-      "settings:preprocess",
-      "//build:branding_buildflags",
-      "//chrome/browser/ui",
-      "//services/network/public/cpp",
-      "//skia",
-    ]
     data = [
       "$root_gen_dir/chrome/test/data/webui/cr_components/managed_footnote_test.m.js",
       "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_button_tests.m.js",
diff --git a/chrome/test/data/webui/chromeos/crostini_upgrader_browsertest.js b/chrome/test/data/webui/chromeos/crostini_upgrader_browsertest.js
index 08848e4..0c65dab 100644
--- a/chrome/test/data/webui/chromeos/crostini_upgrader_browsertest.js
+++ b/chrome/test/data/webui/chromeos/crostini_upgrader_browsertest.js
@@ -7,7 +7,7 @@
  */
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
 
-GEN('#include "chromeos/constants/chromeos_features.h"');
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
 
 function CrostiniUpgraderBrowserTest() {}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js
index 082e5832..7c7a3ba4 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js
@@ -19,7 +19,7 @@
 
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
 
-GEN('#include "chromeos/constants/chromeos_features.h"');
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
 
 const dxTestSuites = 'chromeos/diagnostics/diagnostics_app_unified_test.js';
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_browsertest.js b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_browsertest.js
index 80f92cb..955c3b9 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_browsertest.js
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_browsertest.js
@@ -10,8 +10,8 @@
   '//chrome/test/data/webui/polymer_browser_test_base.js',
 ]);
 
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
-GEN('#include "chromeos/constants/chromeos_features.h"');
 
 // This file bootstraps the other tests written in Javascript.
 class EmojiPickerBrowserTest extends PolymerTest {
@@ -50,4 +50,4 @@
 
 TEST_F('EmojiPickerStoreTest', 'All', function() {
   mocha.run();
-});
\ No newline at end of file
+});
diff --git a/chrome/test/data/webui/chromeos/scanning/scanning_app_browsertest.js b/chrome/test/data/webui/chromeos/scanning/scanning_app_browsertest.js
index 1aa884cf..865eb35 100644
--- a/chrome/test/data/webui/chromeos/scanning/scanning_app_browsertest.js
+++ b/chrome/test/data/webui/chromeos/scanning/scanning_app_browsertest.js
@@ -19,7 +19,7 @@
 
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
 
-GEN('#include "chromeos/constants/chromeos_features.h"');
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
 
 /**
diff --git a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js
index 57b4ac1..e6b6dace 100644
--- a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js
+++ b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js
@@ -7,8 +7,8 @@
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
 
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
-GEN('#include "chromeos/constants/chromeos_features.h"');
 
 // Polymer 2 test list format:
 //
diff --git a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js
index a939cf5..e5b4d88d7 100644
--- a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js
+++ b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js
@@ -6,8 +6,9 @@
 
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
+
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
-GEN('#include "chromeos/constants/chromeos_features.h"');
 
 // clang-format off
 [['CrPolicyNetworkBehaviorMojo', 'network/cr_policy_network_behavior_mojo_tests.m.js'],
diff --git a/chrome/test/data/webui/inline_login/inline_login_browsertest.js b/chrome/test/data/webui/inline_login/inline_login_browsertest.js
index fb128c8..2abe22a 100644
--- a/chrome/test/data/webui/inline_login/inline_login_browsertest.js
+++ b/chrome/test/data/webui/inline_login/inline_login_browsertest.js
@@ -10,9 +10,10 @@
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
 
+GEN('#include "build/chromeos_buildflags.h"');
 GEN('#include "content/public/test/browser_test.h"');
-GEN('#if defined(OS_CHROMEOS)');
-GEN('#include "chromeos/constants/chromeos_features.h"');
+GEN('#if BUILDFLAG(IS_CHROMEOS_ASH)');
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#endif');
 
 // eslint-disable-next-line no-var
@@ -49,7 +50,7 @@
   this.runMochaTest(inline_login_test.TestNames.BackButton);
 });
 
-GEN('#if defined(OS_CHROMEOS)');
+GEN('#if BUILDFLAG(IS_CHROMEOS_ASH)');
 // eslint-disable-next-line no-var
 var InlineLoginBrowserTestWithAccountManagementFlowsV2Enabled =
     class extends InlineLoginBrowserTest {
diff --git a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
index f899937..f8fcf99 100644
--- a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
+++ b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
@@ -6,7 +6,7 @@
 
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
 
-GEN('#include "chromeos/constants/chromeos_features.h"');
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
 GEN('#include "build/chromeos_buildflags.h"');
 
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
index a61fad3..6b5e45c 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -10,11 +10,11 @@
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
 
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "ash/public/cpp/ash_features.h"');
 GEN('#include "build/branding_buildflags.h"');
 GEN('#include "chrome/browser/nearby_sharing/common/nearby_share_features.h"');
 GEN('#include "chrome/common/chrome_features.h"');
-GEN('#include "chromeos/constants/chromeos_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
 GEN('#include "ui/display/display_features.h"');
 
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
index 4a5c0aa2..77fd65df 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
@@ -5,11 +5,12 @@
 /** @fileoverview Tests for shared Polymer 3 elements. */
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
+
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "ash/public/cpp/ash_features.h"');
 GEN('#include "chrome/common/buildflags.h"');
 GEN('#include "build/branding_buildflags.h"');
 GEN('#include "content/public/test/browser_test.h"');
-GEN('#include "chromeos/constants/chromeos_features.h"');
 GEN('#include "chrome/browser/nearby_sharing/common/nearby_share_features.h"');
 
 /** Test fixture for shared Polymer 3 elements. */
diff --git a/chromeos/DEPS b/chromeos/DEPS
index 8c9f915..e2f5060 100644
--- a/chromeos/DEPS
+++ b/chromeos/DEPS
@@ -2,6 +2,7 @@
 # low level Chrome OS system library that may be used by targets that need to
 # be kept as small as possible.
 include_rules = [
+  "+ash/constants",
   "+components/account_id/account_id.h",
   "+components/device_event_log",
   "+components/policy/proto",
diff --git a/chromeos/audio/DEPS b/chromeos/audio/DEPS
index 7033be9e..3592e83 100644
--- a/chromeos/audio/DEPS
+++ b/chromeos/audio/DEPS
@@ -1,6 +1,7 @@
 noparent = True
 
 include_rules = [
+  "+ash/constants",
   "+base",
   "+chromeos/constants",
   "+chromeos/dbus",
diff --git a/chromeos/audio/cras_audio_handler.cc b/chromeos/audio/cras_audio_handler.cc
index c817d0bc..ad6e1beb 100644
--- a/chromeos/audio/cras_audio_handler.cc
+++ b/chromeos/audio/cras_audio_handler.cc
@@ -13,6 +13,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/logging.h"
@@ -23,7 +24,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chromeos/audio/audio_device.h"
 #include "chromeos/audio/audio_devices_pref_handler_stub.h"
-#include "chromeos/constants/chromeos_features.h"
 
 using std::max;
 using std::min;
diff --git a/chromeos/components/drivefs/drivefs_host.cc b/chromeos/components/drivefs/drivefs_host.cc
index d2dcaff..afb07e3 100644
--- a/chromeos/components/drivefs/drivefs_host.cc
+++ b/chromeos/components/drivefs/drivefs_host.cc
@@ -8,13 +8,13 @@
 #include <set>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/strings/strcat.h"
 #include "base/unguessable_token.h"
 #include "chromeos/components/drivefs/drivefs_bootstrap.h"
 #include "chromeos/components/drivefs/drivefs_host_observer.h"
 #include "chromeos/components/drivefs/drivefs_search.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/drive/drive_notification_manager.h"
 #include "components/drive/drive_notification_observer.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
diff --git a/chromeos/components/eche_app_ui/test/eche_app_ui_browsertest.js b/chromeos/components/eche_app_ui/test/eche_app_ui_browsertest.js
index 5418d95..72c6ba4 100644
--- a/chromeos/components/eche_app_ui/test/eche_app_ui_browsertest.js
+++ b/chromeos/components/eche_app_ui/test/eche_app_ui_browsertest.js
@@ -6,8 +6,8 @@
  * @fileoverview Test suite for chrome://eche-app.
  */
 
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
-GEN('#include "chromeos/constants/chromeos_features.h"');
 
 const HOST_ORIGIN = 'chrome://eche-app';
 
@@ -35,4 +35,4 @@
 
   assertEquals(header.innerText, 'Eche App');
   assertEquals(document.location.origin, HOST_ORIGIN);
-});
\ No newline at end of file
+});
diff --git a/chromeos/components/help_app_ui/help_app_page_handler.cc b/chromeos/components/help_app_ui/help_app_page_handler.cc
index 02688ed..562057ff 100644
--- a/chromeos/components/help_app_ui/help_app_page_handler.cc
+++ b/chromeos/components/help_app_ui/help_app_page_handler.cc
@@ -6,10 +6,10 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "chromeos/components/help_app_ui/help_app_ui.h"
 #include "chromeos/components/help_app_ui/help_app_ui_delegate.h"
-#include "chromeos/constants/chromeos_features.h"
 
 HelpAppPageHandler::HelpAppPageHandler(
     chromeos::HelpAppUI* help_app_ui,
diff --git a/chromeos/components/help_app_ui/help_app_ui.cc b/chromeos/components/help_app_ui/help_app_ui.cc
index 68e2bd5..ee2a8d9 100644
--- a/chromeos/components/help_app_ui/help_app_ui.cc
+++ b/chromeos/components/help_app_ui/help_app_ui.cc
@@ -6,13 +6,13 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "chromeos/components/help_app_ui/help_app_page_handler.h"
 #include "chromeos/components/help_app_ui/help_app_untrusted_ui.h"
 #include "chromeos/components/help_app_ui/url_constants.h"
 #include "chromeos/components/local_search_service/public/cpp/local_search_service_proxy.h"
 #include "chromeos/components/local_search_service/public/cpp/local_search_service_proxy_factory.h"
 #include "chromeos/components/local_search_service/public/mojom/types.mojom.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/grit/chromeos_help_app_resources.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
diff --git a/chromeos/components/help_app_ui/test/help_app_ui_browsertest.js b/chromeos/components/help_app_ui/test/help_app_ui_browsertest.js
index aadfe4b5..461ae49 100644
--- a/chromeos/components/help_app_ui/test/help_app_ui_browsertest.js
+++ b/chromeos/components/help_app_ui/test/help_app_ui_browsertest.js
@@ -8,7 +8,7 @@
 
 GEN('#include "chromeos/components/help_app_ui/test/help_app_ui_browsertest.h"');
 
-GEN('#include "chromeos/constants/chromeos_features.h"');
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
 
 const HOST_ORIGIN = 'chrome://help-app';
diff --git a/chromeos/components/media_app_ui/test/media_app_ui_browsertest.js b/chromeos/components/media_app_ui/test/media_app_ui_browsertest.js
index c3e9df6..c835d67 100644
--- a/chromeos/components/media_app_ui/test/media_app_ui_browsertest.js
+++ b/chromeos/components/media_app_ui/test/media_app_ui_browsertest.js
@@ -7,7 +7,7 @@
  */
 GEN('#include "chromeos/components/media_app_ui/test/media_app_ui_browsertest.h"');
 
-GEN('#include "chromeos/constants/chromeos_features.h"');
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
 GEN('#include "third_party/blink/public/common/features.h"');
 
diff --git a/chromeos/components/multidevice/stub_multidevice_util.cc b/chromeos/components/multidevice/stub_multidevice_util.cc
index 394494b..c23a14d7 100644
--- a/chromeos/components/multidevice/stub_multidevice_util.cc
+++ b/chromeos/components/multidevice/stub_multidevice_util.cc
@@ -7,13 +7,13 @@
 #include <map>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/base64.h"
 #include "base/base64url.h"
 #include "base/no_destructor.h"
 #include "base/system/sys_info.h"
 #include "base/time/time.h"
 #include "chromeos/components/multidevice/beacon_seed.h"
-#include "chromeos/constants/chromeos_features.h"
 
 namespace chromeos {
 
diff --git a/chromeos/components/phonehub/connection_manager_impl.cc b/chromeos/components/phonehub/connection_manager_impl.cc
index f69ea1e..3a36bc2 100644
--- a/chromeos/components/phonehub/connection_manager_impl.cc
+++ b/chromeos/components/phonehub/connection_manager_impl.cc
@@ -4,6 +4,7 @@
 
 #include "chromeos/components/phonehub/connection_manager_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/callback_helpers.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
diff --git a/chromeos/components/phonehub/connection_manager_impl_unittest.cc b/chromeos/components/phonehub/connection_manager_impl_unittest.cc
index 624587e..12355f7c 100644
--- a/chromeos/components/phonehub/connection_manager_impl_unittest.cc
+++ b/chromeos/components/phonehub/connection_manager_impl_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/test/metrics/histogram_tester.h"
diff --git a/chromeos/components/quick_answers/quick_answers_client.cc b/chromeos/components/quick_answers/quick_answers_client.cc
index 66c99b4..703d09c 100644
--- a/chromeos/components/quick_answers/quick_answers_client.cc
+++ b/chromeos/components/quick_answers/quick_answers_client.cc
@@ -6,10 +6,10 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.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"
-#include "chromeos/constants/chromeos_features.h"
 #include "third_party/icu/source/common/unicode/locid.h"
 
 namespace chromeos {
diff --git a/chromeos/components/quick_answers/quick_answers_client_unittest.cc b/chromeos/components/quick_answers/quick_answers_client_unittest.cc
index 8304543..d2fd61c 100644
--- a/chromeos/components/quick_answers/quick_answers_client_unittest.cc
+++ b/chromeos/components/quick_answers/quick_answers_client_unittest.cc
@@ -8,13 +8,13 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/assistant/assistant_state.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/test_helpers.h"
 #include "chromeos/components/quick_answers/utils/quick_answers_utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/test/test_url_loader_factory.h"
diff --git a/chromeos/components/quick_answers/result_loader.cc b/chromeos/components/quick_answers/result_loader.cc
index a7c2e7e..f8cf9e91 100644
--- a/chromeos/components/quick_answers/result_loader.cc
+++ b/chromeos/components/quick_answers/result_loader.cc
@@ -3,12 +3,12 @@
 // found in the LICENSE file.
 #include "chromeos/components/quick_answers/result_loader.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "chromeos/components/quick_answers/quick_answers_model.h"
 #include "chromeos/components/quick_answers/search_result_loader.h"
 #include "chromeos/components/quick_answers/translation_result_loader.h"
 #include "chromeos/components/quick_answers/utils/quick_answers_metrics.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/simple_url_loader.h"
 
diff --git a/chromeos/components/quick_answers/understanding/intent_generator.cc b/chromeos/components/quick_answers/understanding/intent_generator.cc
index 10d9ebc..2c781f6 100644
--- a/chromeos/components/quick_answers/understanding/intent_generator.cc
+++ b/chromeos/components/quick_answers/understanding/intent_generator.cc
@@ -6,13 +6,13 @@
 
 #include <map>
 
+#include "ash/constants/ash_features.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/quick_answers_model.h"
 #include "chromeos/components/quick_answers/utils/quick_answers_utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
 #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chromeos/components/quick_answers/understanding/intent_generator_unittest.cc b/chromeos/components/quick_answers/understanding/intent_generator_unittest.cc
index 7ffe638e..e715aac 100644
--- a/chromeos/components/quick_answers/understanding/intent_generator_unittest.cc
+++ b/chromeos/components/quick_answers/understanding/intent_generator_unittest.cc
@@ -7,12 +7,12 @@
 #include <memory>
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.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/utils/quick_answers_utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/machine_learning/public/cpp/fake_service_connection.h"
 #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
 #include "chromeos/services/machine_learning/public/mojom/text_classifier.mojom.h"
diff --git a/chromeos/components/quick_answers/utils/language_detector.cc b/chromeos/components/quick_answers/utils/language_detector.cc
index 1500057..3d89ba5 100644
--- a/chromeos/components/quick_answers/utils/language_detector.cc
+++ b/chromeos/components/quick_answers/utils/language_detector.cc
@@ -4,9 +4,9 @@
 
 #include "chromeos/components/quick_answers/utils/language_detector.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/callback.h"
 #include "base/metrics/field_trial_params.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace chromeos {
diff --git a/chromeos/components/quick_answers/utils/language_detector_unittest.cc b/chromeos/components/quick_answers/utils/language_detector_unittest.cc
index 3d1abc42..481cb7e 100644
--- a/chromeos/components/quick_answers/utils/language_detector_unittest.cc
+++ b/chromeos/components/quick_answers/utils/language_detector_unittest.cc
@@ -7,13 +7,13 @@
 #include <memory>
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/run_loop.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/utils/quick_answers_utils.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
 #include "chromeos/services/machine_learning/public/mojom/text_classifier.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromeos/components/telemetry_extension_ui/test/telemetry_extension_ui_browsertest.js b/chromeos/components/telemetry_extension_ui/test/telemetry_extension_ui_browsertest.js
index 5c3a1421..5de6140f 100644
--- a/chromeos/components/telemetry_extension_ui/test/telemetry_extension_ui_browsertest.js
+++ b/chromeos/components/telemetry_extension_ui/test/telemetry_extension_ui_browsertest.js
@@ -8,8 +8,8 @@
 
 GEN('#include "chromeos/components/telemetry_extension_ui/test/telemetry_extension_ui_browsertest.h"');
 
+GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
-GEN('#include "chromeos/constants/chromeos_features.h"');
 
 const HOST_ORIGIN = 'chrome://telemetry-extension';
 const UNTRUSTED_HOST_ORIGIN = 'chrome-untrusted://telemetry-extension';
diff --git a/chromeos/constants/BUILD.gn b/chromeos/constants/BUILD.gn
index 3c98490..cc6e1a7 100644
--- a/chromeos/constants/BUILD.gn
+++ b/chromeos/constants/BUILD.gn
@@ -13,10 +13,10 @@
     "//build:branding_buildflags",
   ]
   sources = [
+    "../../ash/constants/ash_features.cc",
+    "../../ash/constants/ash_features.h",
     "chromeos_constants.cc",
     "chromeos_constants.h",
-    "chromeos_features.cc",
-    "chromeos_features.h",
     "chromeos_paths.cc",
     "chromeos_paths.h",
     "chromeos_pref_names.cc",
diff --git a/chromeos/constants/OWNERS b/chromeos/constants/OWNERS
index 9a6f659..3e39d9b2 100644
--- a/chromeos/constants/OWNERS
+++ b/chromeos/constants/OWNERS
@@ -1,4 +1,2 @@
-per-file chromeos_features.cc=*
-per-file chromeos_features.h=*
 per-file chromeos_switches.cc=*
 per-file chromeos_switches.h=*
diff --git a/chromeos/constants/chromeos_switches.h b/chromeos/constants/chromeos_switches.h
index a6e89c6..571525b3 100644
--- a/chromeos/constants/chromeos_switches.h
+++ b/chromeos/constants/chromeos_switches.h
@@ -15,7 +15,7 @@
 // with any code that is specific to the chromeos system). Chrome OS specific
 // UI should be in src/ash.
 //
-// Prefer adding Features over switches. Features go in chromeos_features.h.
+// Prefer adding Features over switches. Features go in ash_features.h.
 //
 // Note: If you add a switch, consider if it needs to be copied to a subsequent
 // command line if the process executes a new copy of itself.  (For example,
diff --git a/chromeos/disks/BUILD.gn b/chromeos/disks/BUILD.gn
index 0671f69f..fa944dde 100644
--- a/chromeos/disks/BUILD.gn
+++ b/chromeos/disks/BUILD.gn
@@ -50,7 +50,6 @@
     ":disks",
     ":test_support",
     "//base/test:test_support",
-    "//chromeos/constants",
     "//chromeos/dbus:test_support",
     "//chromeos/dbus/power",
     "//chromeos/dbus/power:power_manager_proto",
diff --git a/chromeos/disks/DEPS b/chromeos/disks/DEPS
index aa18272..d7fec93 100644
--- a/chromeos/disks/DEPS
+++ b/chromeos/disks/DEPS
@@ -1,8 +1,8 @@
 noparent = True
 
 include_rules = [
+  "+ash/constants",
   "+base",
-  "+chromeos/constants",
   "+chromeos/dbus",
   "+dbus",
   "+testing",
diff --git a/chromeos/disks/disk_mount_manager.cc b/chromeos/disks/disk_mount_manager.cc
index 855133e5..7798b18 100644
--- a/chromeos/disks/disk_mount_manager.cc
+++ b/chromeos/disks/disk_mount_manager.cc
@@ -13,6 +13,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -23,7 +24,6 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/observer_list.h"
 #include "base/strings/string_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/cros_disks_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/disks/disk.h"
diff --git a/chromeos/network/DEPS b/chromeos/network/DEPS
index 31d1d84..9efe1e2 100644
--- a/chromeos/network/DEPS
+++ b/chromeos/network/DEPS
@@ -1,6 +1,7 @@
 noparent = True
 
 include_rules = [
+  "+ash/constants",
   "+base",
   "+base/component_export.h",
   "+chromeos/constants",
diff --git a/chromeos/network/network_device_handler_impl.cc b/chromeos/network/network_device_handler_impl.cc
index 2ef46879..25180122 100644
--- a/chromeos/network/network_device_handler_impl.cc
+++ b/chromeos/network/network_device_handler_impl.cc
@@ -11,6 +11,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/location.h"
@@ -22,7 +23,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/shill/shill_device_client.h"
 #include "chromeos/dbus/shill/shill_ipconfig_client.h"
 #include "chromeos/network/device_state.h"
diff --git a/chromeos/network/network_handler.cc b/chromeos/network/network_handler.cc
index 7934450..630b556 100644
--- a/chromeos/network/network_handler.cc
+++ b/chromeos/network/network_handler.cc
@@ -4,8 +4,8 @@
 
 #include "chromeos/network/network_handler.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/network/auto_connect_handler.h"
 #include "chromeos/network/cellular_esim_profile_handler_impl.h"
 #include "chromeos/network/cellular_esim_uninstall_handler.h"
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.cc b/chromeos/services/assistant/assistant_manager_service_impl.cc
index fffa914e..65c39f91 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl.cc
+++ b/chromeos/services/assistant/assistant_manager_service_impl.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ambient/ambient_ui_model.h"
 #include "ash/public/cpp/assistant/assistant_state_base.h"
 #include "ash/public/cpp/assistant/controller/assistant_alarm_timer_controller.h"
@@ -30,7 +31,6 @@
 #include "base/unguessable_token.h"
 #include "chromeos/assistant/internal/internal_constants.h"
 #include "chromeos/assistant/internal/proto/google3/assistant/api/client_op/device_args.pb.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/util/version_loader.h"
 #include "chromeos/services/assistant/assistant_device_settings_delegate.h"
diff --git a/chromeos/services/assistant/proxy/service_controller_proxy.cc b/chromeos/services/assistant/proxy/service_controller_proxy.cc
index 90c2d6e5..7749aa39 100644
--- a/chromeos/services/assistant/proxy/service_controller_proxy.cc
+++ b/chromeos/services/assistant/proxy/service_controller_proxy.cc
@@ -4,12 +4,12 @@
 
 #include "chromeos/services/assistant/proxy/service_controller_proxy.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/notreached.h"
 #include "base/optional.h"
 #include "chromeos/assistant/internal/internal_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/assistant/proxy/libassistant_service_host.h"
 #include "chromeos/services/assistant/public/cpp/features.h"
 #include "chromeos/services/assistant/public/cpp/migration/assistant_manager_service_delegate.h"
diff --git a/chromeos/services/assistant/public/cpp/features.cc b/chromeos/services/assistant/public/cpp/features.cc
index 49f3f5d..9a76616 100644
--- a/chromeos/services/assistant/public/cpp/features.cc
+++ b/chromeos/services/assistant/public/cpp/features.cc
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #include "chromeos/services/assistant/public/cpp/features.h"
-#include "chromeos/constants/chromeos_features.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 
 namespace chromeos {
diff --git a/chromeos/services/assistant/service.cc b/chromeos/services/assistant/service.cc
index ec6c1ca..c1b144c 100644
--- a/chromeos/services/assistant/service.cc
+++ b/chromeos/services/assistant/service.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ambient/ambient_ui_model.h"
 #include "ash/public/cpp/assistant/assistant_state.h"
 #include "ash/public/cpp/assistant/controller/assistant_alarm_timer_controller.h"
@@ -25,7 +26,6 @@
 #include "build/buildflag.h"
 #include "chromeos/assistant/buildflags.h"
 #include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
diff --git a/chromeos/services/device_sync/cryptauth_feature_type.cc b/chromeos/services/device_sync/cryptauth_feature_type.cc
index 9588a76a..d5cb9d1 100644
--- a/chromeos/services/device_sync/cryptauth_feature_type.cc
+++ b/chromeos/services/device_sync/cryptauth_feature_type.cc
@@ -4,11 +4,11 @@
 
 #include "chromeos/services/device_sync/cryptauth_feature_type.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/base64url.h"
 #include "base/containers/flat_map.h"
 #include "base/no_destructor.h"
 #include "base/stl_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "crypto/sha2.h"
 
 namespace chromeos {
diff --git a/chromeos/services/device_sync/device_sync_impl.cc b/chromeos/services/device_sync/device_sync_impl.cc
index a26354cd..5f792e61 100644
--- a/chromeos/services/device_sync/device_sync_impl.cc
+++ b/chromeos/services/device_sync/device_sync_impl.cc
@@ -4,6 +4,7 @@
 
 #include "chromeos/services/device_sync/device_sync_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/feature_list.h"
@@ -16,7 +17,6 @@
 #include "base/unguessable_token.h"
 #include "chromeos/components/multidevice/logging/logging.h"
 #include "chromeos/components/multidevice/secure_message_delegate_impl.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/cryptauth_client_impl.h"
 #include "chromeos/services/device_sync/cryptauth_device_activity_getter_impl.h"
 #include "chromeos/services/device_sync/cryptauth_device_manager_impl.h"
diff --git a/chromeos/services/device_sync/device_sync_service_unittest.cc b/chromeos/services/device_sync/device_sync_service_unittest.cc
index 8e01995..563890f21 100644
--- a/chromeos/services/device_sync/device_sync_service_unittest.cc
+++ b/chromeos/services/device_sync/device_sync_service_unittest.cc
@@ -7,6 +7,7 @@
 #include <tuple>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
@@ -22,7 +23,6 @@
 #include "base/timer/mock_timer.h"
 #include "chromeos/components/multidevice/remote_device_test_util.h"
 #include "chromeos/components/multidevice/secure_message_delegate.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/services/device_sync/cryptauth_device_manager_impl.h"
 #include "chromeos/services/device_sync/cryptauth_device_registry_impl.h"
diff --git a/chromeos/services/device_sync/public/cpp/device_sync_client_impl.cc b/chromeos/services/device_sync/public/cpp/device_sync_client_impl.cc
index c4b00c7..e78408b3 100644
--- a/chromeos/services/device_sync/public/cpp/device_sync_client_impl.cc
+++ b/chromeos/services/device_sync/public/cpp/device_sync_client_impl.cc
@@ -8,12 +8,12 @@
 
 #include "chromeos/services/device_sync/public/cpp/device_sync_client_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/base64url.h"
 #include "base/bind.h"
 #include "chromeos/components/multidevice/expiring_remote_device_cache.h"
 #include "chromeos/components/multidevice/logging/logging.h"
 #include "chromeos/components/multidevice/remote_device.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h"
 
 namespace chromeos {
diff --git a/chromeos/services/device_sync/public/cpp/device_sync_prefs.cc b/chromeos/services/device_sync/public/cpp/device_sync_prefs.cc
index ca39fdab..3ad75eb 100644
--- a/chromeos/services/device_sync/public/cpp/device_sync_prefs.cc
+++ b/chromeos/services/device_sync/public/cpp/device_sync_prefs.cc
@@ -4,8 +4,8 @@
 
 #include "chromeos/services/device_sync/public/cpp/device_sync_prefs.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/cryptauth_device_manager.h"
 #include "chromeos/services/device_sync/cryptauth_device_registry_impl.h"
 #include "chromeos/services/device_sync/cryptauth_enrollment_manager_impl.h"
diff --git a/chromeos/services/device_sync/remote_device_provider_impl.cc b/chromeos/services/device_sync/remote_device_provider_impl.cc
index 3f8bf748..87bf6d12 100644
--- a/chromeos/services/device_sync/remote_device_provider_impl.cc
+++ b/chromeos/services/device_sync/remote_device_provider_impl.cc
@@ -6,13 +6,13 @@
 
 #include <algorithm>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_functions.h"
 #include "chromeos/components/multidevice/logging/logging.h"
 #include "chromeos/components/multidevice/secure_message_delegate_impl.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/remote_device_loader.h"
 #include "chromeos/services/device_sync/remote_device_v2_loader_impl.h"
 
diff --git a/chromeos/services/device_sync/remote_device_provider_impl_unittest.cc b/chromeos/services/device_sync/remote_device_provider_impl_unittest.cc
index 99b7a90..9c0264c 100644
--- a/chromeos/services/device_sync/remote_device_provider_impl_unittest.cc
+++ b/chromeos/services/device_sync/remote_device_provider_impl_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/containers/contains.h"
 #include "base/memory/ptr_util.h"
@@ -16,7 +17,6 @@
 #include "chromeos/components/multidevice/fake_secure_message_delegate.h"
 #include "chromeos/components/multidevice/remote_device.h"
 #include "chromeos/components/multidevice/secure_message_delegate_impl.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/cryptauth_device.h"
 #include "chromeos/services/device_sync/cryptauth_device_manager.h"
 #include "chromeos/services/device_sync/fake_cryptauth_device_manager.h"
diff --git a/chromeos/services/device_sync/synced_bluetooth_address_tracker_impl.cc b/chromeos/services/device_sync/synced_bluetooth_address_tracker_impl.cc
index 562c7f08..70c494ab 100644
--- a/chromeos/services/device_sync/synced_bluetooth_address_tracker_impl.cc
+++ b/chromeos/services/device_sync/synced_bluetooth_address_tracker_impl.cc
@@ -6,10 +6,10 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "chromeos/components/multidevice/logging/logging.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/cryptauth_scheduler.h"
 #include "chromeos/services/device_sync/pref_names.h"
 #include "chromeos/services/device_sync/proto/cryptauth_common.pb.h"
diff --git a/chromeos/services/device_sync/synced_bluetooth_address_tracker_impl_unittest.cc b/chromeos/services/device_sync/synced_bluetooth_address_tracker_impl_unittest.cc
index 5a43021..76b2a3d 100644
--- a/chromeos/services/device_sync/synced_bluetooth_address_tracker_impl_unittest.cc
+++ b/chromeos/services/device_sync/synced_bluetooth_address_tracker_impl_unittest.cc
@@ -7,11 +7,11 @@
 #include <memory>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/fake_cryptauth_scheduler.h"
 #include "chromeos/services/device_sync/pref_names.h"
 #include "components/prefs/testing_pref_service.h"
diff --git a/chromeos/services/ime/decoder/system_engine_unittest.cc b/chromeos/services/ime/decoder/system_engine_unittest.cc
index 11221968..a598fb4 100644
--- a/chromeos/services/ime/decoder/system_engine_unittest.cc
+++ b/chromeos/services/ime/decoder/system_engine_unittest.cc
@@ -4,10 +4,10 @@
 
 #include "chromeos/services/ime/decoder/system_engine.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/ime/decoder/proto_conversion.h"
 #include "chromeos/services/ime/mock_input_channel.h"
 #include "chromeos/services/ime/public/proto/messages.pb.h"
diff --git a/chromeos/services/ime/ime_service.cc b/chromeos/services/ime/ime_service.cc
index f8728a0..21cf024 100644
--- a/chromeos/services/ime/ime_service.cc
+++ b/chromeos/services/ime/ime_service.cc
@@ -9,6 +9,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/files/file_util.h"
@@ -16,7 +17,6 @@
 #include "base/notreached.h"
 #include "base/sequenced_task_runner.h"
 #include "build/buildflag.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/ime/constants.h"
 #include "chromeos/services/ime/decoder/decoder_engine.h"
 #include "chromeos/services/ime/decoder/system_engine.h"
diff --git a/chromeos/services/multidevice_setup/eligible_host_devices_provider_impl.cc b/chromeos/services/multidevice_setup/eligible_host_devices_provider_impl.cc
index 6a24d10..e7f3233 100644
--- a/chromeos/services/multidevice_setup/eligible_host_devices_provider_impl.cc
+++ b/chromeos/services/multidevice_setup/eligible_host_devices_provider_impl.cc
@@ -4,11 +4,11 @@
 
 #include "chromeos/services/multidevice_setup/eligible_host_devices_provider_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
 #include "chromeos/components/multidevice/software_feature.h"
 #include "chromeos/components/multidevice/software_feature_state.h"
-#include "chromeos/constants/chromeos_features.h"
 
 namespace chromeos {
 
diff --git a/chromeos/services/multidevice_setup/eligible_host_devices_provider_impl_unittest.cc b/chromeos/services/multidevice_setup/eligible_host_devices_provider_impl_unittest.cc
index 65a732dd..c4383ef6c 100644
--- a/chromeos/services/multidevice_setup/eligible_host_devices_provider_impl_unittest.cc
+++ b/chromeos/services/multidevice_setup/eligible_host_devices_provider_impl_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/containers/flat_set.h"
 #include "base/macros.h"
 #include "base/stl_util.h"
@@ -14,7 +15,6 @@
 #include "chromeos/components/multidevice/remote_device_test_util.h"
 #include "chromeos/components/multidevice/software_feature.h"
 #include "chromeos/components/multidevice/software_feature_state.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/proto/cryptauth_api.pb.h"
 #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h"
diff --git a/chromeos/services/multidevice_setup/grandfathered_easy_unlock_host_disabler.cc b/chromeos/services/multidevice_setup/grandfathered_easy_unlock_host_disabler.cc
index e4bc9648c..bde7b45 100644
--- a/chromeos/services/multidevice_setup/grandfathered_easy_unlock_host_disabler.cc
+++ b/chromeos/services/multidevice_setup/grandfathered_easy_unlock_host_disabler.cc
@@ -4,11 +4,11 @@
 
 #include "chromeos/services/multidevice_setup/grandfathered_easy_unlock_host_disabler.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/timer/timer.h"
 #include "chromeos/components/multidevice/logging/logging.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/public/cpp/device_sync_client.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
diff --git a/chromeos/services/multidevice_setup/grandfathered_easy_unlock_host_disabler_unittest.cc b/chromeos/services/multidevice_setup/grandfathered_easy_unlock_host_disabler_unittest.cc
index 58883ab..c32872d5 100644
--- a/chromeos/services/multidevice_setup/grandfathered_easy_unlock_host_disabler_unittest.cc
+++ b/chromeos/services/multidevice_setup/grandfathered_easy_unlock_host_disabler_unittest.cc
@@ -6,10 +6,10 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/macros.h"
 #include "base/timer/mock_timer.h"
 #include "chromeos/components/multidevice/remote_device_test_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "chromeos/services/multidevice_setup/fake_host_backend_delegate.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
diff --git a/chromeos/services/multidevice_setup/host_backend_delegate_impl.cc b/chromeos/services/multidevice_setup/host_backend_delegate_impl.cc
index 61c2a9c3..b731718 100644
--- a/chromeos/services/multidevice_setup/host_backend_delegate_impl.cc
+++ b/chromeos/services/multidevice_setup/host_backend_delegate_impl.cc
@@ -7,13 +7,13 @@
 #include <algorithm>
 #include <sstream>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/containers/contains.h"
 #include "base/memory/ptr_util.h"
 #include "chromeos/components/multidevice/logging/logging.h"
 #include "chromeos/components/multidevice/software_feature.h"
 #include "chromeos/components/multidevice/software_feature_state.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/feature_status_change.h"
 #include "chromeos/services/multidevice_setup/eligible_host_devices_provider.h"
 #include "components/prefs/pref_registry_simple.h"
diff --git a/chromeos/services/multidevice_setup/host_backend_delegate_impl_unittest.cc b/chromeos/services/multidevice_setup/host_backend_delegate_impl_unittest.cc
index 3416fd0..2a36d1af 100644
--- a/chromeos/services/multidevice_setup/host_backend_delegate_impl_unittest.cc
+++ b/chromeos/services/multidevice_setup/host_backend_delegate_impl_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/optional.h"
@@ -15,7 +16,6 @@
 #include "chromeos/components/multidevice/remote_device_test_util.h"
 #include "chromeos/components/multidevice/software_feature.h"
 #include "chromeos/components/multidevice/software_feature_state.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "chromeos/services/multidevice_setup/fake_eligible_host_devices_provider.h"
 #include "chromeos/services/multidevice_setup/fake_host_backend_delegate.h"
diff --git a/chromeos/services/multidevice_setup/host_verifier_impl.cc b/chromeos/services/multidevice_setup/host_verifier_impl.cc
index 9a4fe17..e8ff121e 100644
--- a/chromeos/services/multidevice_setup/host_verifier_impl.cc
+++ b/chromeos/services/multidevice_setup/host_verifier_impl.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/logging.h"
@@ -13,7 +14,6 @@
 #include "base/metrics/histogram_functions.h"
 #include "chromeos/components/multidevice/logging/logging.h"
 #include "chromeos/components/multidevice/software_feature.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/proto/cryptauth_common.pb.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
diff --git a/chromeos/services/multidevice_setup/host_verifier_impl_unittest.cc b/chromeos/services/multidevice_setup/host_verifier_impl_unittest.cc
index b190321..ebc1c137 100644
--- a/chromeos/services/multidevice_setup/host_verifier_impl_unittest.cc
+++ b/chromeos/services/multidevice_setup/host_verifier_impl_unittest.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/macros.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_clock.h"
@@ -15,7 +16,6 @@
 #include "chromeos/components/multidevice/remote_device_test_util.h"
 #include "chromeos/components/multidevice/software_feature.h"
 #include "chromeos/components/multidevice/software_feature_state.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/proto/cryptauth_common.pb.h"
 #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "chromeos/services/multidevice_setup/fake_host_backend_delegate.h"
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_impl.cc b/chromeos/services/multidevice_setup/multidevice_setup_impl.cc
index d0881db..2c9b6b12 100644
--- a/chromeos/services/multidevice_setup/multidevice_setup_impl.cc
+++ b/chromeos/services/multidevice_setup/multidevice_setup_impl.cc
@@ -7,6 +7,7 @@
 
 #include "chromeos/services/multidevice_setup/multidevice_setup_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/containers/contains.h"
 #include "base/containers/flat_set.h"
 #include "base/memory/ptr_util.h"
@@ -14,7 +15,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/time/default_clock.h"
 #include "chromeos/components/multidevice/logging/logging.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h"
 #include "chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.h"
 #include "chromeos/services/multidevice_setup/device_reenroller.h"
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc b/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc
index ab637a49..f229e4e1 100644
--- a/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc
+++ b/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc
@@ -6,12 +6,12 @@
 #include <memory>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "chromeos/components/multidevice/remote_device_test_util.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "chromeos/services/device_sync/public/cpp/fake_gcm_device_info_provider.h"
 #include "chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h"
diff --git a/chromeos/services/multidevice_setup/public/cpp/first_run_field_trial.cc b/chromeos/services/multidevice_setup/public/cpp/first_run_field_trial.cc
index 768a3b9..1e8e542 100644
--- a/chromeos/services/multidevice_setup/public/cpp/first_run_field_trial.cc
+++ b/chromeos/services/multidevice_setup/public/cpp/first_run_field_trial.cc
@@ -4,12 +4,12 @@
 
 #include "chromeos/services/multidevice_setup/public/cpp/first_run_field_trial.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/containers/contains.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/field_trial.h"
 #include "base/no_destructor.h"
 #include "base/system/sys_info.h"
-#include "chromeos/constants/chromeos_features.h"
 
 namespace chromeos {
 
diff --git a/chromeos/services/multidevice_setup/public/cpp/prefs.cc b/chromeos/services/multidevice_setup/public/cpp/prefs.cc
index 162706c..421754c 100644
--- a/chromeos/services/multidevice_setup/public/cpp/prefs.cc
+++ b/chromeos/services/multidevice_setup/public/cpp/prefs.cc
@@ -4,7 +4,7 @@
 
 #include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
 
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 
diff --git a/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl.cc b/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl.cc
index e437c50c..c04b8cb 100644
--- a/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl.cc
+++ b/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl.cc
@@ -6,13 +6,13 @@
 
 #include <sstream>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
 #include "chromeos/components/multidevice/logging/logging.h"
 #include "chromeos/components/multidevice/software_feature.h"
 #include "chromeos/components/multidevice/software_feature_state.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/feature_status_change.h"
 #include "chromeos/services/multidevice_setup/host_status_provider.h"
 #include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
diff --git a/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl_unittest.cc b/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl_unittest.cc
index 17ce3c0..40eedf5e 100644
--- a/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl_unittest.cc
+++ b/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/optional.h"
@@ -16,7 +17,6 @@
 #include "chromeos/components/multidevice/remote_device_test_util.h"
 #include "chromeos/components/multidevice/software_feature.h"
 #include "chromeos/components/multidevice/software_feature_state.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "chromeos/services/multidevice_setup/fake_account_status_change_delegate.h"
 #include "chromeos/services/multidevice_setup/fake_account_status_change_delegate_notifier.h"
diff --git a/chromeos/services/secure_channel/bluetooth_helper_impl.cc b/chromeos/services/secure_channel/bluetooth_helper_impl.cc
index 93d7c09e..413b18c4 100644
--- a/chromeos/services/secure_channel/bluetooth_helper_impl.cc
+++ b/chromeos/services/secure_channel/bluetooth_helper_impl.cc
@@ -4,13 +4,13 @@
 
 #include "chromeos/services/secure_channel/bluetooth_helper_impl.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/containers/flat_map.h"
 #include "base/memory/ptr_util.h"
 #include "chromeos/components/multidevice/beacon_seed.h"
 #include "chromeos/components/multidevice/logging/logging.h"
 #include "chromeos/components/multidevice/remote_device_cache.h"
 #include "chromeos/components/multidevice/remote_device_ref.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/secure_channel/background_eid_generator.h"
 #include "chromeos/services/secure_channel/ble_advertisement_generator.h"
 #include "chromeos/services/secure_channel/ble_constants.h"
diff --git a/components/arc/DEPS b/components/arc/DEPS
index 0ffc244..9cf3fa93 100644
--- a/components/arc/DEPS
+++ b/components/arc/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+ash/constants",
   "+ash/public/cpp",
   "+chromeos/components/sensors",
   "+chromeos/constants",
diff --git a/components/arc/ime/arc_ime_service.cc b/components/arc/ime/arc_ime_service.cc
index 843bf71..608cb01 100644
--- a/components/arc/ime/arc_ime_service.cc
+++ b/components/arc/ime/arc_ime_service.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/keyboard/ui/keyboard_ui_controller.h"
 #include "ash/public/cpp/app_types.h"
 #include "base/feature_list.h"
@@ -14,7 +15,6 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/ime/arc_ime_bridge_impl.h"
diff --git a/components/arc/session/arc_vm_client_adapter.cc b/components/arc/session/arc_vm_client_adapter.cc
index 43ace00..9648d27 100644
--- a/components/arc/session/arc_vm_client_adapter.cc
+++ b/components/arc/session/arc_vm_client_adapter.cc
@@ -315,7 +315,6 @@
 
   // Add /run/imageloader/.../android_demo_apps.squash as /dev/block/vdc if
   // needed.
-  // TODO(b/144542975): Do this on upgrade instead.
   if (!demo_session_apps_path.empty()) {
     disk_image = request.add_disks();
     disk_image->set_path(demo_session_apps_path.value());
diff --git a/components/breadcrumbs/OWNERS b/components/breadcrumbs/OWNERS
new file mode 100644
index 0000000..a8a5194
--- /dev/null
+++ b/components/breadcrumbs/OWNERS
@@ -0,0 +1,2 @@
+jessemckenna@google.com
+michaeldo@chromium.org
diff --git a/components/breadcrumbs/core/BUILD.gn b/components/breadcrumbs/core/BUILD.gn
new file mode 100644
index 0000000..e094512
--- /dev/null
+++ b/components/breadcrumbs/core/BUILD.gn
@@ -0,0 +1,7 @@
+# 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.
+
+source_set("core") {
+  sources = [ "crash_reporter_breadcrumb_constants.h" ]
+}
diff --git a/components/breadcrumbs/core/crash_reporter_breadcrumb_constants.h b/components/breadcrumbs/core/crash_reporter_breadcrumb_constants.h
new file mode 100644
index 0000000..b68204e
--- /dev/null
+++ b/components/breadcrumbs/core/crash_reporter_breadcrumb_constants.h
@@ -0,0 +1,18 @@
+// 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 COMPONENTS_BREADCRUMBS_CORE_CRASH_REPORTER_BREADCRUMB_CONSTANTS_H_
+#define COMPONENTS_BREADCRUMBS_CORE_CRASH_REPORTER_BREADCRUMB_CONSTANTS_H_
+
+namespace breadcrumbs {
+
+// The maximum string length for breadcrumbs data. The breadcrumbs size cannot
+// be larger than the maximum length of a single Breakpad product data value
+// (currently 2550 bytes). This value should be large enough to include enough
+//  events so that they are useful for diagnosing crashes.
+constexpr unsigned long kMaxDataLength = 1530;
+
+}  // namespace breadcrumbs
+
+#endif  // COMPONENTS_BREADCRUMBS_CORE_CRASH_REPORTER_BREADCRUMB_CONSTANTS_H_
diff --git a/components/browser_sync/DEPS b/components/browser_sync/DEPS
index 0ac7b8ae..f0aa56d8 100644
--- a/components/browser_sync/DEPS
+++ b/components/browser_sync/DEPS
@@ -1,5 +1,5 @@
 include_rules = [
-  "+chromeos/constants",
+  "+ash/constants",
   "+components/autofill/core",
   "+components/bookmarks/browser",
   "+components/bookmarks/managed",
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index 80bd3d32..3aac6dc 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -55,7 +55,7 @@
 #include "components/sync_user_events/user_event_model_type_controller.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif
 
 using syncer::DataTypeController;
diff --git a/components/components_strings.grd b/components/components_strings.grd
index d9e22ae8..d0fca4d 100644
--- a/components/components_strings.grd
+++ b/components/components_strings.grd
@@ -325,6 +325,9 @@
       <if expr="not is_android and not is_ios">
         <part file="management_strings.grdp" />
       </if>
+      <if expr="not is_android and not is_ios">
+        <part file="memories_strings.grdp" />
+      </if>
       <if expr="is_android">
         <part file="android_system_error_page_strings.grdp" />
       </if>
diff --git a/components/content_capture/android/BUILD.gn b/components/content_capture/android/BUILD.gn
index e5c5680..7e8e020 100644
--- a/components/content_capture/android/BUILD.gn
+++ b/components/content_capture/android/BUILD.gn
@@ -48,6 +48,7 @@
     "java/src/org/chromium/components/content_capture/PlatformSession.java",
     "java/src/org/chromium/components/content_capture/ProcessContentCaptureDataTask.java",
     "java/src/org/chromium/components/content_capture/SessionRemovedTask.java",
+    "java/src/org/chromium/components/content_capture/TitleUpdateTask.java",
   ]
 }
 
diff --git a/components/content_capture/android/content_capture_receiver_manager_android.cc b/components/content_capture/android/content_capture_receiver_manager_android.cc
index 586d566..5eaf4899 100644
--- a/components/content_capture/android/content_capture_receiver_manager_android.cc
+++ b/components/content_capture/android/content_capture_receiver_manager_android.cc
@@ -66,8 +66,10 @@
     JNIEnv* env,
     const ContentCaptureFrame& data) {
   ScopedJavaLocalRef<jstring> jurl = ConvertUTF16ToJavaString(env, data.url);
-  ScopedJavaLocalRef<jstring> jtitle =
-      ConvertUTF16ToJavaString(env, data.title);
+  ScopedJavaLocalRef<jstring> jtitle;
+  if (!data.title.empty())
+    jtitle = ConvertUTF16ToJavaString(env, data.title);
+
   ScopedJavaLocalRef<jobject> jdata =
       Java_ContentCaptureFrame_createContentCaptureFrame(
           env, data.id, jurl, data.bounds.x(), data.bounds.y(),
@@ -86,7 +88,7 @@
   ScopedJavaLocalRef<jclass> object_clazz =
       base::android::GetClass(env, "java/lang/Object");
   jobjectArray joa =
-      env->NewObjectArray(session.size(), object_clazz.obj(), NULL);
+      env->NewObjectArray(session.size(), object_clazz.obj(), nullptr);
   jni_generator::CheckException(env);
 
   for (size_t i = 0; i < session.size(); ++i) {
@@ -166,6 +168,17 @@
       env, java_ref_, ToJavaArrayOfContentCaptureFrame(env, session));
 }
 
+void ContentCaptureReceiverManagerAndroid::DidUpdateTitle(
+    const ContentCaptureFrame& main_frame) {
+  JNIEnv* env = AttachCurrentThread();
+  DCHECK(java_ref_.obj());
+  ScopedJavaLocalRef<jobject> jdata =
+      ToJavaObjectOfContentCaptureFrame(env, main_frame);
+  if (jdata.is_null())
+    return;
+  Java_ContentCaptureReceiverManager_didUpdateTitle(env, java_ref_, jdata);
+}
+
 bool ContentCaptureReceiverManagerAndroid::ShouldCapture(const GURL& url) {
   // Capture all urls for experiment, the url will be checked
   // before the content is sent to the consumers.
diff --git a/components/content_capture/android/content_capture_receiver_manager_android.h b/components/content_capture/android/content_capture_receiver_manager_android.h
index ca7a3fb..f8b5618 100644
--- a/components/content_capture/android/content_capture_receiver_manager_android.h
+++ b/components/content_capture/android/content_capture_receiver_manager_android.h
@@ -29,6 +29,7 @@
   void DidRemoveContent(const ContentCaptureSession& session,
                         const std::vector<int64_t>& data) override;
   void DidRemoveSession(const ContentCaptureSession& session) override;
+  void DidUpdateTitle(const ContentCaptureFrame& main_frame) override;
 
   base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
 
diff --git a/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureConsumer.java b/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureConsumer.java
index 0abd8004..ab4516673 100644
--- a/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureConsumer.java
+++ b/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureConsumer.java
@@ -29,8 +29,8 @@
      * @param parentFrame is the parent of the frame from that the content captured.
      * @param contentCaptureFrame is the captured content tree, its root is the frame.
      */
-    public void onContentUpdated(
-            FrameSession parentFrame, ContentCaptureFrame contentCaptureFrame) {}
+    public abstract void onContentUpdated(
+            FrameSession parentFrame, ContentCaptureFrame contentCaptureFrame);
 
     /**
      * Invoked when the session is removed
@@ -45,6 +45,12 @@
      */
     public abstract void onContentRemoved(FrameSession session, long[] removedIds);
 
+    /**
+     * Invoked when the title is updated.
+     * @param mainFrame the frame whose title is updated.
+     */
+    public abstract void onTitleUpdated(ContentCaptureFrame mainFrame);
+
     public void onWebContentsChanged(WebContents current) {
         if (!ContentCaptureFeatures.isEnabled()) return;
         // Not reset previous mManager's ContentCaptureConsumer, because it will be used to notify
diff --git a/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureConsumerImpl.java b/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureConsumerImpl.java
index 0601670..6fb604837 100644
--- a/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureConsumerImpl.java
+++ b/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureConsumerImpl.java
@@ -86,6 +86,13 @@
     }
 
     @Override
+    public void onTitleUpdated(ContentCaptureFrame contentCaptureFrame) {
+        if (mPlatformSession == null) return;
+        new TitleUpdateTask(contentCaptureFrame, mPlatformSession)
+                .executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
+    }
+
+    @Override
     public void onContentRemoved(FrameSession frame, long[] removedIds) {
         if (frame.isEmpty() || mPlatformSession == null) return;
         new ContentRemovedTask(frame, removedIds, mPlatformSession)
diff --git a/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureData.java b/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureData.java
index d281e47..61e42c2 100644
--- a/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureData.java
+++ b/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureData.java
@@ -41,7 +41,6 @@
         StringBuilder sb = new StringBuilder(super.toString());
         sb.append(" value:");
         sb.append(mValue);
-        sb.append('\n');
         return sb.toString();
     }
 
diff --git a/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureDataBase.java b/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureDataBase.java
index ad55f8589..3634c62 100644
--- a/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureDataBase.java
+++ b/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureDataBase.java
@@ -51,13 +51,12 @@
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("id:");
+        sb.append(" id:");
         sb.append(getId());
         sb.append(" bounds:");
         sb.append(getBounds());
-        sb.append('\n');
         if (hasChildren()) {
-            sb.append("children:");
+            sb.append(" children:");
             sb.append(getChildren().size());
             for (ContentCaptureDataBase child : getChildren()) {
                 sb.append(child.toString());
diff --git a/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureFrame.java b/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureFrame.java
index d51d2eb..b26e08d 100644
--- a/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureFrame.java
+++ b/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureFrame.java
@@ -46,12 +46,11 @@
         sb.append(getUrl());
         sb.append(" Title:");
         sb.append(getTitle());
-        sb.append('\n');
         return sb.toString();
     }
 
     @Override
     public String getText() {
-        return getUrl();
+        return getTitle();
     }
 }
diff --git a/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureReceiverManager.java b/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureReceiverManager.java
index fc1ca3b..fc5ec1e0 100644
--- a/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureReceiverManager.java
+++ b/components/content_capture/android/java/src/org/chromium/components/content_capture/ContentCaptureReceiverManager.java
@@ -85,6 +85,17 @@
         if (sDump.booleanValue()) Log.i(TAG, "Removed Session: %s", frameSession.get(0));
     }
 
+    @CalledByNative
+    private void didUpdateTitle(ContentCaptureFrame mainFrame) {
+        String[] urls = buildUrls(null, mainFrame);
+        for (ContentCaptureConsumer consumer : mContentCaptureConsumers) {
+            if (consumer.shouldCapture(urls)) {
+                consumer.onTitleUpdated(mainFrame);
+            }
+        }
+        if (sDump.booleanValue()) Log.i(TAG, "Updated Title: %s", mainFrame);
+    }
+
     private FrameSession toFrameSession(Object[] session) {
         FrameSession frameSession = new FrameSession(session.length);
         for (Object s : session) frameSession.add((ContentCaptureFrame) s);
diff --git a/components/content_capture/android/java/src/org/chromium/components/content_capture/ExperimentContentCaptureConsumer.java b/components/content_capture/android/java/src/org/chromium/components/content_capture/ExperimentContentCaptureConsumer.java
index cb7989b3..eba0395 100644
--- a/components/content_capture/android/java/src/org/chromium/components/content_capture/ExperimentContentCaptureConsumer.java
+++ b/components/content_capture/android/java/src/org/chromium/components/content_capture/ExperimentContentCaptureConsumer.java
@@ -47,4 +47,9 @@
             FrameSession parentFrame, ContentCaptureFrame contentCaptureFrame) {
         if (sDump) Log.d(TAG, "onContentUpdated");
     }
+
+    @Override
+    public void onTitleUpdated(ContentCaptureFrame contentCaptureFrame) {
+        if (sDump) Log.d(TAG, "onTitleUpdated");
+    }
 }
diff --git a/components/content_capture/android/java/src/org/chromium/components/content_capture/NotificationTask.java b/components/content_capture/android/java/src/org/chromium/components/content_capture/NotificationTask.java
index 1ea1baa..f51c5993 100644
--- a/components/content_capture/android/java/src/org/chromium/components/content_capture/NotificationTask.java
+++ b/components/content_capture/android/java/src/org/chromium/components/content_capture/NotificationTask.java
@@ -78,7 +78,7 @@
                 parentPlatformSessionData.contentCaptureSession,
                 parentPlatformSessionData.autofillId, data.getId());
 
-        if (!data.hasChildren()) viewStructure.setText(data.getText());
+        viewStructure.setText(data.getText());
         Rect rect = data.getBounds();
         // Always set scroll as (0, 0).
         viewStructure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height());
diff --git a/components/content_capture/android/java/src/org/chromium/components/content_capture/TitleUpdateTask.java b/components/content_capture/android/java/src/org/chromium/components/content_capture/TitleUpdateTask.java
new file mode 100644
index 0000000..62b6bab
--- /dev/null
+++ b/components/content_capture/android/java/src/org/chromium/components/content_capture/TitleUpdateTask.java
@@ -0,0 +1,37 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.content_capture;
+
+import android.view.autofill.AutofillId;
+
+import org.chromium.components.content_capture.PlatformSession.PlatformSessionData;
+
+/**
+ * The task to update the title change to plateform
+ */
+public class TitleUpdateTask extends NotificationTask {
+    private ContentCaptureFrame mMainFrame;
+    public TitleUpdateTask(ContentCaptureFrame mainFrame, PlatformSession platformSession) {
+        super(null, platformSession);
+        mMainFrame = mainFrame;
+    }
+
+    @Override
+    protected void runTask() {
+        updateTitle();
+    }
+
+    private void updateTitle() {
+        log("TitleUpdateTask.updateTitle");
+        // To notify the text change, the parent ContentCaptureSession and this view's autofill id
+        // are needed.
+        PlatformSessionData parentPlatformSessionData = buildCurrentSession();
+        AutofillId autofillId = PlatformAPIWrapper.getInstance().newAutofillId(
+                parentPlatformSessionData.contentCaptureSession,
+                mPlatformSession.getRootPlatformSessionData().autofillId, mMainFrame.getId());
+        PlatformAPIWrapper.getInstance().notifyViewTextChanged(
+                parentPlatformSessionData.contentCaptureSession, autofillId, mMainFrame.getText());
+    }
+}
diff --git a/components/content_capture/android/junit/src/org/chromium/components/content_capture/PlatformAPIWrapperTest.java b/components/content_capture/android/junit/src/org/chromium/components/content_capture/PlatformAPIWrapperTest.java
index 17eb099..6203847 100644
--- a/components/content_capture/android/junit/src/org/chromium/components/content_capture/PlatformAPIWrapperTest.java
+++ b/components/content_capture/android/junit/src/org/chromium/components/content_capture/PlatformAPIWrapperTest.java
@@ -223,10 +223,11 @@
 
     private static final String MAIN_URL = "http://main.domain.com";
     private static final String MAIN_TITLE = "MAIN TITLE";
+    private static final String UPDATED_MAIN_TITLE = "MAIN TITLE UPDATE";
     private static final long MAIN_ID = 4;
     private static final Rect MAIN_FRAME_RECT = new Rect(0, 0, 200, 200);
     private static final String CHILD_URL = "http://test.domain.com";
-    private static final String CHILD_TITLE = "CHILD TITLE";
+    private static final String CHILD_TITLE = null;
     private static final long CHILD_FRAME_ID = 1;
     private static final Rect CHILD_FRAME_RECT = new Rect(0, 0, 100, 100);
     private static final long CHILD1_ID = 2;
@@ -336,6 +337,13 @@
         return new SessionRemovedTask(createFrameSessionForRemoveTask(), mRootPlatformSession);
     }
 
+    private TitleUpdateTask createTitleUpdateTask() {
+        ContentCaptureFrame mainFrame = ContentCaptureFrame.createContentCaptureFrame(MAIN_ID,
+                MAIN_URL, MAIN_FRAME_RECT.left, MAIN_FRAME_RECT.top, MAIN_FRAME_RECT.width(),
+                MAIN_FRAME_RECT.height(), UPDATED_MAIN_TITLE);
+        return new TitleUpdateTask(mainFrame, mRootPlatformSession);
+    }
+
     private void runContentCapturedTask() throws Exception {
         runTaskAndVerifyCallback(createContentCapturedTask(),
                 toIntArray(PlatformAPIWrapperTestHelper.CREATE_CONTENT_CAPTURE_SESSION,
@@ -369,6 +377,7 @@
         };
         return e;
     }
+
     @Test
     public void testTypicalLifecycle() throws Throwable {
         runContentCapturedTask();
@@ -386,7 +395,7 @@
         inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
                 .notifyViewAppeared(mMockedRootContentCaptureSession,
                         mPlatformAPIWrapperTestHelper.mCreatedViewStructures.get(0));
-        verifyVirtualViewStructure(MAIN_URL, MAIN_FRAME_RECT, 0);
+        verifyVirtualViewStructure(MAIN_TITLE, MAIN_FRAME_RECT, 0);
 
         // Verifies the child frame.
         inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
@@ -457,6 +466,15 @@
         inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
                 .destroyContentCaptureSession(
                         mPlatformAPIWrapperTestHelper.mCreatedContentCaptureSessions.get(1));
+
+        // Updates the title.
+        runTaskAndVerifyCallback(createTitleUpdateTask(),
+                toIntArray(PlatformAPIWrapperTestHelper.NEW_AUTOFILL_ID,
+                        PlatformAPIWrapperTestHelper.NOTIFY_VIEW_TEXT_CHANGED));
+        inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+                .notifyViewTextChanged(mMockedRootContentCaptureSession,
+                        mPlatformAPIWrapperTestHelper.mCreatedAutofilIds.get(3),
+                        UPDATED_MAIN_TITLE);
     }
 
     // The below testFooException() tests mock the specific method to throw exception, then verify
diff --git a/components/content_capture/browser/content_capture_receiver.cc b/components/content_capture/browser/content_capture_receiver.cc
index ff489be..cc972d5 100644
--- a/components/content_capture/browser/content_capture_receiver.cc
+++ b/components/content_capture/browser/content_capture_receiver.cc
@@ -7,7 +7,11 @@
 #include <utility>
 
 #include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "base/time/time.h"
 #include "components/content_capture/browser/content_capture_receiver_manager.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
@@ -45,6 +49,7 @@
 
 void ContentCaptureReceiver::DidCaptureContent(const ContentCaptureData& data,
                                                bool first_data) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   auto* manager = GetContentCaptureReceiverManager(rfh_);
   if (!manager)
     return;
@@ -65,30 +70,29 @@
     frame_content_capture_data_.bounds = data.bounds;
     has_session_ = true;
   }
-  // We can't avoid copy the data here, because id need to be overridden.
-  ContentCaptureFrame content(data);
-  content.id = id_;
+  // We can't avoid copy the data here because frame needs to be replaced.
   // Always have frame URL attached, since the ContentCaptureConsumer will
   // be reset once activity is resumed, URL is needed to rebuild session.
-  if (!first_data)
-    content.url = frame_content_capture_data_.url;
-  manager->DidCaptureContent(this, content);
+  ContentCaptureFrame frame(frame_content_capture_data_);
+  frame.children = data.children;
+  manager->DidCaptureContent(this, frame);
 }
 
 void ContentCaptureReceiver::DidUpdateContent(const ContentCaptureData& data) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   auto* manager = GetContentCaptureReceiverManager(rfh_);
   if (!manager)
     return;
 
-  // We can't avoid copy the data here, because id need to be overridden.
-  ContentCaptureFrame content(data);
-  content.id = id_;
-  content.url = frame_content_capture_data_.url;
-  manager->DidUpdateContent(this, content);
+  // We can't avoid copy the data here because frame needs to be replaced.
+  ContentCaptureFrame frame(frame_content_capture_data_);
+  frame.children = data.children;
+  manager->DidUpdateContent(this, frame);
 }
 
 void ContentCaptureReceiver::DidRemoveContent(
     const std::vector<int64_t>& data) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   auto* manager = GetContentCaptureReceiverManager(rfh_);
   if (!manager)
     return;
@@ -96,6 +100,7 @@
 }
 
 void ContentCaptureReceiver::StartCapture() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (content_capture_enabled_)
     return;
 
@@ -106,6 +111,7 @@
 }
 
 void ContentCaptureReceiver::StopCapture() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (!content_capture_enabled_)
     return;
 
@@ -116,6 +122,7 @@
 }
 
 void ContentCaptureReceiver::RemoveSession() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (!has_session_)
     return;
 
@@ -128,6 +135,50 @@
     // used by GetFrameContentCaptureDataLastSeen(), has_session_ is used to
     // check if new session shall be created as needed.
   }
+
+  // Cancel the task if any.
+  if (notify_title_update_callback_) {
+    notify_title_update_callback_->Cancel();
+    notify_title_update_callback_ = nullptr;
+    title_update_task_runner_ = nullptr;
+  }
+  exponential_delay_ = 1;
+}
+
+void ContentCaptureReceiver::SetTitle(const base::string16& title) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  frame_content_capture_data_.title = title;
+  if (!has_session_)
+    return;
+
+  // Returns if there is the pending task.
+  if (notify_title_update_callback_)
+    return;
+
+  notify_title_update_callback_ =
+      std::make_unique<base::CancelableOnceClosure>(base::BindOnce(
+          &ContentCaptureReceiver::NotifyTitleUpdate, base::Unretained(this)));
+
+  if (!title_update_task_runner_)
+    title_update_task_runner_ = content::GetUIThreadTaskRunner({});
+
+  title_update_task_runner_->PostDelayedTask(
+      FROM_HERE, notify_title_update_callback_->callback(),
+      base::TimeDelta::FromSeconds(exponential_delay_));
+
+  exponential_delay_ =
+      exponential_delay_ < 256 ? exponential_delay_ * 2 : exponential_delay_;
+}
+
+void ContentCaptureReceiver::NotifyTitleUpdate() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (auto* manager = GetContentCaptureReceiverManager(rfh_))
+    manager->DidUpdateTitle(this);
+
+  // Reset the task after running.
+  notify_title_update_callback_ = nullptr;
+  title_update_task_runner_ = nullptr;
 }
 
 const mojo::AssociatedRemote<mojom::ContentCaptureSender>&
@@ -140,6 +191,7 @@
 }
 
 const ContentCaptureFrame& ContentCaptureReceiver::GetContentCaptureFrame() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   base::string16 url = base::UTF8ToUTF16(rfh_->GetLastCommittedURL().spec());
   if (url == frame_content_capture_data_.url && has_session_)
     return frame_content_capture_data_;
diff --git a/components/content_capture/browser/content_capture_receiver.h b/components/content_capture/browser/content_capture_receiver.h
index 8e65709c..50c8819 100644
--- a/components/content_capture/browser/content_capture_receiver.h
+++ b/components/content_capture/browser/content_capture_receiver.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "base/cancelable_callback.h"
 #include "base/gtest_prod_util.h"
 #include "components/content_capture/browser/content_capture_frame.h"
 #include "components/content_capture/common/content_capture.mojom.h"
@@ -53,8 +54,13 @@
 
   void RemoveSession();
 
+  void SetTitle(const base::string16& title);
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ContentCaptureReceiverTest, RenderFrameHostGone);
+  FRIEND_TEST_ALL_PREFIXES(ContentCaptureReceiverTest, TitleUpdateTaskDelay);
+
+  void NotifyTitleUpdate();
 
   const mojo::AssociatedRemote<mojom::ContentCaptureSender>&
   GetContentCaptureSender();
@@ -77,6 +83,16 @@
   // removed; the former is caused by either the content captured or the
   // |frame_content_capture_data_| required by child frame.
   bool has_session_ = false;
+
+  // The TaskRunner for |notify_title_update_callback_| task. It is also used by
+  // test to replace with TestMockTimeTaskRunner.
+  scoped_refptr<base::SingleThreadTaskRunner> title_update_task_runner_;
+  // Hold the task for cancelling on session end.
+  std::unique_ptr<base::CancelableOnceClosure> notify_title_update_callback_;
+  // The delay of |notify_title_update_callback_|, is increased exponentially to
+  // prevent running frequently.
+  unsigned exponential_delay_ = 1;
+
   mojo::AssociatedRemote<mojom::ContentCaptureSender> content_capture_sender_;
   DISALLOW_COPY_AND_ASSIGN(ContentCaptureReceiver);
 };
diff --git a/components/content_capture/browser/content_capture_receiver_manager.cc b/components/content_capture/browser/content_capture_receiver_manager.cc
index d4a9ba0..e62736d 100644
--- a/components/content_capture/browser/content_capture_receiver_manager.cc
+++ b/components/content_capture/browser/content_capture_receiver_manager.cc
@@ -8,6 +8,7 @@
 
 #include "components/content_capture/browser/content_capture_receiver.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
@@ -108,6 +109,17 @@
   }
 }
 
+void ContentCaptureReceiverManager::TitleWasSet(
+    content::NavigationEntry* entry) {
+  // Set the title to the mainframe.
+  if (auto* receiver =
+          ContentCaptureReceiverForFrame(web_contents()->GetMainFrame())) {
+    // To match what the user sees, intentionally get the title from WebContents
+    // instead of NavigationEntry, though they might be same.
+    receiver->SetTitle(web_contents()->GetTitle());
+  }
+}
+
 void ContentCaptureReceiverManager::DidCaptureContent(
     ContentCaptureReceiver* content_capture_receiver,
     const ContentCaptureFrame& data) {
@@ -155,6 +167,17 @@
   DidRemoveSession(session);
 }
 
+void ContentCaptureReceiverManager::DidUpdateTitle(
+    ContentCaptureReceiver* content_capture_receiver) {
+  ContentCaptureSession session;
+  BuildContentCaptureSession(content_capture_receiver,
+                             /*ancestor_only=*/false, &session);
+
+  // Shall only update mainframe's title.
+  DCHECK(session.size() == 1);
+  DidUpdateTitle(*session.begin());
+}
+
 void ContentCaptureReceiverManager::BuildContentCaptureSession(
     ContentCaptureReceiver* content_capture_receiver,
     bool ancestor_only,
diff --git a/components/content_capture/browser/content_capture_receiver_manager.h b/components/content_capture/browser/content_capture_receiver_manager.h
index 001961a..d4e3db9f 100644
--- a/components/content_capture/browser/content_capture_receiver_manager.h
+++ b/components/content_capture/browser/content_capture_receiver_manager.h
@@ -21,6 +21,7 @@
 namespace content_capture {
 
 class ContentCaptureReceiver;
+class NavigationEntry;
 
 // This class has an instance per WebContents, it is the base class of
 // ContentCaptureReceiverManager implementation which shall overrides the pure
@@ -50,12 +51,14 @@
   void DidRemoveContent(ContentCaptureReceiver* content_capture_receiver,
                         const std::vector<int64_t>& data);
   void DidRemoveSession(ContentCaptureReceiver* content_capture_receiver);
+  void DidUpdateTitle(ContentCaptureReceiver* content_capture_receiver);
 
   // content::WebContentsObserver:
   void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
   void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
   void ReadyToCommitNavigation(
       content::NavigationHandle* navigation_handle) override;
+  void TitleWasSet(content::NavigationEntry* entry) override;
 
   size_t GetFrameMapSizeForTesting() const { return frame_map_.size(); }
 
@@ -75,6 +78,8 @@
                                 const std::vector<int64_t>& ids) = 0;
   // Invoked when the given |session| was removed.
   virtual void DidRemoveSession(const ContentCaptureSession& session) = 0;
+  // Invoked when the given |main_frame|'s title updated.
+  virtual void DidUpdateTitle(const ContentCaptureFrame& main_frame) = 0;
 
   virtual bool ShouldCapture(const GURL& url) = 0;
 
diff --git a/components/content_capture/browser/content_capture_receiver_test.cc b/components/content_capture/browser/content_capture_receiver_test.cc
index b11a77d..eb54cf3 100644
--- a/components/content_capture/browser/content_capture_receiver_test.cc
+++ b/components/content_capture/browser/content_capture_receiver_test.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/test_mock_time_task_runner.h"
 #include "build/build_config.h"
 #include "components/content_capture/browser/content_capture_receiver_manager.h"
 #include "content/public/browser/content_browser_client.h"
@@ -112,6 +113,10 @@
     removed_sessions_.push_back(data);
   }
 
+  void DidUpdateTitle(const ContentCaptureFrame& main_frame) override {
+    updated_title_ = main_frame.title;
+  }
+
   bool ShouldCapture(const GURL& url) override { return false; }
 
   const ContentCaptureSession& parent_session() const {
@@ -133,6 +138,7 @@
   }
 
   const std::vector<int64_t>& removed_ids() const { return removed_ids_; }
+  const base::string16& updated_title() const { return updated_title_; }
 
   void Reset() { removed_sessions_.clear(); }
 
@@ -150,6 +156,7 @@
   std::vector<int64_t> removed_ids_;
   std::vector<ContentCaptureSession> removed_sessions_;
   SessionRemovedTestHelper* session_removed_test_helper_;
+  base::string16 updated_title_;
 };
 
 }  // namespace
@@ -528,6 +535,57 @@
   DidRemoveContent(expected_removed_ids());
 }
 
+TEST_P(ContentCaptureReceiverTest, TitleUpdateTaskDelay) {
+  auto* receiver =
+      content_capture_receiver_manager_helper()->GetContentCaptureReceiver(
+          web_contents()->GetMainFrame());
+  auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+  // Uses TestMockTimeTaskRunner to check the task state.
+  receiver->title_update_task_runner_ = task_runner;
+
+  receiver->SetTitle(base::ASCIIToUTF16("title 1"));
+  // No task scheduled because no content has been captured.
+  EXPECT_FALSE(receiver->notify_title_update_callback_);
+  EXPECT_FALSE(task_runner->HasPendingTask());
+
+  // Capture content, then update the title.
+  DidCaptureContent(test_data(), /*first_data=*/true);
+  base::string16 title2 = base::ASCIIToUTF16("title 2");
+  receiver->SetTitle(title2);
+  // A task should be scheduled.
+  EXPECT_TRUE(receiver->notify_title_update_callback_);
+  EXPECT_TRUE(task_runner->HasPendingTask());
+  EXPECT_EQ(2u, receiver->exponential_delay_);
+  // Run the pending task.
+  task_runner->FastForwardBy(
+      base::TimeDelta::FromSeconds(receiver->exponential_delay_ / 2));
+  task_runner->RunUntilIdle();
+  // Verify the title is updated and the task is reset.
+  EXPECT_EQ(title2, content_capture_receiver_manager_helper()->updated_title());
+  EXPECT_FALSE(receiver->notify_title_update_callback_);
+  EXPECT_FALSE(task_runner->HasPendingTask());
+
+  // Set the task_runner again since it is reset after task runs.
+  receiver->title_update_task_runner_ = task_runner;
+
+  // Change title again and verify the result.
+  receiver->SetTitle(base::ASCIIToUTF16("title 3"));
+  EXPECT_TRUE(receiver->notify_title_update_callback_);
+  EXPECT_TRUE(task_runner->HasPendingTask());
+  EXPECT_EQ(4u, receiver->exponential_delay_);
+
+  // Remove the session to verify the pending task cancelled.
+  receiver->RemoveSession();
+  EXPECT_FALSE(receiver->notify_title_update_callback_);
+  // The cancelled task isn't removed from the TaskRunner, prune it.
+  task_runner->TakePendingTasks();
+  EXPECT_FALSE(task_runner->HasPendingTask());
+  // The delay time is reset after session is removed.
+  EXPECT_EQ(1u, receiver->exponential_delay_);
+  // Verify the latest task isn't run.
+  EXPECT_EQ(title2, content_capture_receiver_manager_helper()->updated_title());
+}
+
 // TODO(https://crbug.com/1010416): Fix flakes on win10_chromium_x64_rel_ng and
 // re-enable this test.
 #if defined(OS_WIN)
diff --git a/components/data_reduction_proxy/DEPS b/components/data_reduction_proxy/DEPS
index 24bcbd0d..dd5b47d 100644
--- a/components/data_reduction_proxy/DEPS
+++ b/components/data_reduction_proxy/DEPS
@@ -3,11 +3,10 @@
   "+components/pref_registry",
   "+components/prefs",
   "+components/previews/core",
-  "+components/variations",
   "+crypto",
   "+google_apis",
-  "+mojo/public/cpp",
   "+net",
+  "+mojo/public/cpp",  
   "+services/network/public/cpp",
   "+services/network/public/mojom",
 
diff --git a/components/data_reduction_proxy/core/browser/BUILD.gn b/components/data_reduction_proxy/core/browser/BUILD.gn
index 95fe82a..82487902 100644
--- a/components/data_reduction_proxy/core/browser/BUILD.gn
+++ b/components/data_reduction_proxy/core/browser/BUILD.gn
@@ -9,8 +9,6 @@
 browser_sources = [
   "data_reduction_proxy_compression_stats.cc",
   "data_reduction_proxy_compression_stats.h",
-  "data_reduction_proxy_config_service_client.cc",
-  "data_reduction_proxy_config_service_client.h",
   "data_reduction_proxy_data.cc",
   "data_reduction_proxy_data.h",
   "data_reduction_proxy_metrics.h",
@@ -45,12 +43,9 @@
       "//components/pref_registry",
       "//components/prefs",
       "//components/previews/core:core",
-      "//components/variations",
-      "//components/variations/net",
       "//crypto",
       "//google_apis",
       "//net:net",
-      "//services/network/public/cpp",
       "//url:url",
     ]
   }
@@ -78,8 +73,6 @@
     "//components/pref_registry",
     "//components/prefs",
     "//components/previews/core:core",
-    "//components/variations",
-    "//components/variations/net",
     "//crypto",
     "//google_apis",
     "//net",
@@ -98,8 +91,6 @@
 static_library("test_support") {
   testonly = true
   sources = [
-    "data_reduction_proxy_config_service_client_test_utils.cc",
-    "data_reduction_proxy_config_service_client_test_utils.h",
     "data_reduction_proxy_settings_test_utils.cc",
     "data_reduction_proxy_settings_test_utils.h",
     "data_reduction_proxy_test_utils.cc",
@@ -146,13 +137,10 @@
   testonly = true
   sources = [
     "data_reduction_proxy_compression_stats_unittest.cc",
-    "data_reduction_proxy_config_service_client_unittest.cc",
     "data_reduction_proxy_data_unittest.cc",
     "data_reduction_proxy_prefs_unittest.cc",
     "data_reduction_proxy_request_options_unittest.cc",
-    "data_reduction_proxy_service_unittest.cc",
     "data_reduction_proxy_settings_unittest.cc",
-    "data_reduction_proxy_util_unittest.cc",
     "data_usage_store_unittest.cc",
   ]
 
@@ -170,10 +158,9 @@
     "//components/data_use_measurement/core:ascriber",
     "//components/prefs:test_support",
     "//components/previews/core",
-    "//components/variations",
     "//net:test_support",
-    "//services/network:network_service",
     "//services/network:test_support",
+    "//services/network/public/cpp",
     "//testing/gmock",
     "//testing/gtest",
   ]
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
deleted file mode 100644
index 8ef138c..0000000
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
+++ /dev/null
@@ -1,558 +0,0 @@
-// 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.
-
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h"
-
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/base64.h"
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/command_line.h"
-#include "base/feature_list.h"
-#include "base/json/json_writer.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/system/sys_info.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/data_reduction_proxy/proto/client_config.pb.h"
-#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "components/previews/core/previews_experiments.h"
-#include "components/variations/net/variations_http_headers.h"
-#include "net/base/host_port_pair.h"
-#include "net/base/load_flags.h"
-#include "net/base/load_timing_info.h"
-#include "net/base/net_errors.h"
-#include "net/base/proxy_server.h"
-#include "net/http/http_network_session.h"
-#include "net/http/http_request_headers.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_status_code.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "services/network/public/cpp/features.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/public/cpp/simple_url_loader.h"
-
-#if defined(OS_ANDROID)
-#include "net/android/network_library.h"
-#endif
-
-namespace data_reduction_proxy {
-
-namespace {
-
-// Key of the UMA DataReductionProxy.ConfigService.FetchResponseCode histogram.
-const char kUMAConfigServiceFetchResponseCode[] =
-    "DataReductionProxy.ConfigService.FetchResponseCode";
-
-// Key of the UMA
-// DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess histogram.
-const char kUMAConfigServiceFetchFailedAttemptsBeforeSuccess[] =
-    "DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess";
-
-// Key of the UMA DataReductionProxy.ConfigService.FetchLatency histogram.
-const char kUMAConfigServiceFetchLatency[] =
-    "DataReductionProxy.ConfigService.FetchLatency";
-
-// Key of the UMA DataReductionProxy.ConfigService.AuthExpired histogram.
-const char kUMAConfigServiceAuthExpired[] =
-    "DataReductionProxy.ConfigService.AuthExpired";
-
-#if defined(OS_ANDROID)
-// Maximum duration  to wait before fetching the config, while the application
-// is in background.
-const uint32_t kMaxBackgroundFetchIntervalSeconds = 6 * 60 * 60;  // 6 hours.
-#endif
-
-// This is the default backoff policy used to communicate with the Data
-// Reduction Proxy configuration service. The policy gets overwritten based on
-// kDataReductionProxyAggressiveConfigFetch.
-const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
-    0,                // num_errors_to_ignore
-    10 * 1000,        // initial_delay_ms
-    3,                // multiply_factor
-    0.25,             // jitter_factor,
-    128 * 60 * 1000,  // maximum_backoff_ms
-    -1,               // entry_lifetime_ms
-    true,             // always_use_initial_delay
-};
-
-bool AllowInsecurePrefetchProxy() {
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      "allow-insecure-prefetch-proxy-for-testing");
-}
-
-std::vector<GURL> GetPrefetchProxyHosts(
-    const data_reduction_proxy::PrefetchProxyConfig& prefetch_config) {
-  std::vector<GURL> hosts;
-
-  // Check for a command line override and maybe early return.
-  std::string cmd_line_override =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-          "prefetch-proxy-override-proxy-hosts");
-  if (!cmd_line_override.empty()) {
-    std::vector<std::string> split_cmd_line_override =
-        base::SplitString(cmd_line_override, ",", base::TRIM_WHITESPACE,
-                          base::SPLIT_WANT_NONEMPTY);
-
-    for (const std::string& host : split_cmd_line_override) {
-      GURL url(host);
-      if (url.is_valid()) {
-        hosts.push_back(url);
-      }
-    }
-    if (!hosts.empty()) {
-      return hosts;
-    }
-  }
-
-  for (const auto& proxy : prefetch_config.proxy_list()) {
-    if (proxy.type() != PrefetchProxyConfig_Proxy_Type_CONNECT)
-      continue;
-
-    if (proxy.scheme() != PrefetchProxyConfig_Proxy_Scheme_HTTPS &&
-        !AllowInsecurePrefetchProxy()) {
-      LOG(ERROR) << "non-HTTPS PrefetchProxy hosts are not accepted without "
-                    "--allow-insecure-prefetch-proxy-for-testing";
-      continue;
-    }
-
-    std::string scheme =
-        protobuf_parser::SchemeFromPrefetchScheme(proxy.scheme());
-    if (scheme.empty())
-      continue;
-    if (proxy.host().empty())
-      continue;
-    if (proxy.port() == 0)
-      continue;
-
-    url::SchemeHostPort shp(scheme, proxy.host(),
-                            static_cast<uint16_t>(proxy.port()));
-    if (!shp.IsValid())
-      continue;
-
-    hosts.push_back(shp.GetURL());
-  }
-  return hosts;
-}
-
-void RecordAuthExpiredHistogram(bool auth_expired) {
-  UMA_HISTOGRAM_BOOLEAN(kUMAConfigServiceAuthExpired, auth_expired);
-}
-
-}  // namespace
-
-net::BackoffEntry::Policy GetBackoffPolicy() {
-  net::BackoffEntry::Policy policy = kDefaultBackoffPolicy;
-  if (base::FeatureList::IsEnabled(
-          features::kDataReductionProxyAggressiveConfigFetch)) {
-    // Disabling always_use_initial_delay allows no backoffs until
-    // num_errors_to_ignore failures have occurred.
-    policy.num_errors_to_ignore = 2;
-    policy.always_use_initial_delay = false;
-  }
-  return policy;
-}
-
-DataReductionProxyConfigServiceClient::DataReductionProxyConfigServiceClient(
-    const net::BackoffEntry::Policy& backoff_policy,
-    DataReductionProxyRequestOptions* request_options,
-    DataReductionProxyService* service,
-    network::NetworkConnectionTracker* network_connection_tracker,
-    ConfigStorer config_storer)
-    : request_options_(request_options),
-      service_(service),
-      network_connection_tracker_(network_connection_tracker),
-      config_storer_(config_storer),
-      backoff_policy_(backoff_policy),
-      backoff_entry_(&backoff_policy_),
-      config_service_url_(util::AddApiKeyToUrl(params::GetConfigServiceURL())),
-      enabled_(false),
-      remote_config_applied_(false),
-#if defined(OS_ANDROID)
-      foreground_fetch_pending_(false),
-#endif
-      previous_request_failed_authentication_(false),
-      failed_attempts_before_success_(0),
-      fetch_in_progress_(false),
-      client_config_override_used_(false) {
-  DCHECK(request_options);
-  DCHECK(service);
-  DCHECK(config_service_url_.is_valid());
-  DCHECK(params::ForceEnableClientConfigServiceForAllDataSaverUsers());
-
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  client_config_override_ = command_line.GetSwitchValueASCII(
-      switches::kDataReductionProxyServerClientConfig);
-
-  // Constructed on the UI thread, but should be checked on the IO thread.
-  thread_checker_.DetachFromThread();
-}
-
-DataReductionProxyConfigServiceClient::
-    ~DataReductionProxyConfigServiceClient() {
-  network_connection_tracker_->RemoveNetworkConnectionObserver(this);
-}
-
-base::TimeDelta
-DataReductionProxyConfigServiceClient::CalculateNextConfigRefreshTime(
-    bool fetch_succeeded,
-    const base::TimeDelta& config_expiration_delta,
-    const base::TimeDelta& backoff_delay) {
-  DCHECK(backoff_delay >= base::TimeDelta());
-
-#if defined(OS_ANDROID)
-  foreground_fetch_pending_ = false;
-  if (!fetch_succeeded &&
-      !base::FeatureList::IsEnabled(
-          features::kDataReductionProxyAggressiveConfigFetch) &&
-      IsApplicationStateBackground()) {
-    // If Chromium is in background, then fetch the config when Chromium comes
-    // to foreground or after max of |kMaxBackgroundFetchIntervalSeconds| and
-    // |backoff_delay|.
-    foreground_fetch_pending_ = true;
-    return std::max(backoff_delay, base::TimeDelta::FromSeconds(
-                                       kMaxBackgroundFetchIntervalSeconds));
-  }
-#endif
-
-  if (fetch_succeeded) {
-    return std::max(backoff_delay, config_expiration_delta);
-  }
-
-  return backoff_delay;
-}
-
-void DataReductionProxyConfigServiceClient::Initialize(
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
-  DCHECK(url_loader_factory);
-#if defined(OS_ANDROID)
-  // It is okay to use Unretained here because |app_status_listener| would be
-  // destroyed before |this|.
-  app_status_listener_ =
-      base::android::ApplicationStatusListener::New(base::BindRepeating(
-          &DataReductionProxyConfigServiceClient::OnApplicationStateChange,
-          base::Unretained(this)));
-#endif
-  url_loader_factory_ = std::move(url_loader_factory);
-  network_connection_tracker_->AddNetworkConnectionObserver(this);
-}
-
-void DataReductionProxyConfigServiceClient::SetEnabled(bool enabled) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  enabled_ = enabled;
-}
-
-void DataReductionProxyConfigServiceClient::InvalidateAndRetrieveNewConfig() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  InvalidateConfig();
-
-  if (fetch_in_progress_) {
-    // If a client config fetch is already in progress, then do not start
-    // another fetch since starting a new fetch will cause extra data
-    // usage, and also cancel the ongoing fetch.
-    return;
-  }
-
-  RetrieveConfig();
-}
-
-void DataReductionProxyConfigServiceClient::RetrieveConfig() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (!enabled_)
-    return;
-
-  if (!client_config_override_.empty()) {
-    // Return fast if the override has already been attempted.
-    if (client_config_override_used_) {
-      return;
-    }
-    // Set this flag so that we only attempt to apply the given config once. If
-    // there are parse errors, the DCHECKs will catch them in a debug build.
-    client_config_override_used_ = true;
-
-    std::string override_config;
-    bool b64_decode_ok =
-        base::Base64Decode(client_config_override_, &override_config);
-    LOG_IF(DFATAL, !b64_decode_ok)
-        << "The given ClientConfig is not valid base64";
-
-    ClientConfig config;
-    bool was_valid_config = config.ParseFromString(override_config);
-    LOG_IF(DFATAL, !was_valid_config) << "The given ClientConfig was invalid.";
-    if (was_valid_config)
-      ParseAndApplyProxyConfig(config);
-    return;
-  }
-
-  config_fetch_start_time_ = base::TimeTicks::Now();
-
-  RetrieveRemoteConfig();
-}
-
-bool DataReductionProxyConfigServiceClient::RemoteConfigApplied() const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  return remote_config_applied_;
-}
-
-void DataReductionProxyConfigServiceClient::ApplySerializedConfig(
-    const std::string& config_value) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (RemoteConfigApplied())
-    return;
-
-  if (!client_config_override_.empty())
-    return;
-
-  std::string decoded_config;
-  if (base::Base64Decode(config_value, &decoded_config)) {
-    ClientConfig config;
-    if (config.ParseFromString(decoded_config))
-      ParseAndApplyProxyConfig(config);
-  }
-}
-
-net::BackoffEntry* DataReductionProxyConfigServiceClient::GetBackoffEntry() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  return &backoff_entry_;
-}
-
-void DataReductionProxyConfigServiceClient::SetConfigRefreshTimer(
-    const base::TimeDelta& delay) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(delay >= base::TimeDelta());
-  config_refresh_timer_.Stop();
-  config_refresh_timer_.Start(
-      FROM_HERE, delay, this,
-      &DataReductionProxyConfigServiceClient::RetrieveConfig);
-}
-
-base::Time DataReductionProxyConfigServiceClient::Now() {
-  return base::Time::Now();
-}
-
-void DataReductionProxyConfigServiceClient::OnConnectionChanged(
-    network::mojom::ConnectionType type) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (type == network::mojom::ConnectionType::CONNECTION_NONE)
-    return;
-
-  GetBackoffEntry()->Reset();
-  last_ip_address_change_ = base::TimeTicks::Now();
-  failed_attempts_before_success_ = 0;
-  RetrieveConfig();
-}
-
-void DataReductionProxyConfigServiceClient::OnURLLoadComplete(
-    std::unique_ptr<std::string> response_body) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  fetch_in_progress_ = false;
-
-  int response_code = -1;
-  if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers) {
-    response_code = url_loader_->ResponseInfo()->headers->response_code();
-  }
-  HandleResponse(response_body ? *response_body : "", url_loader_->NetError(),
-                 response_code);
-}
-
-void DataReductionProxyConfigServiceClient::RetrieveRemoteConfig() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(params::ForceEnableClientConfigServiceForAllDataSaverUsers());
-
-  CreateClientConfigRequest request;
-  std::string serialized_request;
-#if defined(OS_ANDROID)
-  request.set_telephony_network_operator(
-      net::android::GetTelephonyNetworkOperator());
-#endif
-
-  data_reduction_proxy::ConfigDeviceInfo* device_info =
-      request.mutable_device_info();
-  device_info->set_total_device_memory_kb(
-      base::SysInfo::AmountOfPhysicalMemory() / 1024);
-  const std::string& session_key = request_options_->GetSecureSession();
-  if (!session_key.empty())
-    request.set_session_key(request_options_->GetSecureSession());
-  request.set_dogfood_group(
-      base::FeatureList::IsEnabled(features::kDogfood)
-          ? CreateClientConfigRequest_DogfoodGroup_DOGFOOD
-          : CreateClientConfigRequest_DogfoodGroup_NONDOGFOOD);
-  data_reduction_proxy::VersionInfo* version_info =
-      request.mutable_version_info();
-  uint32_t build;
-  uint32_t patch;
-  util::GetChromiumBuildAndPatchAsInts(util::ChromiumVersion(), &build, &patch);
-  version_info->set_client(util::GetStringForClient(service_->client()));
-  version_info->set_build(build);
-  version_info->set_patch(patch);
-  version_info->set_channel(service_->channel());
-  request.SerializeToString(&serialized_request);
-
-  net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("data_reduction_proxy_config", R"(
-        semantics {
-          sender: "Data Reduction Proxy"
-          description:
-            "Requests a configuration that specifies how to connect to the "
-            "data reduction proxy."
-          trigger:
-            "Requested when Data Saver is enabled and the browser does not "
-            "have a configuration that is not older than a threshold set by "
-            "the server."
-          data: "None."
-          destination: GOOGLE_OWNED_SERVICE
-        }
-        policy {
-          cookies_allowed: NO
-          setting:
-            "Users can control Data Saver on Android via 'Data Saver' setting. "
-            "Data Saver is not available on iOS, and on desktop it is enabled "
-            "by insalling the Data Saver extension."
-          policy_exception_justification: "Not implemented."
-        })");
-  fetch_in_progress_ = true;
-
-  auto resource_request = std::make_unique<network::ResourceRequest>();
-  resource_request->url = config_service_url_;
-  resource_request->method = "POST";
-  resource_request->load_flags = net::LOAD_BYPASS_PROXY;
-  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
-  // Attach variations headers.
-  url_loader_ = variations::CreateSimpleURLLoaderWithVariationsHeader(
-      std::move(resource_request), variations::InIncognito::kNo,
-      variations::SignedIn::kNo, traffic_annotation);
-
-  url_loader_->AttachStringForUpload(serialized_request,
-                                     "application/x-protobuf");
-  // |url_loader_| should not retry on 5xx errors since the server may already
-  // be overloaded. Spurious 5xx errors are still retried on exponential
-  // backoff. |url_loader_| should retry on network changes since the network
-  // stack may receive the connection change event later than |this|.
-  static const int kMaxRetries = 5;
-  url_loader_->SetRetryOptions(
-      kMaxRetries, network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE);
-  url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
-      url_loader_factory_.get(),
-      base::BindOnce(&DataReductionProxyConfigServiceClient::OnURLLoadComplete,
-                     base::Unretained(this)));
-}
-
-void DataReductionProxyConfigServiceClient::InvalidateConfig() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  GetBackoffEntry()->InformOfRequest(false);
-  config_storer_.Run(std::string());
-  request_options_->Invalidate();
-}
-
-void DataReductionProxyConfigServiceClient::HandleResponse(
-    const std::string& config_data,
-    int status,
-    int response_code) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ClientConfig config;
-  bool succeeded = false;
-
-  if (!network_connection_tracker_->IsOffline())
-    base::UmaHistogramSparse(kUMAConfigServiceFetchResponseCode, response_code);
-
-  if (status == net::OK && response_code == net::HTTP_OK &&
-      config.ParseFromString(config_data)) {
-    succeeded = ParseAndApplyProxyConfig(config);
-  }
-
-  base::TimeDelta refresh_duration;
-  if (succeeded) {
-    refresh_duration =
-        protobuf_parser::DurationToTimeDelta(config.refresh_duration());
-
-    DCHECK(!config_fetch_start_time_.is_null());
-    base::TimeDelta configuration_fetch_latency =
-        base::TimeTicks::Now() - config_fetch_start_time_;
-    RecordAuthExpiredHistogram(false);
-    UMA_HISTOGRAM_MEDIUM_TIMES(kUMAConfigServiceFetchLatency,
-                               configuration_fetch_latency);
-    UMA_HISTOGRAM_COUNTS_100(kUMAConfigServiceFetchFailedAttemptsBeforeSuccess,
-                             failed_attempts_before_success_);
-    failed_attempts_before_success_ = 0;
-    std::string encoded_config;
-    base::Base64Encode(config_data, &encoded_config);
-    config_storer_.Run(encoded_config);
-
-    // Record timing metrics on successful requests only.
-    const network::mojom::URLResponseHead* info = url_loader_->ResponseInfo();
-    base::TimeDelta http_request_rtt =
-        info->response_start - info->request_start;
-    UMA_HISTOGRAM_TIMES("DataReductionProxy.ConfigService.HttpRequestRTT",
-                        http_request_rtt);
-
-    if (info->load_timing.connect_timing.connect_end > base::TimeTicks() &&
-        info->load_timing.connect_timing.connect_start > base::TimeTicks()) {
-      base::TimeDelta connection_setup =
-          info->load_timing.connect_timing.connect_end -
-          info->load_timing.connect_timing.connect_start;
-      UMA_HISTOGRAM_TIMES(
-          "DataReductionProxy.ConfigService.ConnectionSetupTime",
-          connection_setup);
-    }
-  } else {
-    ++failed_attempts_before_success_;
-  }
-
-  GetBackoffEntry()->InformOfRequest(succeeded);
-  base::TimeDelta next_config_refresh_time = CalculateNextConfigRefreshTime(
-      succeeded, refresh_duration, GetBackoffEntry()->GetTimeUntilRelease());
-
-  SetConfigRefreshTimer(next_config_refresh_time);
-}
-
-bool DataReductionProxyConfigServiceClient::ParseAndApplyProxyConfig(
-    const ClientConfig& config) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (!config.has_proxy_config())
-    return false;
-
-  service_->UpdatePrefetchProxyHosts(
-      GetPrefetchProxyHosts(config.prefetch_proxy_config()));
-
-  request_options_->SetSecureSession(config.session_key());
-  remote_config_applied_ = true;
-  return true;
-}
-
-#if defined(OS_ANDROID)
-bool DataReductionProxyConfigServiceClient::IsApplicationStateBackground()
-    const {
-  return base::android::ApplicationStatusListener::GetState() !=
-         base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES;
-}
-
-void DataReductionProxyConfigServiceClient::OnApplicationStateChange(
-    base::android::ApplicationState new_state) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (new_state == base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES &&
-      foreground_fetch_pending_) {
-    foreground_fetch_pending_ = false;
-    RetrieveConfig();
-  }
-}
-#endif
-
-}  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
deleted file mode 100644
index 7289bf82..0000000
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
+++ /dev/null
@@ -1,261 +0,0 @@
-// 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_SERVICE_CLIENT_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_SERVICE_CLIENT_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/threading/thread_checker.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "net/base/backoff_entry.h"
-#include "services/network/public/cpp/network_connection_tracker.h"
-#include "url/gurl.h"
-
-#if defined(OS_ANDROID)
-#include "base/android/application_status_listener.h"
-#endif  // OS_ANDROID
-
-namespace network {
-class SharedURLLoaderFactory;
-class SimpleURLLoader;
-}  // namespace network
-
-namespace data_reduction_proxy {
-
-class ClientConfig;
-class DataReductionProxyService;
-class DataReductionProxyRequestOptions;
-
-using ConfigStorer = base::RepeatingCallback<void(const std::string&)>;
-
-// Retrieves the default net::BackoffEntry::Policy for the Data Reduction Proxy
-// configuration service client.
-net::BackoffEntry::Policy GetBackoffPolicy();
-
-// Retrieves the Data Reduction Proxy configuration from a remote service. This
-// object lives on the IO thread.
-// TODO(jeremyim): Rename the class to DataReductionProxyConfigGetter(?).
-//
-// The client config module is a state machine with 2 states:
-// 1) Chrome has a config. Requests will attempt to use DRP with that config.
-// 2) Chrome doesn’t have a config. Requests will go direct.
-//
-// When Chrome starts up, if there is a cached config on disk, it is loaded. Go
-// to state (1). Otherwise, go to state (2).
-//
-// When a config fetch finishes, move to state (1). If already in state (1),
-// replace the existing config.
-//
-// When in state (1), if a response comes back 407 whose request was made with
-// the existing config, invalidate the existing config and move to state (2).
-// Retry the request on the direct path.
-//
-// The following events will trigger a config fetch, without invalidating the
-// existing config. The existing config will be replaced when the async config
-// fetch returns.
-// * Starting Chrome.
-// * Using a config whose refresh_duration has expired (see
-//   components/data_reduction_proxy/proto/client_config.proto).
-// * Getting a IP address change event notification.
-//
-// Config fetches are async and subject to a backoff policy. On Android, the
-// fetch policy is different if Chrome is in the background. Every time a config
-// is fetched, it is written to the disk.
-class DataReductionProxyConfigServiceClient
-    : public network::NetworkConnectionTracker::NetworkConnectionObserver {
- public:
-  // The caller must ensure that all parameters remain alive for the lifetime of
-  // the |DataReductionProxyConfigClient|.
-  DataReductionProxyConfigServiceClient(
-      const net::BackoffEntry::Policy& backoff_policy,
-      DataReductionProxyRequestOptions* request_options,
-      DataReductionProxyService* service,
-      network::NetworkConnectionTracker* network_connection_tracker,
-      ConfigStorer config_storer);
-
-  ~DataReductionProxyConfigServiceClient() override;
-
-  // Performs initialization on the IO thread.
-  void Initialize(
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
-
-  // Sets whether the configuration should be retrieved or not.
-  void SetEnabled(bool enabled);
-
-  // Request the retrieval of the Data Reduction Proxy configuration. This
-  // operation takes place asynchronously.
-  void RetrieveConfig();
-
-  // Invalidates the current Data Reduction Proxy configuration and requests the
-  // retrieval of the Data Reduction Proxy configuration
-  void InvalidateAndRetrieveNewConfig();
-
-  // Takes a serialized Data Reduction Proxy configuration and sets it as the
-  // current Data Reduction Proxy configuration. If a remote configuration has
-  // already been retrieved, the remote configuration takes precedence.
-  void ApplySerializedConfig(const std::string& config_value);
-
-  void SetRemoteConfigAppliedForTesting(bool remote_config_applied) {
-    remote_config_applied_ = remote_config_applied;
-  }
-
- protected:
-  // Retrieves the backoff entry object being used to throttle request failures.
-  // Virtual for testing.
-  virtual net::BackoffEntry* GetBackoffEntry();
-
-  // Returns the current time.
-  // Virtual for testing.
-  virtual base::Time Now();
-
-  // Sets a timer to determine when to next refresh the Data Reduction Proxy
-  // configuration.
-  void SetConfigRefreshTimer(const base::TimeDelta& delay);
-
-#if defined(OS_ANDROID)
-  // Returns true if Chromium is in background.
-  // Virtualized for mocking.
-  virtual bool IsApplicationStateBackground() const;
-#endif
-
-  // Returns true if the remote config has been applied. Virtualized for
-  // testing.
-  virtual bool RemoteConfigApplied() const;
-
- private:
-  friend class TestDataReductionProxyConfigServiceClient;
-
-  // Returns the duration after which the Data Reduction Proxy configuration
-  // should be retrieved. |backoff_delay| must be non-negative.
-  base::TimeDelta CalculateNextConfigRefreshTime(
-      bool fetch_succeeded,
-      const base::TimeDelta& config_expiration,
-      const base::TimeDelta& backoff_delay);
-
-  // Override of network::NetworkConnectionTracker::NetworkConnectionObserver.
-  void OnConnectionChanged(network::mojom::ConnectionType type) override;
-
-  // URL loader completion callback.
-  void OnURLLoadComplete(std::unique_ptr<std::string> response_body);
-
-  // Retrieves the Data Reduction Proxy configuration from a remote service.
-  void RetrieveRemoteConfig();
-
-  // Invalidates the current Data Reduction Proxy configuration.
-  void InvalidateConfig();
-
-  // Handles the response from the remote Data Reduction Proxy configuration
-  // service. |response| is the response body, |status| is the
-  // |net::Error| of the response, and response_code is the HTTP
-  // response code (if available).
-  void HandleResponse(const std::string& response,
-                      int status,
-                      int response_code);
-
-  // Parses out the proxy configuration portion of |config| and applies it to
-  // |config_| and |request_options_|. Takes into account the field trials that
-  // this session belongs to. Returns true if the |config| was successfully
-  // parsed and applied.
-  bool ParseAndApplyProxyConfig(const ClientConfig& config);
-
-#if defined(OS_ANDROID)
-  // Listens to when Chromium comes to foreground and fetches new client config
-  // if the config fetch is pending.
-  void OnApplicationStateChange(base::android::ApplicationState new_state);
-#endif
-
-  // The caller must ensure that the |request_options_| outlives this instance.
-  DataReductionProxyRequestOptions* request_options_;
-
-  // The caller must ensure that the |service_| outlives this instance.
-  DataReductionProxyService* service_;
-
-  // Watches for network changes.
-  network::NetworkConnectionTracker* network_connection_tracker_;
-
-  // Used to persist a serialized Data Reduction Proxy configuration.
-  ConfigStorer config_storer_;
-
-  // Used to calculate the backoff time on request failures.
-  net::BackoffEntry::Policy backoff_policy_;
-  net::BackoffEntry backoff_entry_;
-
-  // The URL for retrieving the Data Reduction Proxy configuration.
-  GURL config_service_url_;
-
-  // True if the Data Reduction Proxy configuration should be retrieved.
-  bool enabled_;
-
-  // True if a remote Data Reduction Proxy configuration has been retrieved and
-  // successfully applied.
-  bool remote_config_applied_;
-
-  // Used for setting up the |url_loader_|.
-  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
-
-  // An event that fires when it is time to refresh the Data Reduction Proxy
-  // configuration.
-  base::OneShotTimer config_refresh_timer_;
-
-  // A |network::URLLoader| to retrieve the Date Reduction Proxy configuration.
-  std::unique_ptr<network::SimpleURLLoader> url_loader_;
-
-  // Used to determine the latency in retrieving the Data Reduction Proxy
-  // configuration.
-  base::TimeTicks config_fetch_start_time_;
-
-#if defined(OS_ANDROID)
-  // Listens to the application transitions from foreground to background or
-  // vice versa.
-  std::unique_ptr<base::android::ApplicationStatusListener>
-      app_status_listener_;
-
-  // True if config needs to be fetched when the application comes to
-  // foreground.
-  bool foreground_fetch_pending_;
-#endif
-
-  // Keeps track of whether the previous request to a Data Reduction Proxy
-  // failed to authenticate. This is necessary in the situation where a new
-  // configuration with a bad session key is obtained, but the previous request
-  // failed to authenticate, since the new configuration marks |backoff_entry_|
-  // with a success, resulting in no net increase in the backoff timer.
-  bool previous_request_failed_authentication_;
-
-  // Number of failed fetch attempts before the config is fetched successfully.
-  // It is reset to 0 every time there is a change in IP address, or when the
-  // config is fetched successfully.
-  int32_t failed_attempts_before_success_;
-
-  // Time when the IP address last changed.
-  base::TimeTicks last_ip_address_change_;
-
-  // True if a client config fetch is in progress.
-  bool fetch_in_progress_;
-
-  // If given on the command line with kDataReductionProxyServerClientConfig,
-  // this base64 binary-encoded ClientConfig will always be used instead of
-  // fetching one remotely, regardless of authentication error or expiration. If
-  // the value fails to parse as a valid ClientConfig, it will not be used.
-  std::string client_config_override_;
-
-  // True if |client_config_override_| has been applied to |this|.
-  bool client_config_override_used_;
-
-  // Enforce usage on the IO thread.
-  base::ThreadChecker thread_checker_;
-
-  DISALLOW_COPY_AND_ASSIGN(DataReductionProxyConfigServiceClient);
-};
-
-}  // namespace data_reduction_proxy
-#endif  // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_SERVICE_CLIENT_H_
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.cc
deleted file mode 100644
index c3c9ddd6..0000000
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.cc
+++ /dev/null
@@ -1,43 +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 "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h"
-
-#include <string>
-
-#include "base/base64.h"
-#include "components/data_reduction_proxy/proto/client_config.pb.h"
-#include "net/base/proxy_server.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace data_reduction_proxy {
-
-// Creates a new ClientConfig.
-ClientConfig CreateClientConfig(const std::string& session_key,
-                                int64_t expire_duration_seconds,
-                                int64_t expire_duration_nanoseconds) {
-  ClientConfig config;
-
-  config.set_session_key(session_key);
-  config.mutable_refresh_duration()->set_seconds(expire_duration_seconds);
-  config.mutable_refresh_duration()->set_nanos(expire_duration_nanoseconds);
-  config.mutable_proxy_config()->clear_http_proxy_servers();
-  return config;
-}
-
-// Takes |config| and returns the base64 encoding of its serialized byte stream.
-std::string EncodeConfig(const ClientConfig& config) {
-  std::string config_data;
-  std::string encoded_data;
-  EXPECT_TRUE(config.SerializeToString(&config_data));
-  base::Base64Encode(config_data, &encoded_data);
-  return encoded_data;
-}
-
-std::string DummyBase64Config() {
-  ClientConfig config = CreateClientConfig("secureSessionKey", 600, 0);
-  return EncodeConfig(config);
-}
-
-}  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h
deleted file mode 100644
index aa70fac4..0000000
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h
+++ /dev/null
@@ -1,28 +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 COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_SERVICE_CLIENT_TEST_UTILS_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_SERVICE_CLIENT_TEST_UTILS_H_
-
-#include <stdint.h>
-#include <string>
-
-#include "components/data_reduction_proxy/proto/client_config.pb.h"
-
-namespace data_reduction_proxy {
-
-// Creates a new ClientConfig.
-ClientConfig CreateClientConfig(const std::string& session_key,
-                                int64_t expire_duration_seconds,
-                                int64_t expire_duration_nanoseconds);
-
-// Takes |config| and returns the base64 encoding of its serialized byte stream.
-std::string EncodeConfig(const ClientConfig& config);
-
-// Returns a valid ClientConfig in base64 full of dummy values.
-std::string DummyBase64Config();
-
-}  // namespace data_reduction_proxy
-
-#endif  // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_SERVICE_CLIENT_TEST_UTILS_H_
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
deleted file mode 100644
index 162657f..0000000
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
+++ /dev/null
@@ -1,761 +0,0 @@
-// 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.
-
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include "base/base64.h"
-#include "base/command_line.h"
-#include "base/metrics/field_trial.h"
-#include "base/run_loop.h"
-#include "base/stl_util.h"
-#include "base/test/bind.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/mock_entropy_provider.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/test/task_environment.h"
-#include "base/time/default_clock.h"
-#include "base/time/time.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/data_reduction_proxy/proto/client_config.pb.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "net/base/network_change_notifier.h"
-#include "net/base/proxy_server.h"
-#include "net/http/http_request_headers.h"
-#include "net/http/http_response_headers.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/test/test_url_loader_factory.h"
-#include "services/network/test/test_utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace {
-
-// The following values should match those in
-// DataReductionProxyConfigServiceClientTest.config_:
-const char kSuccessSessionKey[] = "SecretSessionKey";
-
-// The following values should match those in
-// DataReductionProxyConfigServiceClientTest.previous_config_:
-const char kOldSuccessSessionKey[] = "OldSecretSessionKey";
-
-// The following values should match those in
-// DataReductionProxyConfigServiceClientTest.loaded_config_:
-const char kPersistedSessionKey[] = "PersistedSessionKey";
-
-// Duration (in seconds) after which the config should be refreshed.
-const int kConfigRefreshDurationSeconds = 600;
-
-#if defined(OS_ANDROID)
-// Maximum duration  to wait before fetching the config, while the application
-// is in background.
-const uint32_t kMaxBackgroundFetchIntervalSeconds = 6 * 60 * 60;  // 6 hours.
-#endif
-
-}  // namespace
-
-namespace data_reduction_proxy {
-
-class DataReductionProxyConfigServiceClientTest : public testing::Test {
- protected:
-  DataReductionProxyConfigServiceClientTest(
-      bool enable_aggressive_config_fetch_feature = false)
-      : test_shared_url_loader_factory_(
-            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-                &test_url_loader_factory_)) {
-    if (enable_aggressive_config_fetch_feature) {
-      scoped_feature_list_.InitAndEnableFeature(
-          features::kDataReductionProxyAggressiveConfigFetch);
-    } else {
-      scoped_feature_list_.InitAndDisableFeature(
-          features::kDataReductionProxyAggressiveConfigFetch);
-    }
-  }
-
-  void SetUp() override {
-    testing::Test::SetUp();
-
-    // Install an interceptor here to process the queue of responses
-    // (fed by calls to AddMock{Success,PreviousSuccess,Failure}.
-    test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
-        [&](const network::ResourceRequest& request) {
-          // Some tests trigger loading, without having an respective
-          // mock response set. Ignore such cases.
-          if (mock_responses_.size() <= curr_mock_response_index_) {
-            test_url_loader_factory_.pending_requests()->clear();
-            return;
-          }
-          test_url_loader_factory_.ClearResponses();
-          test_url_loader_factory_.AddResponse(
-              request.url.spec(),
-              mock_responses_[curr_mock_response_index_].response,
-              mock_responses_[curr_mock_response_index_].http_code);
-          curr_mock_response_index_++;
-          RunUntilIdle();
-        }));
-  }
-
-  void Init() {
-    test_context_ = DataReductionProxyTestContext::Builder()
-                        .WithURLLoaderFactory(test_shared_url_loader_factory_)
-                        .WithMockRequestOptions()
-                        .WithTestConfigClient()
-                        .SkipSettingsInitialization()
-                        .Build();
-
-    test_context_->InitSettings();
-    ResetBackoffEntryReleaseTime();
-    test_context_->test_config_client()->SetNow(base::Time::UnixEpoch());
-    test_context_->test_config_client()->SetEnabled(true);
-    test_context_->test_config_client()->SetConfigServiceURL(
-        GURL("http://configservice.com"));
-
-    // Set up the various test ClientConfigs.
-    ClientConfig config = CreateClientConfig(kSuccessSessionKey,
-                                             kConfigRefreshDurationSeconds, 0);
-    config.SerializeToString(&config_);
-    encoded_config_ = EncodeConfig(config);
-
-    ClientConfig previous_config = CreateClientConfig(
-        kOldSuccessSessionKey, kConfigRefreshDurationSeconds, 0);
-    previous_config.SerializeToString(&previous_config_);
-
-    ClientConfig persisted = CreateClientConfig(
-        kPersistedSessionKey, kConfigRefreshDurationSeconds, 0);
-    loaded_config_ = EncodeConfig(persisted);
-
-    ClientConfig ignore_block_list_config = CreateClientConfig(
-        kSuccessSessionKey, kConfigRefreshDurationSeconds, 0);
-    ignore_block_list_encoded_config_ = EncodeConfig(ignore_block_list_config);
-
-    ClientConfig no_proxies_config;
-    no_proxies_config.set_session_key(kSuccessSessionKey);
-    no_proxies_config.mutable_refresh_duration()->set_seconds(
-        kConfigRefreshDurationSeconds);
-    no_proxies_config.mutable_refresh_duration()->set_nanos(0);
-    no_proxies_config_ = EncodeConfig(no_proxies_config);
-  }
-
-  void ResetBackoffEntryReleaseTime() {
-    config_client()->SetCustomReleaseTime(base::TimeTicks::UnixEpoch());
-  }
-
-  void VerifyRemoteSuccess(bool expect_secure_proxies) {
-    EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
-              config_client()->GetDelay());
-    EXPECT_EQ(kSuccessSessionKey, request_options()->GetSecureSession());
-    // The config should be persisted on the pref.
-    EXPECT_EQ(encoded_config(), persisted_config());
-  }
-
-  void VerifyRemoteSuccessWithOldConfig() {
-    EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
-              config_client()->GetDelay());
-    EXPECT_EQ(kOldSuccessSessionKey, request_options()->GetSecureSession());
-  }
-
-  void VerifySuccessWithLoadedConfig(bool expect_secure_proxies) {
-    EXPECT_EQ(kPersistedSessionKey, request_options()->GetSecureSession());
-  }
-
-  TestDataReductionProxyConfigServiceClient* config_client() {
-    return test_context_->test_config_client();
-  }
-
-  MockDataReductionProxyRequestOptions* request_options() {
-    return test_context_->mock_request_options();
-  }
-
-  void RunUntilIdle() { test_context_->RunUntilIdle(); }
-
-  void AddMockSuccess() {
-    mock_responses_.push_back({success_response(), net::HTTP_OK});
-  }
-
-  void AddMockPreviousSuccess() {
-    mock_responses_.push_back({previous_success_response(), net::HTTP_OK});
-  }
-
-  void AddMockFailure() {
-    mock_responses_.push_back({std::string(), net::HTTP_NOT_FOUND});
-  }
-
-  std::string persisted_config() const {
-    return test_context_->pref_service()->GetString(
-        prefs::kDataReductionProxyConfig);
-  }
-
-  base::Time persisted_config_retrieval_time() const {
-    return base::Time() +
-           base::TimeDelta::FromMicroseconds(
-               test_context_->pref_service()->GetInt64(
-                   prefs::kDataReductionProxyLastConfigRetrievalTime));
-  }
-
-  const std::string& success_response() const { return config_; }
-
-  const std::string& encoded_config() const { return encoded_config_; }
-
-  const std::string& previous_success_response() const {
-    return previous_config_;
-  }
-  const std::string& ignore_block_list_encoded_config() const {
-    return ignore_block_list_encoded_config_;
-  }
-  const std::string& no_proxies_config() const { return no_proxies_config_; }
-
-  const std::string& loaded_config() const { return loaded_config_; }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-  base::test::SingleThreadTaskEnvironment task_environment_;
-
-  network::TestURLLoaderFactory test_url_loader_factory_;
-  scoped_refptr<network::SharedURLLoaderFactory>
-      test_shared_url_loader_factory_;
-
- protected:
-  std::unique_ptr<DataReductionProxyTestContext> test_context_;
-
- private:
-  std::unique_ptr<DataReductionProxyRequestOptions> request_options_;
-
-  // A configuration from the current remote request. The encoded version is
-  // also stored.
-  std::string config_;
-  std::string encoded_config_;
-
-  // A configuration from a previous remote request.
-  std::string previous_config_;
-
-  // An encoded config that represents a previously saved configuration.
-  std::string loaded_config_;
-
-  // A configuration where the block list rules are ignored.
-  std::string ignore_block_list_encoded_config_;
-
-  // A configuration where no proxies are configured.
-  std::string no_proxies_config_;
-
-  struct MockResponse {
-    std::string response;
-    net::HttpStatusCode http_code;
-  };
-  std::vector<MockResponse> mock_responses_;
-  size_t curr_mock_response_index_ = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(DataReductionProxyConfigServiceClientTest);
-};
-
-// Tests that backoff values increases with every time config cannot be fetched.
-TEST_F(DataReductionProxyConfigServiceClientTest, EnsureBackoff) {
-  Init();
-  // Use a local/static config.
-  base::HistogramTester histogram_tester;
-  AddMockFailure();
-  AddMockFailure();
-  AddMockSuccess();
-
-  EXPECT_EQ(0, config_client()->failed_attempts_before_success());
-
-  // First attempt should be unsuccessful.
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-  EXPECT_EQ(base::TimeDelta::FromSeconds(30), config_client()->GetDelay());
-
-#if defined(OS_ANDROID)
-  EXPECT_FALSE(config_client()->foreground_fetch_pending());
-#endif
-
-  // Second attempt should be unsuccessful and backoff time should increase.
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-  EXPECT_EQ(base::TimeDelta::FromSeconds(90), config_client()->GetDelay());
-  EXPECT_TRUE(persisted_config().empty());
-  EXPECT_TRUE(persisted_config_retrieval_time().is_null());
-
-#if defined(OS_ANDROID)
-  EXPECT_FALSE(config_client()->foreground_fetch_pending());
-#endif
-
-  EXPECT_EQ(2, config_client()->failed_attempts_before_success());
-  histogram_tester.ExpectTotalCount(
-      "DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess", 0);
-}
-
-// Tests that the config is read successfully on the first attempt.
-TEST_F(DataReductionProxyConfigServiceClientTest, RemoteConfigSuccess) {
-  Init();
-  base::HistogramTester histogram_tester;
-
-  AddMockSuccess();
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-  VerifyRemoteSuccess(true);
-  histogram_tester.ExpectTotalCount(
-      "DataReductionProxy.ConfigService.HttpRequestRTT", 1);
-#if defined(OS_ANDROID)
-  EXPECT_FALSE(config_client()->foreground_fetch_pending());
-#endif
-}
-
-// Tests that the config is read successfully on the first attempt, and secure
-// proxies are not used if the secure check failed.
-TEST_F(DataReductionProxyConfigServiceClientTest,
-       RemoteConfigSuccessWithSecureCheckFail) {
-  Init();
-  AddMockSuccess();
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-  VerifyRemoteSuccess(false);
-#if defined(OS_ANDROID)
-  EXPECT_FALSE(config_client()->foreground_fetch_pending());
-#endif
-}
-
-
-// Tests that the config is read successfully on the second attempt.
-TEST_F(DataReductionProxyConfigServiceClientTest,
-       RemoteConfigSuccessAfterFailure) {
-  Init();
-  base::HistogramTester histogram_tester;
-
-  AddMockFailure();
-  AddMockSuccess();
-
-  EXPECT_EQ(0, config_client()->failed_attempts_before_success());
-
-  // First attempt should be unsuccessful.
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-  EXPECT_EQ(1, config_client()->failed_attempts_before_success());
-  EXPECT_EQ(base::TimeDelta::FromSeconds(30), config_client()->GetDelay());
-  EXPECT_TRUE(request_options()->GetSecureSession().empty());
-
-  // Second attempt should be successful.
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-  VerifyRemoteSuccess(true);
-  EXPECT_EQ(0, config_client()->failed_attempts_before_success());
-
-  histogram_tester.ExpectUniqueSample(
-      "DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess", 1,
-      1);
-  histogram_tester.ExpectTotalCount(
-      "DataReductionProxy.ConfigService.HttpRequestRTT", 1);
-}
-
-// Verifies that the config is fetched successfully after IP address changes.
-TEST_F(DataReductionProxyConfigServiceClientTest, OnIPAddressChange) {
-  Init();
-  const struct {
-    bool secure_proxies_allowed;
-  } tests[] = {
-      {
-          true,
-      },
-      {
-          false,
-      },
-  };
-
-  for (size_t i = 0; i < base::size(tests); ++i) {
-    config_client()->RetrieveConfig();
-
-    const int kFailureCount = 5;
-
-    for (int i = 0; i < kFailureCount; ++i) {
-      AddMockFailure();
-      config_client()->RetrieveConfig();
-      RunUntilIdle();
-    }
-
-    // Verify that the backoff increased exponentially.
-    EXPECT_EQ(base::TimeDelta::FromSeconds(2430),
-              config_client()->GetDelay());  // 2430 = 30 * 3^(5-1)
-    EXPECT_EQ(kFailureCount, config_client()->GetBackoffErrorCount());
-
-    // IP address change should reset.
-    config_client()->OnConnectionChanged(
-        network::mojom::ConnectionType::CONNECTION_WIFI);
-    EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
-    EXPECT_EQ(i == 0, persisted_config().empty());
-    EXPECT_EQ(i == 0, persisted_config_retrieval_time().is_null());
-    ResetBackoffEntryReleaseTime();
-
-    // Fetching the config should be successful.
-    AddMockSuccess();
-    config_client()->RetrieveConfig();
-    RunUntilIdle();
-    VerifyRemoteSuccess(tests[i].secure_proxies_allowed);
-  }
-}
-
-// Verifies that the config is fetched successfully after IP address changes,
-// and secure proxies are not used if the secure proxy check fails later after
-// some time.
-TEST_F(DataReductionProxyConfigServiceClientTest,
-       OnIPAddressChangeDelayedSecureProxyCheckFail) {
-  Init();
-
-  config_client()->RetrieveConfig();
-
-  const int kFailureCount = 5;
-
-  for (int i = 0; i < kFailureCount; ++i) {
-    AddMockFailure();
-    config_client()->RetrieveConfig();
-    RunUntilIdle();
-  }
-
-  // Verify that the backoff increased exponentially.
-  EXPECT_EQ(base::TimeDelta::FromSeconds(2430),
-            config_client()->GetDelay());  // 2430 = 30 * 3^(5-1)
-  EXPECT_EQ(kFailureCount, config_client()->GetBackoffErrorCount());
-
-  // IP address change should reset.
-  config_client()->OnConnectionChanged(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
-  EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
-  EXPECT_TRUE(persisted_config().empty());
-  EXPECT_TRUE(persisted_config_retrieval_time().is_null());
-  ResetBackoffEntryReleaseTime();
-
-  // Fetching the config should be successful.
-  AddMockSuccess();
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-  VerifyRemoteSuccess(true);
-
-}
-
-// Verifies that fetching the remote config has no effect if the config client
-// is disabled.
-TEST_F(DataReductionProxyConfigServiceClientTest, OnIPAddressChangeDisabled) {
-  Init();
-  config_client()->SetEnabled(false);
-  config_client()->RetrieveConfig();
-  EXPECT_TRUE(request_options()->GetSecureSession().empty());
-
-  enum : int { kFailureCount = 5 };
-
-  for (int i = 0; i < kFailureCount; ++i) {
-    config_client()->RetrieveConfig();
-    RunUntilIdle();
-    EXPECT_TRUE(request_options()->GetSecureSession().empty());
-  }
-
-  EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
-  config_client()->OnConnectionChanged(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
-  EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
-
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-
-  EXPECT_TRUE(request_options()->GetSecureSession().empty());
-}
-
-// Verifies that the persisted client config is fetched from the disk at
-// startup, and that the persisted client config is used only if it is less
-// than 24 hours old.
-TEST_F(DataReductionProxyConfigServiceClientTest,
-       ValidatePersistedClientConfig) {
-  Init();
-
-  const struct {
-    base::Optional<base::TimeDelta> staleness;
-    bool expect_valid_config;
-  } tests[] = {
-      {
-          base::nullopt,
-          true,
-      },
-      {
-          base::TimeDelta::FromHours(25),
-          false,
-      },
-      {
-          base::TimeDelta::FromHours(1),
-          true,
-      },
-  };
-
-  for (const auto& test : tests) {
-    base::HistogramTester histogram_tester;
-    // Reset the state.
-    request_options()->Invalidate();
-    test_context_->pref_service()->ClearPref(
-        prefs::kDataReductionProxyLastConfigRetrievalTime);
-    RunUntilIdle();
-    EXPECT_TRUE(request_options()->GetSecureSession().empty());
-
-    // Apply a valid config. This should be stored on the disk.
-    AddMockSuccess();
-    config_client()->RetrieveConfig();
-
-    RunUntilIdle();
-    EXPECT_EQ(kSuccessSessionKey, request_options()->GetSecureSession());
-
-    if (test.staleness) {
-      base::TimeDelta last_config_retrieval_time =
-          base::Time::Now() - base::Time() - test.staleness.value();
-
-      test_context_->pref_service()->SetInt64(
-          prefs::kDataReductionProxyLastConfigRetrievalTime,
-          last_config_retrieval_time.InMicroseconds());
-      test_context_->pref_service()->SchedulePendingLossyWrites();
-      test_context_->pref_service()->CommitPendingWrite();
-    }
-
-    RunUntilIdle();
-    EXPECT_FALSE(persisted_config().empty());
-    EXPECT_FALSE(persisted_config_retrieval_time().is_null());
-
-    // Simulate startup which should cause the empty persisted client config to
-    // be read from the disk.
-    config_client()->SetRemoteConfigApplied(false);
-    request_options()->Invalidate();
-    test_context_->data_reduction_proxy_service()->ReadPersistedClientConfig();
-    RunUntilIdle();
-    EXPECT_NE(test.expect_valid_config,
-              request_options()->GetSecureSession().empty());
-    if (test.expect_valid_config) {
-      EXPECT_EQ(kSuccessSessionKey, request_options()->GetSecureSession());
-    }
-  }
-}
-
-// Tests that the config is overriden by kDataReductionProxyServerClientConfig.
-TEST_F(DataReductionProxyConfigServiceClientTest, ApplyClientConfigOverride) {
-  const std::string override_key = "OverrideSecureSession";
-  std::string encoded_config;
-  ClientConfig config =
-      CreateClientConfig(override_key, kConfigRefreshDurationSeconds, 0);
-  config.SerializeToString(&encoded_config);
-  base::Base64Encode(encoded_config, &encoded_config);
-
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      data_reduction_proxy::switches::kDataReductionProxyServerClientConfig,
-      encoded_config);
-  Init();
-
-  AddMockSuccess();
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-  // Make sure repeated fetches won't change the overridden config.
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-  EXPECT_EQ(request_options()->GetSecureSession(), override_key);
-}
-
-// Tests that remote config can be applied after the serialized config has
-// been applied.
-TEST_F(DataReductionProxyConfigServiceClientTest, ApplySerializedConfig) {
-  Init();
-  AddMockSuccess();
-
-  config_client()->ApplySerializedConfig(loaded_config());
-  VerifySuccessWithLoadedConfig(true);
-  EXPECT_TRUE(persisted_config().empty());
-
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-  VerifyRemoteSuccess(true);
-}
-
-// Tests that remote config can be applied after the serialized config has
-// been applied. Verifies that if the secure transport is restricted, then the
-// secure proxies are not used.
-TEST_F(DataReductionProxyConfigServiceClientTest,
-       ApplySerializedConfigWithSecureTransportRestricted) {
-  Init();
-
-  AddMockSuccess();
-
-  config_client()->ApplySerializedConfig(loaded_config());
-  VerifySuccessWithLoadedConfig(false);
-  EXPECT_TRUE(persisted_config().empty());
-
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-  VerifyRemoteSuccess(false);
-}
-
-// Tests that serialized config has no effect after the config has been
-// retrieved successfully.
-TEST_F(DataReductionProxyConfigServiceClientTest,
-       ApplySerializedConfigAfterReceipt) {
-  Init();
-  AddMockSuccess();
-
-  EXPECT_TRUE(request_options()->GetSecureSession().empty());
-
-  // Retrieve the remote config.
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-  VerifyRemoteSuccess(true);
-
-  // ApplySerializedConfig should not have any effect since the remote config
-  // is already applied.
-  config_client()->ApplySerializedConfig(encoded_config());
-  VerifyRemoteSuccess(true);
-}
-
-// Tests that a local serialized config can be applied successfully if remote
-// config has not been fetched so far.
-TEST_F(DataReductionProxyConfigServiceClientTest, ApplySerializedConfigLocal) {
-  Init();
-  EXPECT_TRUE(request_options()->GetSecureSession().empty());
-  EXPECT_TRUE(persisted_config_retrieval_time().is_null());
-
-  // ApplySerializedConfig should apply the encoded config.
-  config_client()->ApplySerializedConfig(encoded_config());
-  EXPECT_TRUE(persisted_config().empty());
-  EXPECT_TRUE(persisted_config_retrieval_time().is_null());
-  EXPECT_FALSE(request_options()->GetSecureSession().empty());
-}
-
-TEST_F(DataReductionProxyConfigServiceClientTest, EmptyConfigDisablesDRP) {
-  Init();
-
-  config_client()->ApplySerializedConfig(no_proxies_config());
-}
-
-#if defined(OS_ANDROID)
-// Verifies the correctness of fetching config when Chromium is in background
-// and foreground.
-TEST_F(DataReductionProxyConfigServiceClientTest, FetchConfigOnForeground) {
-  Init();
-
-  {
-    // Tests that successful config fetches while Chromium is in background,
-    // does not trigger refetches when Chromium comes to foreground.
-    base::HistogramTester histogram_tester;
-    AddMockSuccess();
-    config_client()->set_application_state_background(true);
-    config_client()->RetrieveConfig();
-    RunUntilIdle();
-    VerifyRemoteSuccess(true);
-    EXPECT_FALSE(config_client()->foreground_fetch_pending());
-    histogram_tester.ExpectTotalCount(
-        "DataReductionProxy.ConfigService.FetchLatency", 1);
-    EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
-              config_client()->GetDelay());
-    config_client()->set_application_state_background(false);
-    config_client()->TriggerApplicationStatusToForeground();
-    RunUntilIdle();
-    EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
-              config_client()->GetDelay());
-    histogram_tester.ExpectTotalCount(
-        "DataReductionProxy.ConfigService.FetchLatency", 1);
-  }
-
-  {
-    // Tests that config fetch failures while Chromium is in foreground does not
-    // trigger refetches when Chromium comes to foreground again.
-    base::HistogramTester histogram_tester;
-    AddMockFailure();
-    config_client()->set_application_state_background(false);
-    config_client()->RetrieveConfig();
-    RunUntilIdle();
-    EXPECT_FALSE(config_client()->foreground_fetch_pending());
-    histogram_tester.ExpectTotalCount(
-        "DataReductionProxy.ConfigService.FetchLatency", 0);
-    EXPECT_EQ(base::TimeDelta::FromSeconds(30), config_client()->GetDelay());
-    config_client()->TriggerApplicationStatusToForeground();
-    RunUntilIdle();
-    histogram_tester.ExpectTotalCount(
-        "DataReductionProxy.ConfigService.FetchLatency", 0);
-    EXPECT_EQ(base::TimeDelta::FromSeconds(30), config_client()->GetDelay());
-  }
-
-  {
-    // Tests that config fetch failures while Chromium is in background, trigger
-    // a refetch when Chromium comes to foreground.
-    base::HistogramTester histogram_tester;
-    AddMockFailure();
-    AddMockSuccess();
-    config_client()->set_application_state_background(true);
-    config_client()->RetrieveConfig();
-    RunUntilIdle();
-    EXPECT_TRUE(config_client()->foreground_fetch_pending());
-    histogram_tester.ExpectTotalCount(
-        "DataReductionProxy.ConfigService.FetchLatency", 0);
-    EXPECT_EQ(base::TimeDelta::FromSeconds(kMaxBackgroundFetchIntervalSeconds),
-              config_client()->GetDelay());
-    config_client()->set_application_state_background(false);
-    config_client()->TriggerApplicationStatusToForeground();
-    RunUntilIdle();
-    EXPECT_FALSE(config_client()->foreground_fetch_pending());
-    histogram_tester.ExpectTotalCount(
-        "DataReductionProxy.ConfigService.FetchLatency", 1);
-    EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
-              config_client()->GetDelay());
-    VerifyRemoteSuccess(true);
-  }
-}
-
-class DataReductionProxyAggressiveConfigServiceClientTest
-    : public DataReductionProxyConfigServiceClientTest {
- public:
-  DataReductionProxyAggressiveConfigServiceClientTest()
-      : DataReductionProxyConfigServiceClientTest(true) {}
-};
-
-TEST_F(DataReductionProxyAggressiveConfigServiceClientTest,
-       AggressiveFetchConfigOnBackground) {
-  Init();
-
-  // Tests that config fetch failures while Chromium is in background, trigger
-  // refetches while still in background, and no refetch happens Chromium
-  // comes to foreground, when the aggressive client config fetch feature is
-  // enabled.
-  base::HistogramTester histogram_tester;
-  AddMockFailure();
-  AddMockFailure();
-  AddMockSuccess();
-  config_client()->set_application_state_background(true);
-  config_client()->RetrieveConfig();
-  RunUntilIdle();
-  // Three fetches are triggered in background without any backoff. First two
-  // fail, while the third succeeds.
-  EXPECT_EQ(base::TimeDelta::FromSeconds(0),
-            config_client()->GetBackoffTimeUntilRelease());
-  EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
-            config_client()->GetDelay());
-  EXPECT_FALSE(config_client()->foreground_fetch_pending());
-  histogram_tester.ExpectTotalCount(
-      "DataReductionProxy.ConfigService.FetchLatency", 1);
-  histogram_tester.ExpectBucketCount(
-      "DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess", 2,
-      1);
-
-  // No new fetch should happen when Chromium comes to foreground.
-  config_client()->set_application_state_background(false);
-  config_client()->TriggerApplicationStatusToForeground();
-  RunUntilIdle();
-  EXPECT_FALSE(config_client()->foreground_fetch_pending());
-  histogram_tester.ExpectTotalCount(
-      "DataReductionProxy.ConfigService.FetchLatency", 1);
-  EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
-            config_client()->GetDelay());
-  VerifyRemoteSuccess(true);
-}
-
-#endif
-
-}  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
index 15f90e5..03fe3d84 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
@@ -152,9 +152,6 @@
   registry->RegisterListPref(prefs::kDailyHttpReceivedContentLength);
 
   registry->RegisterInt64Pref(prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
-  registry->RegisterStringPref(prefs::kDataReductionProxyConfig, std::string());
-  registry->RegisterInt64Pref(prefs::kDataReductionProxyLastConfigRetrievalTime,
-                              0L);
 
   registry->RegisterIntegerPref(prefs::kThisWeekNumber, 0);
   registry->RegisterDictionaryPref(
@@ -196,9 +193,6 @@
   registry->RegisterListPref(prefs::kDailyHttpReceivedContentLength);
   registry->RegisterInt64Pref(
       prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
-  registry->RegisterStringPref(prefs::kDataReductionProxyConfig, std::string());
-  registry->RegisterInt64Pref(prefs::kDataReductionProxyLastConfigRetrievalTime,
-                              0L);
 
   registry->RegisterIntegerPref(prefs::kThisWeekNumber, 0);
   registry->RegisterDictionaryPref(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
index b3cc3ce..3d62fac 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
@@ -21,7 +21,6 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/variations/variations_associated_data.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/load_flags.h"
 #include "net/base/proxy_server.h"
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
index 280da4a..46bc013 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
@@ -21,7 +21,6 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/variations/variations_associated_data.h"
 #include "net/base/auth.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/load_flags.h"
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
index 5a5b8e7..285fa4b0 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
@@ -18,7 +18,6 @@
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h"
@@ -31,7 +30,6 @@
 #include "components/data_use_measurement/core/data_use_measurement.h"
 #include "components/prefs/pref_service.h"
 #include "components/previews/core/previews_experiments.h"
-#include "mojo/public/cpp/bindings/remote.h"
 
 namespace data_reduction_proxy {
 
@@ -61,33 +59,24 @@
 DataReductionProxyService::DataReductionProxyService(
     DataReductionProxySettings* settings,
     PrefService* prefs,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     std::unique_ptr<DataStore> store,
-    network::NetworkQualityTracker* network_quality_tracker,
-    network::NetworkConnectionTracker* network_connection_tracker,
     data_use_measurement::DataUseMeasurement* data_use_measurement,
     const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
     const base::TimeDelta& commit_delay,
     Client client,
     const std::string& channel,
     const std::string& user_agent)
-    : url_loader_factory_(std::move(url_loader_factory)),
-      settings_(settings),
+    : settings_(settings),
       prefs_(prefs),
       db_data_owner_(new DBDataOwner(std::move(store))),
       db_task_runner_(db_task_runner),
-      network_quality_tracker_(network_quality_tracker),
-      network_connection_tracker_(network_connection_tracker),
       data_use_measurement_(data_use_measurement),
-      effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
       client_(client),
       channel_(channel),
       save_data_savings_estimate_dict_(
           GetSaveDataSavingsPercentEstimateFromFieldTrial()) {
   DCHECK(data_use_measurement_);
   DCHECK(settings);
-  DCHECK(network_quality_tracker_);
-  DCHECK(network_connection_tracker_);
 
   request_options_ =
       std::make_unique<DataReductionProxyRequestOptions>(client_);
@@ -99,22 +88,6 @@
       base::BindRepeating(&DataReductionProxyService::UpdateProxyRequestHeaders,
                           base::Unretained(this)));
 
-  // It is safe to use base::Unretained here, since it gets executed
-  // synchronously on the UI thread, and |this| outlives the caller (since the
-  // caller is owned by |this|.
-  if (params::ForceEnableClientConfigServiceForAllDataSaverUsers()) {
-    config_client_ = std::make_unique<DataReductionProxyConfigServiceClient>(
-        GetBackoffPolicy(), request_options_.get(), this,
-        network_connection_tracker_,
-        base::BindRepeating(&DataReductionProxyService::StoreSerializedConfig,
-                            base::Unretained(this)));
-  }
-
-  if (config_client_)
-    config_client_->Initialize(url_loader_factory_);
-
-  ReadPersistedClientConfig();
-
   db_task_runner_->PostTask(FROM_HERE,
                             base::BindOnce(&DBDataOwner::InitializeOnDBThread,
                                            db_data_owner_->GetWeakPtr()));
@@ -122,25 +95,13 @@
     compression_stats_.reset(
         new DataReductionProxyCompressionStats(this, prefs_, commit_delay));
   }
-  network_quality_tracker_->AddEffectiveConnectionTypeObserver(this);
-  network_quality_tracker_->AddRTTAndThroughputEstimatesObserver(this);
   if (data_use_measurement_) {  // null in unit tests.
     data_use_measurement_->AddServicesDataUseObserver(this);
   }
-
-  // TODO(rajendrant): Combine uses of NetworkConnectionTracker within DRP.
-  network_connection_tracker_->AddNetworkConnectionObserver(this);
-  network_connection_tracker_->GetConnectionType(
-      &connection_type_,
-      base::BindOnce(&DataReductionProxyService::OnConnectionChanged,
-                     GetWeakPtr()));
 }
 
 DataReductionProxyService::~DataReductionProxyService() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  network_quality_tracker_->RemoveEffectiveConnectionTypeObserver(this);
-  network_quality_tracker_->RemoveRTTAndThroughputEstimatesObserver(this);
-  network_connection_tracker_->RemoveNetworkConnectionObserver(this);
   compression_stats_.reset();
   db_task_runner_->DeleteSoon(FROM_HERE, db_data_owner_.release());
   if (data_use_measurement_) {  // null in unit tests.
@@ -148,56 +109,6 @@
   }
 }
 
-void DataReductionProxyService::ReadPersistedClientConfig() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (!prefs_)
-    return;
-
-  base::Time last_config_retrieval_time =
-      base::Time() + base::TimeDelta::FromMicroseconds(prefs_->GetInt64(
-                         prefs::kDataReductionProxyLastConfigRetrievalTime));
-  base::TimeDelta time_since_last_config_retrieval =
-      base::Time::Now() - last_config_retrieval_time;
-
-  // A config older than 24 hours should not be used.
-  bool persisted_config_is_expired =
-      !last_config_retrieval_time.is_null() &&
-      time_since_last_config_retrieval > base::TimeDelta::FromHours(24);
-
-  if (persisted_config_is_expired)
-    return;
-
-  const std::string config_value =
-      prefs_->GetString(prefs::kDataReductionProxyConfig);
-
-  if (config_value.empty())
-    return;
-
-  if (config_client_)
-    config_client_->ApplySerializedConfig(config_value);
-}
-
-void DataReductionProxyService::OnConnectionChanged(
-    network::mojom::ConnectionType type) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  connection_type_ = type;
-}
-
-void DataReductionProxyService::OnEffectiveConnectionTypeChanged(
-    net::EffectiveConnectionType type) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  effective_connection_type_ = type;
-}
-
-void DataReductionProxyService::OnRTTOrThroughputEstimatesComputed(
-    base::TimeDelta http_rtt,
-    base::TimeDelta transport_rtt,
-    int32_t downstream_throughput_kbps) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  http_rtt_ = http_rtt;
-}
 
 void DataReductionProxyService::Shutdown() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -248,39 +159,6 @@
     prefs_->SetString(pref_path, value);
 }
 
-void DataReductionProxyService::SetProxyPrefs(bool enabled, bool at_startup) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (config_client_) {
-    config_client_->SetEnabled(enabled);
-    if (enabled)
-      config_client_->RetrieveConfig();
-  }
-
-  // If Data Saver is disabled, reset data reduction proxy state.
-  if (!enabled) {
-    for (auto& client : proxy_config_clients_)
-      client->ClearBadProxiesCache();
-  }
-}
-
-net::EffectiveConnectionType
-DataReductionProxyService::GetEffectiveConnectionType() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return effective_connection_type_;
-}
-
-network::mojom::ConnectionType DataReductionProxyService::GetConnectionType()
-    const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return connection_type_;
-}
-
-base::Optional<base::TimeDelta> DataReductionProxyService::GetHttpRttEstimate()
-    const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return http_rtt_;
-}
 
 void DataReductionProxyService::UpdateProxyRequestHeaders(
     const net::HttpRequestHeaders& headers) {
@@ -288,20 +166,6 @@
   settings_->SetProxyRequestHeaders(headers);
 }
 
-void DataReductionProxyService::UpdatePrefetchProxyHosts(
-    const std::vector<GURL>& prefetch_proxies) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  settings_->UpdatePrefetchProxyHosts(std::move(prefetch_proxies));
-}
-
-void DataReductionProxyService::OnProxyConfigUpdated() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-void DataReductionProxyService::AddCustomProxyConfigClient(
-    mojo::Remote<network::mojom::CustomProxyConfigClient> config_client) {
-  proxy_config_clients_.Add(std::move(config_client));
-}
 
 void DataReductionProxyService::LoadHistoricalDataUsage(
     HistoricalDataUsageCallback load_data_usage_callback) {
@@ -378,27 +242,12 @@
   }
 }
 
-void DataReductionProxyService::StoreSerializedConfig(
-    const std::string& serialized_config) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(params::ForceEnableClientConfigServiceForAllDataSaverUsers());
-  SetStringPref(prefs::kDataReductionProxyConfig, serialized_config);
-  SetInt64Pref(prefs::kDataReductionProxyLastConfigRetrievalTime,
-               (base::Time::Now() - base::Time()).InMicroseconds());
-}
-
 void DataReductionProxyService::SetDependenciesForTesting(
-    std::unique_ptr<DataReductionProxyRequestOptions> request_options,
-    std::unique_ptr<DataReductionProxyConfigServiceClient> config_client) {
+    std::unique_ptr<DataReductionProxyRequestOptions> request_options) {
   request_options_ = std::move(request_options);
   request_options_->SetUpdateHeaderCallback(
       base::BindRepeating(&DataReductionProxyService::UpdateProxyRequestHeaders,
                           base::Unretained(this)));
-
-  config_client_ = std::move(config_client);
-
-  if (config_client_)
-    config_client_->Initialize(url_loader_factory_);
 }
 
 double DataReductionProxyService::GetSaveDataSavingsPercentEstimate(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
index 6a6ebc0..81d5adad 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
@@ -21,15 +21,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h"
 #include "components/data_reduction_proxy/core/browser/db_data_owner.h"
 #include "components/data_use_measurement/core/data_use_measurement.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
-#include "mojo/public/cpp/bindings/remote_set.h"
 #include "net/nqe/effective_connection_type.h"
-#include "services/network/public/cpp/network_connection_tracker.h"
-#include "services/network/public/cpp/network_quality_tracker.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/public/mojom/network_context.mojom.h"
 
 class PrefService;
 
@@ -45,17 +37,13 @@
 namespace data_reduction_proxy {
 
 class DataReductionProxyCompressionStats;
-class DataReductionProxyConfigServiceClient;
 class DataReductionProxyRequestOptions;
 class DataReductionProxySettings;
 
 // Contains and initializes all Data Reduction Proxy objects that have a
 // lifetime based on the UI thread.
 class DataReductionProxyService
-    : public data_use_measurement::DataUseMeasurement::ServicesDataUseObserver,
-      public network::NetworkQualityTracker::EffectiveConnectionTypeObserver,
-      public network::NetworkQualityTracker::RTTAndThroughputEstimatesObserver,
-      public network::NetworkConnectionTracker::NetworkConnectionObserver {
+    : public data_use_measurement::DataUseMeasurement::ServicesDataUseObserver {
  public:
   // The caller must ensure that |settings|, |prefs|, |request_context|, and
   // |io_task_runner| remain alive for the lifetime of the
@@ -66,10 +54,7 @@
   DataReductionProxyService(
       DataReductionProxySettings* settings,
       PrefService* prefs,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       std::unique_ptr<DataStore> store,
-      network::NetworkQualityTracker* network_quality_tracker,
-      network::NetworkConnectionTracker* network_connection_tracker,
       data_use_measurement::DataUseMeasurement* data_use_measurement,
       const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
       const base::TimeDelta& commit_delay,
@@ -77,7 +62,7 @@
       const std::string& channel,
       const std::string& user_agent);
 
-  ~DataReductionProxyService() override;
+  virtual ~DataReductionProxyService();
 
   void Shutdown();
 
@@ -108,10 +93,6 @@
   // Stores a string value in |prefs_|.
   void SetStringPref(const std::string& pref_path, const std::string& value);
 
-  // Bridge methods to safely call to the UI thread objects.
-  // Virtual for testing.
-  virtual void SetProxyPrefs(bool enabled, bool at_startup);
-
   void LoadHistoricalDataUsage(
       HistoricalDataUsageCallback load_data_usage_callback);
   void LoadCurrentDataUsageBucket(
@@ -124,23 +105,9 @@
     settings_ = settings;
   }
 
-  // Returns the current network quality estimates.
-  net::EffectiveConnectionType GetEffectiveConnectionType() const;
-  base::Optional<base::TimeDelta> GetHttpRttEstimate() const;
-
-  network::mojom::ConnectionType GetConnectionType() const;
-
   // Sends the given |headers| to |DataReductionProxySettings|.
   void UpdateProxyRequestHeaders(const net::HttpRequestHeaders& headers);
 
-  // Sends the given |prefetch_proxies| to |DataReductionProxySettings|.
-  void UpdatePrefetchProxyHosts(const std::vector<GURL>& prefetch_proxies);
-
-  // Adds a config client that can be used to update Data Reduction Proxy
-  // settings.
-  void AddCustomProxyConfigClient(
-      mojo::Remote<network::mojom::CustomProxyConfigClient> config_client);
-
   // Returns the percentage of data savings estimate provided by save-data for
   // an origin.
   double GetSaveDataSavingsPercentEstimate(const std::string& origin) const;
@@ -150,16 +117,6 @@
     return compression_stats_.get();
   }
 
-  std::unique_ptr<network::PendingSharedURLLoaderFactory>
-  pending_url_loader_factory() const {
-    return url_loader_factory_->Clone();
-  }
-
-
-  DataReductionProxyConfigServiceClient* config_client() const {
-    return config_client_.get();
-  }
-
   DataReductionProxyRequestOptions* request_options() const {
     return request_options_.get();
   }
@@ -177,8 +134,7 @@
   }
 
   void SetDependenciesForTesting(
-      std::unique_ptr<DataReductionProxyRequestOptions> request_options,
-      std::unique_ptr<DataReductionProxyConfigServiceClient> config_client);
+      std::unique_ptr<DataReductionProxyRequestOptions> request_options);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigServiceClientTest,
@@ -186,33 +142,10 @@
   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigServiceClientTest,
                            ValidatePersistedClientConfig);
 
-  void OnEffectiveConnectionTypeChanged(
-      net::EffectiveConnectionType type) override;
-
-  void OnRTTOrThroughputEstimatesComputed(
-      base::TimeDelta http_rtt,
-      base::TimeDelta transport_rtt,
-      int32_t downstream_throughput_kbps) override;
-
-  // Loads the Data Reduction Proxy configuration from |prefs_| and applies it.
-  void ReadPersistedClientConfig();
-
   void OnServicesDataUse(int32_t service_hash_code,
                          int64_t recv_bytes,
                          int64_t sent_bytes) override;
 
-  // NetworkConnectionTracker::NetworkConnectionObserver
-  void OnConnectionChanged(network::mojom::ConnectionType type) override;
-
-  // Called when the list of proxies changes.
-  void OnProxyConfigUpdated();
-
-  // Stores a serialized Data Reduction Proxy configuration in preferences
-  // storage.
-  void StoreSerializedConfig(const std::string& serialized_config);
-
-  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
-
   // Tracks compression statistics to be displayed to the user.
   std::unique_ptr<DataReductionProxyCompressionStats> compression_stats_;
 
@@ -228,20 +161,8 @@
 
   // Must be accessed on UI thread. Guaranteed to be non-null during the
   // lifetime of |this|.
-  network::NetworkQualityTracker* network_quality_tracker_;
-  network::NetworkConnectionTracker* network_connection_tracker_;
-
-  // Must be accessed on UI thread. Guaranteed to be non-null during the
-  // lifetime of |this|.
   data_use_measurement::DataUseMeasurement* data_use_measurement_;
 
-  // Current network quality estimates.
-  net::EffectiveConnectionType effective_connection_type_;
-  base::Optional<base::TimeDelta> http_rtt_;
-
-  network::mojom::ConnectionType connection_type_ =
-      network::mojom::ConnectionType::CONNECTION_UNKNOWN;
-
   // The type of Data Reduction Proxy client.
   const Client client_;
 
@@ -249,19 +170,12 @@
   // Constructs credentials suitable for authenticating the client.
   std::unique_ptr<DataReductionProxyRequestOptions> request_options_;
 
-  // Requests new Data Reduction Proxy configurations from a remote service.
-  // May be null.
-  std::unique_ptr<DataReductionProxyConfigServiceClient> config_client_;
-
   // The production channel of this build.
   const std::string channel_;
 
   // Dictionary of save-data savings estimates by origin.
   const base::Optional<base::Value> save_data_savings_estimate_dict_;
 
-  // The set of clients that will get updates about changes to the proxy config.
-  mojo::RemoteSet<network::mojom::CustomProxyConfigClient>
-      proxy_config_clients_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service_unittest.cc
deleted file mode 100644
index 790e445..0000000
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service_unittest.cc
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
-
-#include <stddef.h>
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/metrics/field_trial.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/test/task_environment.h"
-#include "base/time/default_clock.h"
-#include "base/time/time.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/testing_pref_service.h"
-#include "net/proxy_resolution/proxy_info.h"
-#include "net/proxy_resolution/proxy_resolution_service.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "services/network/test/test_network_connection_tracker.h"
-#include "services/network/test/test_network_quality_tracker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace data_reduction_proxy {
-namespace {
-
-std::string CreateEncodedConfig() {
-  ClientConfig config;
-  config.set_session_key("session");
-  return EncodeConfig(config);
-}
-}  // namespace
-
-class DataReductionProxyServiceTest : public testing::Test {
- public:
-  void SetUp() override {
-    RegisterSimpleProfilePrefs(prefs_.registry());
-  }
-
-  void RequestCallback(int err) {}
-
-  PrefService* prefs() { return &prefs_; }
-
- private:
-  base::test::TaskEnvironment task_environment_;
-  TestingPrefServiceSimple prefs_;
-};
-
-class TestCustomProxyConfigClient
-    : public network::mojom::CustomProxyConfigClient {
- public:
-  TestCustomProxyConfigClient(
-      mojo::PendingReceiver<network::mojom::CustomProxyConfigClient>
-          pending_receiver)
-      : receiver_(this, std::move(pending_receiver)) {}
-
-  // network::mojom::CustomProxyConfigClient implementation:
-  void OnCustomProxyConfigUpdated(
-      network::mojom::CustomProxyConfigPtr proxy_config) override {
-    config = std::move(proxy_config);
-  }
-
-  void MarkProxiesAsBad(base::TimeDelta bypass_duration,
-                        const net::ProxyList& bad_proxies,
-                        MarkProxiesAsBadCallback callback) override {}
-
-  void ClearBadProxiesCache() override { num_clear_cache_calls++; }
-
-  network::mojom::CustomProxyConfigPtr config;
-  int num_clear_cache_calls = 0;
-
- private:
-  mojo::Receiver<network::mojom::CustomProxyConfigClient> receiver_;
-};
-
-TEST_F(DataReductionProxyServiceTest, TestResetBadProxyListOnDisableDataSaver) {
-  std::unique_ptr<DataReductionProxyTestContext> drp_test_context =
-      DataReductionProxyTestContext::Builder()
-          .SkipSettingsInitialization()
-          .Build();
-
-  drp_test_context->SetDataReductionProxyEnabled(true);
-  drp_test_context->InitSettings();
-
-  mojo::Remote<network::mojom::CustomProxyConfigClient> client_remote;
-  TestCustomProxyConfigClient client(
-      client_remote.BindNewPipeAndPassReceiver());
-  drp_test_context->data_reduction_proxy_service()->AddCustomProxyConfigClient(
-      std::move(client_remote));
-  base::RunLoop().RunUntilIdle();
-
-  // Turn Data Saver off.
-  drp_test_context->SetDataReductionProxyEnabled(false);
-  base::RunLoop().RunUntilIdle();
-
-  // Verify that the bad proxy cache was cleared.
-  EXPECT_EQ(1, client.num_clear_cache_calls);
-}
-
-
-
-TEST_F(DataReductionProxyServiceTest, TestCustomProxyConfigUpdatedOnECTChange) {
-  std::unique_ptr<DataReductionProxyTestContext> drp_test_context =
-      DataReductionProxyTestContext::Builder().Build();
-  drp_test_context->SetDataReductionProxyEnabled(true);
-  drp_test_context->test_network_quality_tracker()
-      ->ReportEffectiveConnectionTypeForTesting(
-          net::EFFECTIVE_CONNECTION_TYPE_4G);
-
-  mojo::Remote<network::mojom::CustomProxyConfigClient> client_remote;
-  TestCustomProxyConfigClient client(
-      client_remote.BindNewPipeAndPassReceiver());
-  drp_test_context->data_reduction_proxy_service()->AddCustomProxyConfigClient(
-      std::move(client_remote));
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_FALSE(client.config);
-}
-
-TEST_F(DataReductionProxyServiceTest,
-       TestCustomProxyConfigUpdatedOnHeaderChange) {
-  std::unique_ptr<DataReductionProxyTestContext> drp_test_context =
-      DataReductionProxyTestContext::Builder().Build();
-  drp_test_context->SetDataReductionProxyEnabled(true);
-  DataReductionProxyService* service =
-      drp_test_context->data_reduction_proxy_service();
-
-  mojo::Remote<network::mojom::CustomProxyConfigClient> client_remote;
-  TestCustomProxyConfigClient client(
-      client_remote.BindNewPipeAndPassReceiver());
-  service->AddCustomProxyConfigClient(std::move(client_remote));
-  base::RunLoop().RunUntilIdle();
-
-  std::string value;
-  ASSERT_FALSE(client.config);
-}
-
-TEST_F(DataReductionProxyServiceTest,
-       TestCustomProxyConfigUpdatedOnProxyChange) {
-  std::unique_ptr<DataReductionProxyTestContext> drp_test_context =
-      DataReductionProxyTestContext::Builder().WithConfigClient().Build();
-  drp_test_context->SetDataReductionProxyEnabled(true);
-  DataReductionProxyService* service =
-      drp_test_context->data_reduction_proxy_service();
-
-  auto proxy_server1 = net::ProxyServer::FromPacString("PROXY foo");
-  service->config_client()->ApplySerializedConfig(CreateEncodedConfig());
-
-  mojo::Remote<network::mojom::CustomProxyConfigClient> client_remote;
-  TestCustomProxyConfigClient client(
-      client_remote.BindNewPipeAndPassReceiver());
-  service->AddCustomProxyConfigClient(std::move(client_remote));
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_FALSE(client.config);
-}
-
-TEST_F(DataReductionProxyServiceTest,
-       TestCustomProxyConfigHasAlternateProxyListOfCoreProxies) {
-  std::unique_ptr<DataReductionProxyTestContext> drp_test_context =
-      DataReductionProxyTestContext::Builder().WithConfigClient().Build();
-  drp_test_context->SetDataReductionProxyEnabled(true);
-  DataReductionProxyService* service =
-      drp_test_context->data_reduction_proxy_service();
-
-  auto core_proxy_server = net::ProxyServer::FromPacString("PROXY foo");
-  auto second_proxy_server = net::ProxyServer::FromPacString("PROXY bar");
-  service->config_client()->ApplySerializedConfig(CreateEncodedConfig());
-
-  mojo::Remote<network::mojom::CustomProxyConfigClient> client_remote;
-  TestCustomProxyConfigClient client(
-      client_remote.BindNewPipeAndPassReceiver());
-  service->AddCustomProxyConfigClient(std::move(client_remote));
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_FALSE(client.config);
-}
-
-TEST_F(DataReductionProxyServiceTest, TestCustomProxyConfigProperties) {
-  std::unique_ptr<DataReductionProxyTestContext> drp_test_context =
-      DataReductionProxyTestContext::Builder().Build();
-  drp_test_context->SetDataReductionProxyEnabled(true);
-  DataReductionProxyService* service =
-      drp_test_context->data_reduction_proxy_service();
-
-  mojo::Remote<network::mojom::CustomProxyConfigClient> client_remote;
-  TestCustomProxyConfigClient client(
-      client_remote.BindNewPipeAndPassReceiver());
-  service->AddCustomProxyConfigClient(std::move(client_remote));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_FALSE(client.config);
-}
-
-}  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
index 72977eb..67659c9 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
@@ -89,12 +89,6 @@
 
   for (auto& observer : observers_)
     observer.OnSettingsInitialized();
-
-  while (!proxy_config_clients_.empty()) {
-    data_reduction_proxy_service_->AddCustomProxyConfigClient(
-        std::move(proxy_config_clients_.back()));
-    proxy_config_clients_.pop_back();
-  }
 }
 
 void DataReductionProxySettings::SetCallbackToRegisterSyntheticFieldTrial(
@@ -279,9 +273,6 @@
       RecordSettingsEnabledState(DATA_REDUCTION_SETTINGS_ACTION_ON_TO_OFF);
     }
   }
-
-  data_reduction_proxy_service_->SetProxyPrefs(IsDataReductionProxyEnabled(),
-                                               at_startup);
 }
 
 const net::HttpRequestHeaders&
@@ -298,22 +289,6 @@
     observer.OnProxyRequestHeadersChanged(headers);
 }
 
-const std::vector<GURL>& DataReductionProxySettings::GetPrefetchProxies()
-    const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  return prefetch_proxies_;
-}
-
-void DataReductionProxySettings::UpdatePrefetchProxyHosts(
-    const std::vector<GURL>& prefetch_proxies) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  prefetch_proxies_ = prefetch_proxies;
-  for (auto& observer : observers_)
-    observer.OnPrefetchProxyHostsChanged(prefetch_proxies);
-  LOCAL_HISTOGRAM_BOOLEAN("DataReductionProxy.Settings.ConfigReceived", true);
-}
-
-
 void DataReductionProxySettings::AddDataReductionProxySettingsObserver(
     DataReductionProxySettingsObserver* observer) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -326,17 +301,6 @@
   observers_.RemoveObserver(observer);
 }
 
-void DataReductionProxySettings::AddCustomProxyConfigClient(
-    mojo::Remote<network::mojom::CustomProxyConfigClient> proxy_config_client) {
-  if (data_reduction_proxy_service_) {
-    data_reduction_proxy_service_->AddCustomProxyConfigClient(
-        std::move(proxy_config_client));
-    return;
-  }
-
-  proxy_config_clients_.push_back(std::move(proxy_config_client));
-}
-
 // Metrics methods
 void DataReductionProxySettings::RecordDataReductionInit() const {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
index 7c87ba0..f505cd3 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
@@ -21,9 +21,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_member.h"
-#include "mojo/public/cpp/bindings/remote.h"
 #include "net/http/http_request_headers.h"
-#include "services/network/public/mojom/network_context.mojom.h"
 #include "url/gurl.h"
 
 class PrefService;
@@ -166,15 +164,9 @@
   // Sets the headers to use for requests to the compression server.
   void SetProxyRequestHeaders(const net::HttpRequestHeaders& headers);
 
-  // Sets the list of prefetch_proxies to use.
-  void UpdatePrefetchProxyHosts(const std::vector<GURL>& prefetch_proxies);
-
   // Returns headers to use for requests to the compression server.
   const net::HttpRequestHeaders& GetProxyRequestHeaders() const;
 
-  // Returns the list of hosts for the prefetch proxy.
-  const std::vector<GURL>& GetPrefetchProxies() const;
-
   // Returns the time LiteMode was last enabled. This is reset whenever LiteMode
   // is disabled and re-enabled from settings. Null time is returned when
   // LiteMode has never been enabled.
@@ -190,12 +182,6 @@
   void RemoveDataReductionProxySettingsObserver(
       DataReductionProxySettingsObserver* observer);
 
-  // Addds a config client that can be used to update Data Reduction Proxy
-  // settings.
-  void AddCustomProxyConfigClient(
-      mojo::Remote<network::mojom::CustomProxyConfigClient>
-          proxy_config_client);
-
   DataReductionProxyService* data_reduction_proxy_service() {
     return data_reduction_proxy_service_.get();
   }
@@ -293,14 +279,6 @@
   // The headers to use for requests to the proxy server.
   net::HttpRequestHeaders proxy_request_headers_;
 
-  // The list of prefetch proxy hosts to use.
-  std::vector<GURL> prefetch_proxies_;
-
-  // A list of CustomProxyConfigClients that may have been added before
-  // the DataReductionProxyService was available.
-  std::vector<mojo::Remote<network::mojom::CustomProxyConfigClient>>
-      proxy_config_clients_;
-
   // True if |this| was constructed for an off-the-record profile.
   const bool is_off_the_record_profile_;
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
index 9472f54..e793d1c 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
@@ -94,21 +94,10 @@
 template void DataReductionProxySettingsTestBase::ResetSettings<
     DataReductionProxySettings>(base::Clock* clock);
 
-void DataReductionProxySettingsTestBase::ExpectSetProxyPrefs(
-    bool expected_enabled,
-    bool expected_at_startup) {
-  MockDataReductionProxyService* mock_service =
-      static_cast<MockDataReductionProxyService*>(
-          settings_->data_reduction_proxy_service());
-  EXPECT_CALL(*mock_service,
-              SetProxyPrefs(expected_enabled, expected_at_startup));
-}
-
 void DataReductionProxySettingsTestBase::CheckOnPrefChange(
     bool enabled,
     bool expected_enabled,
     bool managed) {
-  ExpectSetProxyPrefs(expected_enabled, false);
   if (managed) {
     test_context_->pref_service()->SetManagedPref(
         prefs::kDataSaverEnabled, std::make_unique<base::Value>(enabled));
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h
index 1fc4874..913e8209 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h
@@ -50,9 +50,6 @@
   void ResetSettings(base::Clock* clock);
   virtual void ResetSettings(base::Clock* clock) = 0;
 
-  void ExpectSetProxyPrefs(bool expected_enabled,
-                           bool expected_at_startup);
-
   void CheckMaybeActivateDataReductionProxy(bool initially_enabled,
                                             bool request_succeeded,
                                             bool expected_enabled,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
index ff631ad..d38d2184 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
@@ -44,7 +44,6 @@
                                             bool expected_restricted,
                                             bool expected_fallback_restricted) {
     test_context_->SetDataReductionProxyEnabled(initially_enabled);
-    ExpectSetProxyPrefs(expected_enabled, false);
     settings_->MaybeActivateDataReductionProxy(false);
     test_context_->RunUntilIdle();
   }
@@ -113,30 +112,6 @@
   EXPECT_EQ(expected_total_received_content_length, received_content_length);
 }
 
-TEST(DataReductionProxySettingsStandaloneTest, TestOnProxyEnabledPrefChange) {
-  base::test::SingleThreadTaskEnvironment task_environment{
-      base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
-  std::unique_ptr<DataReductionProxyTestContext> drp_test_context =
-      DataReductionProxyTestContext::Builder()
-          .WithMockConfig()
-          .WithMockDataReductionProxyService()
-          .SkipSettingsInitialization()
-          .Build();
-
-  drp_test_context->InitSettings();
-
-  MockDataReductionProxyService* mock_service =
-      static_cast<MockDataReductionProxyService*>(
-          drp_test_context->data_reduction_proxy_service());
-
-  // The pref is disabled, so correspondingly should be the proxy.
-  EXPECT_CALL(*mock_service, SetProxyPrefs(false, false));
-  drp_test_context->SetDataReductionProxyEnabled(false);
-
-  // The pref is enabled, so correspondingly should be the proxy.
-  EXPECT_CALL(*mock_service, SetProxyPrefs(true, false));
-  drp_test_context->SetDataReductionProxyEnabled(true);
-}
 
 TEST(DataReductionProxySettingsStandaloneTest, TestIsProxyEnabledOrManaged) {
   base::test::SingleThreadTaskEnvironment task_environment{
@@ -175,40 +150,6 @@
   drp_test_context->RunUntilIdle();
 }
 
-TEST(DataReductionProxySettingsStandaloneTest, TestCanUseDataReductionProxy) {
-  base::test::SingleThreadTaskEnvironment task_environment{
-      base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
-  std::unique_ptr<DataReductionProxyTestContext> drp_test_context =
-      DataReductionProxyTestContext::Builder()
-          .WithMockConfig()
-          .WithMockDataReductionProxyService()
-          .SkipSettingsInitialization()
-          .Build();
-
-  drp_test_context->InitSettings();
-
-  MockDataReductionProxyService* mock_service =
-      static_cast<MockDataReductionProxyService*>(
-          drp_test_context->data_reduction_proxy_service());
-
-  DataReductionProxySettings* settings = drp_test_context->settings();
-  GURL http_gurl("http://url.com/");
-  GURL https_gurl("https://url.com/");
-
-  // The pref is disabled, so correspondingly should be the proxy.
-  EXPECT_CALL(*mock_service, SetProxyPrefs(false, false));
-  drp_test_context->SetDataReductionProxyEnabled(false);
-  EXPECT_FALSE(settings->CanUseDataReductionProxy(http_gurl));
-  EXPECT_FALSE(settings->CanUseDataReductionProxy(https_gurl));
-
-  // The pref is enabled, so correspondingly should be the proxy.
-  EXPECT_CALL(*mock_service, SetProxyPrefs(true, false));
-  drp_test_context->SetDataReductionProxyEnabled(true);
-  EXPECT_TRUE(settings->CanUseDataReductionProxy(http_gurl));
-  EXPECT_FALSE(settings->CanUseDataReductionProxy(https_gurl));
-
-  drp_test_context->RunUntilIdle();
-}
 
 TEST_F(DataReductionProxySettingsTest, TestMaybeActivateDataReductionProxy) {
   // Initialize the pref member in |settings_| without the usual callback
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
index 5e81210..ef68661 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
@@ -14,7 +14,6 @@
 #include "base/run_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
 #include "components/data_reduction_proxy/core/browser/data_store.h"
@@ -27,10 +26,8 @@
 #include "net/proxy_resolution/proxy_config.h"
 #include "net/proxy_resolution/proxy_info.h"
 #include "net/proxy_resolution/proxy_list.h"
-#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_network_connection_tracker.h"
 #include "services/network/test/test_network_quality_tracker.h"
-#include "services/network/test/test_url_loader_factory.h"
 #include "url/gurl.h"
 
 namespace {
@@ -54,14 +51,6 @@
 
 const char kTestKey[] = "test-key";
 
-net::BackoffEntry::Policy kTestBackoffPolicy;
-
-const net::BackoffEntry::Policy& GetTestBackoffPolicy() {
-  kTestBackoffPolicy = data_reduction_proxy::GetBackoffPolicy();
-  // Remove jitter to bring certainty in the tests.
-  kTestBackoffPolicy.jitter_factor = 0;
-  return kTestBackoffPolicy;
-}
 
 }  // namespace
 
@@ -82,128 +71,15 @@
 
 MockDataReductionProxyRequestOptions::~MockDataReductionProxyRequestOptions() {}
 
-TestDataReductionProxyConfigServiceClient::
-    TestDataReductionProxyConfigServiceClient(
-        DataReductionProxyRequestOptions* request_options,
-        DataReductionProxyService* service,
-        network::NetworkConnectionTracker* network_connection_tracker,
-        ConfigStorer config_storer,
-        const net::BackoffEntry::Policy& backoff_policy)
-    : DataReductionProxyConfigServiceClient(backoff_policy,
-                                            request_options,
-                                            service,
-                                            network_connection_tracker,
-                                            config_storer),
-#if defined(OS_ANDROID)
-      is_application_state_background_(false),
-#endif
-      tick_clock_(base::Time::UnixEpoch()),
-      test_backoff_entry_(&backoff_policy, &tick_clock_) {
-}
-
-TestDataReductionProxyConfigServiceClient::
-    ~TestDataReductionProxyConfigServiceClient() {}
-
-void TestDataReductionProxyConfigServiceClient::SetNow(const base::Time& time) {
-  tick_clock_.SetTime(time);
-}
-
-void TestDataReductionProxyConfigServiceClient::SetCustomReleaseTime(
-    const base::TimeTicks& release_time) {
-  test_backoff_entry_.SetCustomReleaseTime(release_time);
-}
-
-base::TimeDelta TestDataReductionProxyConfigServiceClient::GetDelay() const {
-  return config_refresh_timer_.GetCurrentDelay();
-}
-
-base::TimeDelta
-TestDataReductionProxyConfigServiceClient::GetBackoffTimeUntilRelease() const {
-  return test_backoff_entry_.GetTimeUntilRelease();
-}
-
-int TestDataReductionProxyConfigServiceClient::GetBackoffErrorCount() {
-  return test_backoff_entry_.failure_count();
-}
-
-void TestDataReductionProxyConfigServiceClient::SetConfigServiceURL(
-    const GURL& service_url) {
-  config_service_url_ = service_url;
-}
-
-int32_t
-TestDataReductionProxyConfigServiceClient::failed_attempts_before_success()
-    const {
-  return failed_attempts_before_success_;
-}
-
-base::Time TestDataReductionProxyConfigServiceClient::Now() {
-  return tick_clock_.Now();
-}
-
-net::BackoffEntry*
-TestDataReductionProxyConfigServiceClient::GetBackoffEntry() {
-  return &test_backoff_entry_;
-}
-
-TestDataReductionProxyConfigServiceClient::TestTickClock::TestTickClock(
-    const base::Time& initial_time)
-    : time_(initial_time) {}
-
-base::TimeTicks
-TestDataReductionProxyConfigServiceClient::TestTickClock::NowTicks() const {
-  return base::TimeTicks::UnixEpoch() + (time_ - base::Time::UnixEpoch());
-}
-
-base::Time TestDataReductionProxyConfigServiceClient::TestTickClock::Now()
-    const {
-  return time_;
-}
-
-void TestDataReductionProxyConfigServiceClient::TestTickClock::SetTime(
-    const base::Time& time) {
-  time_ = time;
-}
-
-#if defined(OS_ANDROID)
-bool TestDataReductionProxyConfigServiceClient::IsApplicationStateBackground()
-    const {
-  return is_application_state_background_;
-}
-
-void TestDataReductionProxyConfigServiceClient::
-    TriggerApplicationStatusToForeground() {
-  OnApplicationStateChange(
-      base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
-}
-#endif  // OS_ANDROID
-
-void TestDataReductionProxyConfigServiceClient::SetRemoteConfigApplied(
-    bool remote_config_applied) {
-  remote_config_applied_ = remote_config_applied;
-}
-
-bool TestDataReductionProxyConfigServiceClient::RemoteConfigApplied() const {
-  if (!remote_config_applied_) {
-    return DataReductionProxyConfigServiceClient::RemoteConfigApplied();
-  }
-  return remote_config_applied_.value();
-}
-
 MockDataReductionProxyService::MockDataReductionProxyService(
     data_use_measurement::DataUseMeasurement* data_use_measurement,
     DataReductionProxySettings* settings,
-    network::TestNetworkQualityTracker* test_network_quality_tracker,
     PrefService* prefs,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
     : DataReductionProxyService(
           settings,
           prefs,
-          std::move(url_loader_factory),
           std::make_unique<TestDataStore>(),
-          test_network_quality_tracker,
-          network::TestNetworkConnectionTracker::GetInstance(),
           data_use_measurement,
           task_runner,
           base::TimeDelta(),
@@ -217,16 +93,11 @@
     data_use_measurement::DataUseMeasurement* data_use_measurement,
     DataReductionProxySettings* settings,
     PrefService* prefs,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    network::NetworkQualityTracker* network_quality_tracker,
     const scoped_refptr<base::SequencedTaskRunner>& db_task_runner)
     : DataReductionProxyService(
           settings,
           prefs,
-          url_loader_factory,
           std::make_unique<TestDataStore>(),
-          network_quality_tracker,
-          network::TestNetworkConnectionTracker::GetInstance(),
           data_use_measurement,
           db_task_runner,
           base::TimeDelta(),
@@ -275,8 +146,6 @@
       use_mock_config_(false),
       use_mock_service_(false),
       use_mock_request_options_(false),
-      use_config_client_(false),
-      use_test_config_client_(false),
       skip_settings_initialization_(false),
       data_use_measurement_(
           std::make_unique<data_use_measurement::DataUseMeasurement>(
@@ -286,13 +155,6 @@
 DataReductionProxyTestContext::Builder::~Builder() {}
 
 DataReductionProxyTestContext::Builder&
-DataReductionProxyTestContext::Builder::WithURLLoaderFactory(
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
-  url_loader_factory_ = url_loader_factory;
-  return *this;
-}
-
-DataReductionProxyTestContext::Builder&
 DataReductionProxyTestContext::Builder::WithClient(Client client) {
   client_ = client;
   return *this;
@@ -317,19 +179,6 @@
 }
 
 DataReductionProxyTestContext::Builder&
-DataReductionProxyTestContext::Builder::WithConfigClient() {
-  use_config_client_ = true;
-  return *this;
-}
-
-DataReductionProxyTestContext::Builder&
-DataReductionProxyTestContext::Builder::WithTestConfigClient() {
-  use_config_client_ = true;
-  use_test_config_client_ = true;
-  return *this;
-}
-
-DataReductionProxyTestContext::Builder&
 DataReductionProxyTestContext::Builder::SkipSettingsInitialization() {
   skip_settings_initialization_ = true;
   return *this;
@@ -344,36 +193,13 @@
 
 std::unique_ptr<DataReductionProxyTestContext>
 DataReductionProxyTestContext::Builder::Build() {
-  // Check for invalid builder combinations.
-  DCHECK(!(use_mock_config_ && use_config_client_));
-
   unsigned int test_context_flags = 0;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       base::ThreadTaskRunnerHandle::Get();
-  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory;
   std::unique_ptr<TestingPrefServiceSimple> pref_service(
       new TestingPrefServiceSimple());
-  auto* test_network_connection_tracker =
-      network::TestNetworkConnectionTracker::GetInstance();
-  std::unique_ptr<TestConfigStorer> config_storer(
-      new TestConfigStorer(pref_service.get()));
 
-  // In case no |url_loader_factory_| is specified, an instance will be
-  // created in DataReductionProxyTestContext's ctor.
-  std::unique_ptr<network::TestURLLoaderFactory> test_url_loader_factory;
-  if (url_loader_factory_) {
-    url_loader_factory = url_loader_factory_;
-  } else {
-    test_url_loader_factory = std::make_unique<network::TestURLLoaderFactory>();
-    url_loader_factory =
-        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-            test_url_loader_factory.get());
-  }
-
-  std::unique_ptr<DataReductionProxyConfigServiceClient> config_client;
-  if (use_config_client_) {
-    test_context_flags |= USE_CONFIG_CLIENT;
-  } else if (use_mock_config_) {
+  if (use_mock_config_) {
     test_context_flags |= USE_MOCK_CONFIG;
   } else {
     test_context_flags ^= USE_MOCK_CONFIG;
@@ -399,46 +225,25 @@
                                                 false);
   RegisterSimpleProfilePrefs(pref_service->registry());
 
-  auto test_network_quality_tracker =
-      std::make_unique<network::TestNetworkQualityTracker>();
   std::unique_ptr<DataReductionProxyService> service;
   if (use_mock_service_) {
     test_context_flags |= USE_MOCK_SERVICE;
     service = std::make_unique<MockDataReductionProxyService>(
-        data_use_measurement_.get(), settings_.get(),
-        test_network_quality_tracker.get(), pref_service.get(),
-        url_loader_factory, task_runner);
+        data_use_measurement_.get(), settings_.get(), pref_service.get(),
+        task_runner);
   } else {
     service = std::make_unique<TestDataReductionProxyService>(
         data_use_measurement_.get(), settings_.get(), pref_service.get(),
-        url_loader_factory, test_network_quality_tracker.get(), task_runner);
+        task_runner);
   }
 
-  if (use_test_config_client_) {
-    test_context_flags |= USE_TEST_CONFIG_CLIENT;
-    config_client.reset(new TestDataReductionProxyConfigServiceClient(
-        request_options.get(), service.get(), test_network_connection_tracker,
-        base::BindRepeating(&TestConfigStorer::StoreSerializedConfig,
-                            base::Unretained(config_storer.get())),
-        GetTestBackoffPolicy()));
-  } else if (use_config_client_) {
-    config_client.reset(new DataReductionProxyConfigServiceClient(
-        GetBackoffPolicy(), request_options.get(), service.get(),
-        test_network_connection_tracker,
-        base::BindRepeating(&TestConfigStorer::StoreSerializedConfig,
-                            base::Unretained(config_storer.get()))));
-  }
-
-  service->SetDependenciesForTesting(std::move(request_options),
-                                     std::move(config_client));
+  service->SetDependenciesForTesting(std::move(request_options));
 
   std::unique_ptr<DataReductionProxyTestContext> test_context(
       new DataReductionProxyTestContext(
           std::move(data_use_measurement_), task_runner,
-          std::move(pref_service), url_loader_factory,
-          std::move(test_url_loader_factory), std::move(settings_),
-          std::move(service), std::move(test_network_quality_tracker),
-          std::move(config_storer), test_context_flags));
+          std::move(pref_service), std::move(settings_), std::move(service),
+          test_context_flags));
 
   if (!skip_settings_initialization_)
     test_context->InitSettingsWithoutCheck();
@@ -451,24 +256,15 @@
         data_use_measurement,
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     std::unique_ptr<TestingPrefServiceSimple> simple_pref_service,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    std::unique_ptr<network::TestURLLoaderFactory> test_url_loader_factory,
     std::unique_ptr<DataReductionProxySettings> settings,
     std::unique_ptr<DataReductionProxyService> service,
-    std::unique_ptr<network::TestNetworkQualityTracker>
-        test_network_quality_tracker,
-    std::unique_ptr<TestConfigStorer> config_storer,
     unsigned int test_context_flags)
     : data_use_measurement_(std::move(data_use_measurement)),
       test_context_flags_(test_context_flags),
       task_runner_(task_runner),
       simple_pref_service_(std::move(simple_pref_service)),
-      test_shared_url_loader_factory_(url_loader_factory),
-      test_url_loader_factory_(std::move(test_url_loader_factory)),
       settings_(std::move(settings)),
-      test_network_quality_tracker_(std::move(test_network_quality_tracker)),
-      service_(std::move(service)),
-      config_storer_(std::move(config_storer)) {
+      service_(std::move(service)) {
   DCHECK(data_use_measurement_);
 
   if (service_)
@@ -541,10 +337,6 @@
   // check.
   DCHECK(data_reduction_proxy_service());
 
-  // This method should be called in case DataReductionProxyTestContext is
-  // constructed without a valid SharedURLLoaderFactory instance.
-  DCHECK(test_url_loader_factory_);
-
   // Set the pref to cause the secure proxy check to be issued.
   SetDataReductionProxyEnabled(true);
   RunUntilIdle();
@@ -579,24 +371,4 @@
       data_reduction_proxy_service()->request_options());
 }
 
-TestDataReductionProxyConfigServiceClient*
-DataReductionProxyTestContext::test_config_client() {
-  DCHECK(test_context_flags_ & USE_TEST_CONFIG_CLIENT);
-  return static_cast<TestDataReductionProxyConfigServiceClient*>(
-      data_reduction_proxy_service()->config_client());
-}
-
-DataReductionProxyTestContext::TestConfigStorer::TestConfigStorer(
-    PrefService* prefs)
-    : prefs_(prefs) {
-  DCHECK(prefs);
-}
-
-void DataReductionProxyTestContext::TestConfigStorer::StoreSerializedConfig(
-    const std::string& serialized_config) {
-  prefs_->SetString(prefs::kDataReductionProxyConfig, serialized_config);
-  prefs_->SetInt64(prefs::kDataReductionProxyLastConfigRetrievalTime,
-                   (base::Time::Now() - base::Time()).InMicroseconds());
-}
-
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
index ec0a746..a0a46b6 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
@@ -19,7 +19,6 @@
 #include "base/time/clock.h"
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h"
@@ -30,21 +29,12 @@
 #include "components/prefs/testing_pref_service.h"
 #include "net/base/backoff_entry.h"
 #include "net/base/proxy_server.h"
-#include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
-class GURL;
 class TestingPrefServiceSimple;
 
-namespace network {
-class SharedURLLoaderFactory;
-class TestNetworkQualityTracker;
-class TestURLLoaderFactory;
-}  // namespace network
-
 namespace data_reduction_proxy {
 
-class ClientConfig;
 class DataReductionProxyRequestOptions;
 class DataReductionProxySettings;
 
@@ -68,92 +58,8 @@
   explicit MockDataReductionProxyRequestOptions(Client client);
 
   ~MockDataReductionProxyRequestOptions() override;
-
-  MOCK_CONST_METHOD1(PopulateConfigResponse, void(ClientConfig* config));
 };
 
-// Test version of |DataReductionProxyConfigServiceClient|, which permits
-// finely controlling the backoff timer.
-class TestDataReductionProxyConfigServiceClient
-    : public DataReductionProxyConfigServiceClient {
- public:
-  TestDataReductionProxyConfigServiceClient(
-      DataReductionProxyRequestOptions* request_options,
-      DataReductionProxyService* service,
-      network::NetworkConnectionTracker* network_connection_tracker,
-      ConfigStorer config_storer,
-      const net::BackoffEntry::Policy& backoff_policy);
-
-  ~TestDataReductionProxyConfigServiceClient() override;
-
-  using DataReductionProxyConfigServiceClient::OnConnectionChanged;
-
-  void SetNow(const base::Time& time);
-
-  void SetCustomReleaseTime(const base::TimeTicks& release_time);
-
-  base::TimeDelta GetDelay() const;
-
-  int GetBackoffErrorCount();
-
-  base::TimeDelta GetBackoffTimeUntilRelease() const;
-
-  void SetConfigServiceURL(const GURL& service_url);
-
-  int32_t failed_attempts_before_success() const;
-
-#if defined(OS_ANDROID)
-  bool IsApplicationStateBackground() const override;
-
-  void set_application_state_background(bool new_state) {
-    is_application_state_background_ = new_state;
-  }
-
-  bool foreground_fetch_pending() const { return foreground_fetch_pending_; }
-
-  // Triggers the callback for Chromium status change to foreground.
-  void TriggerApplicationStatusToForeground();
-#endif
-
-  void SetRemoteConfigApplied(bool remote_config_applied);
-
-  bool RemoteConfigApplied() const override;
-
- protected:
-  // Overrides of DataReductionProxyConfigServiceClient
-  base::Time Now() override;
-  net::BackoffEntry* GetBackoffEntry() override;
-
- private:
-  // A clock which returns a fixed value in both base::Time and base::TimeTicks.
-  class TestTickClock : public base::Clock, public base::TickClock {
-   public:
-    TestTickClock(const base::Time& initial_time);
-
-    // base::TickClock implementation.
-    base::TimeTicks NowTicks() const override;
-
-    // base::Clock implementation.
-    base::Time Now() const override;
-
-    // Sets the current time.
-    void SetTime(const base::Time& time);
-
-   private:
-    base::Time time_;
-  };
-
-#if defined(OS_ANDROID)
-  bool is_application_state_background_;
-#endif
-
-  TestTickClock tick_clock_;
-  net::BackoffEntry test_backoff_entry_;
-
-  base::Optional<bool> remote_config_applied_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestDataReductionProxyConfigServiceClient);
-};
 
 // Test version of |DataReductionProxyService|, which permits mocking of various
 // methods.
@@ -162,9 +68,7 @@
   MockDataReductionProxyService(
       data_use_measurement::DataUseMeasurement* data_use_measurement,
       DataReductionProxySettings* settings,
-      network::TestNetworkQualityTracker* test_network_quality_tracker,
       PrefService* prefs,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
   ~MockDataReductionProxyService() override;
 
@@ -195,8 +99,6 @@
       data_use_measurement::DataUseMeasurement* data_use_measurement,
       DataReductionProxySettings* settings,
       PrefService* prefs,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      network::NetworkQualityTracker* network_quality_tracker,
       const scoped_refptr<base::SequencedTaskRunner>& db_task_runner);
   ~TestDataReductionProxyService() override;
 
@@ -246,10 +148,6 @@
     // The |Client| enum to use for |DataReductionProxyRequestOptions|.
     Builder& WithClient(Client client);
 
-    // Specifies a |network::URLLoaderFactory| to use.
-    Builder& WithURLLoaderFactory(
-        scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
-
     // Specifies the use of |MockDataReductionProxyConfig| instead of
     // |TestDataReductionProxyConfig|.
     Builder& WithMockConfig();
@@ -262,13 +160,6 @@
     // |DataReductionProxyRequestOptions|.
     Builder& WithMockRequestOptions();
 
-    // Specifies the use of the |DataReductionProxyConfigServiceClient|.
-    Builder& WithConfigClient();
-
-    // Specifies the use of the a |TestDataReductionProxyConfigServiceClient|
-    // instead of a |DataReductionProxyConfigServiceClient|.
-    Builder& WithTestConfigClient();
-
     // Construct, but do not initialize the |DataReductionProxySettings| object.
     Builder& SkipSettingsInitialization();
 
@@ -280,13 +171,10 @@
 
    private:
     Client client_;
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
     bool use_mock_config_;
     bool use_mock_service_;
     bool use_mock_request_options_;
-    bool use_config_client_;
-    bool use_test_config_client_;
     bool skip_settings_initialization_;
     std::unique_ptr<DataReductionProxySettings> settings_;
     std::unique_ptr<data_use_measurement::DataUseMeasurement>
@@ -337,11 +225,6 @@
   // only be called if built with WithMockRequestOptions.
   MockDataReductionProxyRequestOptions* mock_request_options() const;
 
-
-  // Returns the underlying |TestDataReductionProxyConfigServiceClient|. This
-  // can only be called if built with WithTestConfigClient.
-  TestDataReductionProxyConfigServiceClient* test_config_client();
-
   scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
     return task_runner_;
   }
@@ -350,45 +233,19 @@
     return simple_pref_service_.get();
   }
 
-  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory() const {
-    return test_shared_url_loader_factory_;
-  }
-
   DataReductionProxySettings* settings() const { return settings_.get(); }
 
-  network::TestNetworkQualityTracker* test_network_quality_tracker() const {
-    return test_network_quality_tracker_.get();
-  }
-
   void InitSettingsWithoutCheck();
 
 
  private:
-  // Used to storage a serialized Data Reduction Proxy config.
-  class TestConfigStorer {
-   public:
-    // |prefs| must not be null and outlive |this|.
-    TestConfigStorer(PrefService* prefs);
-
-    // Stores |serialized_config| in |prefs_|.
-    void StoreSerializedConfig(const std::string& serialized_config);
-
-   private:
-    PrefService* prefs_;
-  };
-
   DataReductionProxyTestContext(
       std::unique_ptr<data_use_measurement::DataUseMeasurement>
           data_use_measurement,
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
       std::unique_ptr<TestingPrefServiceSimple> simple_pref_service,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      std::unique_ptr<network::TestURLLoaderFactory> test_url_loader_factory,
       std::unique_ptr<DataReductionProxySettings> settings,
       std::unique_ptr<DataReductionProxyService> service,
-      std::unique_ptr<network::TestNetworkQualityTracker>
-          test_network_quality_tracker,
-      std::unique_ptr<TestConfigStorer> config_storer,
       unsigned int test_context_flags);
 
   std::unique_ptr<data_use_measurement::DataUseMeasurement>
@@ -398,16 +255,10 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   std::unique_ptr<TestingPrefServiceSimple> simple_pref_service_;
-  scoped_refptr<network::SharedURLLoaderFactory>
-      test_shared_url_loader_factory_;
-  std::unique_ptr<network::TestURLLoaderFactory> test_url_loader_factory_;
 
   std::unique_ptr<DataReductionProxySettings> settings_;
   DataReductionProxyService* data_reduction_proxy_service_;
-  std::unique_ptr<network::TestNetworkQualityTracker>
-      test_network_quality_tracker_;
   std::unique_ptr<DataReductionProxyService> service_;
-  std::unique_ptr<TestConfigStorer> config_storer_;
 
   DISALLOW_COPY_AND_ASSIGN(DataReductionProxyTestContext);
 };
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.cc
index 82bde6c..e5d84dd4 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.cc
@@ -127,63 +127,5 @@
 
 }  // namespace util
 
-namespace protobuf_parser {
-
-std::string SchemeFromPrefetchScheme(
-    PrefetchProxyConfig_Proxy_Scheme proxy_scheme) {
-  switch (proxy_scheme) {
-    case PrefetchProxyConfig_Proxy_Scheme_HTTP:
-      return "http";
-    case PrefetchProxyConfig_Proxy_Scheme_HTTPS:
-      return "https";
-    default:
-      return std::string();
-  }
-}
-
-void TimeDeltaToDuration(const base::TimeDelta& time_delta,
-                         Duration* duration) {
-  duration->set_seconds(time_delta.InSeconds());
-  base::TimeDelta partial_seconds =
-      time_delta - base::TimeDelta::FromSeconds(time_delta.InSeconds());
-  duration->set_nanos(partial_seconds.InMicroseconds() *
-                      base::Time::kNanosecondsPerMicrosecond);
-}
-
-base::TimeDelta DurationToTimeDelta(const Duration& duration) {
-  return base::TimeDelta::FromSeconds(duration.seconds()) +
-         base::TimeDelta::FromMicroseconds(
-             duration.nanos() / base::Time::kNanosecondsPerMicrosecond);
-}
-
-void TimeToTimestamp(const base::Time& time, Timestamp* timestamp) {
-  timestamp->set_seconds((time - base::Time::UnixEpoch()).InSeconds());
-  timestamp->set_nanos(((time - base::Time::UnixEpoch()).InMicroseconds() %
-                        base::Time::kMicrosecondsPerSecond) *
-                       base::Time::kNanosecondsPerMicrosecond);
-}
-
-base::Time TimestampToTime(const Timestamp& timestamp) {
-  base::Time t = base::Time::UnixEpoch();
-  t += base::TimeDelta::FromSeconds(timestamp.seconds());
-  t += base::TimeDelta::FromMicroseconds(
-      timestamp.nanos() / base::Time::kNanosecondsPerMicrosecond);
-  return t;
-}
-
-std::unique_ptr<Duration> CreateDurationFromTimeDelta(
-    const base::TimeDelta& time_delta) {
-  std::unique_ptr<Duration> duration(new Duration);
-  TimeDeltaToDuration(time_delta, duration.get());
-  return duration;
-}
-
-std::unique_ptr<Timestamp> CreateTimestampFromTime(const base::Time& time) {
-  std::unique_ptr<Timestamp> timestamp(new Timestamp);
-  TimeToTimestamp(time, timestamp.get());
-  return timestamp;
-}
-
-}  // namespace protobuf_parser
 
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h
index 02270348..61be038e6 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h
@@ -8,17 +8,12 @@
 #include <memory>
 #include <string>
 
-#include "components/data_reduction_proxy/proto/client_config.pb.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/proxy_server.h"
 #include "net/nqe/effective_connection_type.h"
 #include "net/proxy_resolution/proxy_retry_info.h"
 #include "url/gurl.h"
 
-namespace base {
-class Time;
-class TimeDelta;
-}  // namespace base
 
 namespace data_reduction_proxy {
 
@@ -68,39 +63,6 @@
 
 }  // namespace util
 
-namespace protobuf_parser {
-
-static_assert(net::EFFECTIVE_CONNECTION_TYPE_LAST == 6,
-              "If net::EFFECTIVE_CONNECTION_TYPE changes, "
-              "PageloadMetrics_EffectiveConnectionType needs to be updated.");
-
-// Returns the corresponding scheme string for the prefetch proto scheme.
-std::string SchemeFromPrefetchScheme(
-    PrefetchProxyConfig_Proxy_Scheme proxy_scheme);
-
-// Returns the |Duration| representation of |time_delta|.
-void TimeDeltaToDuration(const base::TimeDelta& time_delta, Duration* duration);
-
-// Returns the |base::TimeDelta| representation of |duration|.  This is accurate
-// to the microsecond.
-base::TimeDelta DurationToTimeDelta(const Duration& duration);
-
-// Returns the |Timestamp| representation of |time|.
-void TimeToTimestamp(const base::Time& time, Timestamp* timestamp);
-
-// Returns the |Time| representation of |timestamp|. This is accurate to the
-// microsecond.
-base::Time TimestampToTime(const Timestamp& timestamp);
-
-// Returns an allocated |Duration| unique pointer.
-std::unique_ptr<Duration> CreateDurationFromTimeDelta(
-    const base::TimeDelta& time_delta);
-
-// Returns an allocated |Timestamp| unique pointer.
-std::unique_ptr<Timestamp> CreateTimestampFromTime(const base::Time& time);
-
-}  // namespace protobuf_parser
-
 }  // namespace data_reduction_proxy
 
 #endif  // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_UTIL_H_
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_util_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_util_unittest.cc
deleted file mode 100644
index 9f4c680b..0000000
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_util_unittest.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-// 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.
-
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h"
-
-#include <stdint.h>
-
-#include <string>
-
-#include "base/time/time.h"
-#include "components/data_reduction_proxy/proto/client_config.pb.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace data_reduction_proxy {
-
-namespace {
-
-const char kFutureTime[] = "31 Dec 2020 23:59:59.001";
-
-}  // namespace
-
-class DataReductionProxyClientProtobufParserTest : public testing::Test {
- protected:
-  void SetUp() override {
-    EXPECT_TRUE(base::Time::FromUTCString(kFutureTime, &future_time_));
-  }
-
-  const base::Time& GetFutureTime() const { return future_time_; }
-
- private:
-  base::Time future_time_;
-};
-
-TEST_F(DataReductionProxyClientProtobufParserTest, TimeDeltaToFromDuration) {
-  const struct {
-    std::string test_name;
-    base::TimeDelta time_delta;
-    int64_t seconds;
-    int32_t nanos;
-  } tests[] = {
-      {
-          "Second", base::TimeDelta::FromSeconds(1), 1, 0,
-      },
-      {
-          "-1 Second", base::TimeDelta::FromSeconds(-1), -1, 0,
-      },
-      {
-          "1.5 Seconds", base::TimeDelta::FromMilliseconds(1500), 1,
-          base::Time::kNanosecondsPerSecond / 2,
-      },
-  };
-
-  for (const auto& test : tests) {
-    Duration duration;
-    protobuf_parser::TimeDeltaToDuration(test.time_delta, &duration);
-    EXPECT_EQ(test.seconds, duration.seconds()) << test.test_name;
-    EXPECT_EQ(test.nanos, duration.nanos()) << test.test_name;
-    duration.set_seconds(test.seconds);
-    duration.set_nanos(test.nanos);
-    EXPECT_EQ(test.time_delta, protobuf_parser::DurationToTimeDelta(duration))
-        << test.test_name;
-  }
-}
-
-TEST_F(DataReductionProxyClientProtobufParserTest, TimeStampToFromTime) {
-  const struct {
-    std::string test_name;
-    base::Time time;
-    int64_t seconds;
-    int32_t nanos;
-  } tests[] = {
-      {
-          "Second", base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1),
-          1, 0,
-      },
-      {
-          "1.5 Seconds",
-          base::Time::UnixEpoch() + base::TimeDelta::FromMilliseconds(1500), 1,
-          base::Time::kNanosecondsPerSecond / 2,
-      },
-  };
-
-  for (const auto& test : tests) {
-    Timestamp timestamp;
-    protobuf_parser::TimeToTimestamp(test.time, &timestamp);
-    EXPECT_EQ(test.seconds, timestamp.seconds()) << test.test_name;
-    EXPECT_EQ(test.nanos, timestamp.nanos()) << test.test_name;
-    timestamp.set_seconds(test.seconds);
-    timestamp.set_nanos(test.nanos);
-    EXPECT_EQ(test.time, protobuf_parser::TimestampToTime(timestamp))
-        << test.test_name;
-  }
-}
-
-}  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/BUILD.gn b/components/data_reduction_proxy/core/common/BUILD.gn
index bb25e4e..c4765d8 100644
--- a/components/data_reduction_proxy/core/common/BUILD.gn
+++ b/components/data_reduction_proxy/core/common/BUILD.gn
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 import("//build/util/process_version.gni")
-import("//mojo/public/tools/bindings/mojom.gni")
 
 # Variables:
 #   deps: Extra dependencies.
@@ -28,7 +27,6 @@
     deps = [
       "//base",
       "//components/data_reduction_proxy/proto:data_reduction_proxy_proto",
-      "//components/variations",
       "//google_apis",
       "//services/network/public/cpp",
     ]
@@ -82,7 +80,6 @@
     # TODO this dependency seems wrong, but
     "//components/data_reduction_proxy/core/browser",
     "//components/data_reduction_proxy/proto:data_reduction_proxy_proto",
-    "//components/variations",
     "//net:test_support",
     "//testing/gtest",
   ]
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
index e0830c3..88dd9f4 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
@@ -41,9 +41,5 @@
 const base::Feature kReportSaveDataSavings{"ReportSaveDataSavings",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enables fetching the Client Config for server-based Lite Mode features.
-const base::Feature kFetchClientConfig{"DataReductionProxyFetchClientConfig",
-                                       base::FEATURE_ENABLED_BY_DEFAULT};
-
 }  // namespace features
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
index 9f8a659..94e136d 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
@@ -16,7 +16,6 @@
 extern const base::Feature kDataReductionProxyServerExperiments;
 extern const base::Feature kDataReductionProxyAggressiveConfigFetch;
 extern const base::Feature kReportSaveDataSavings;
-extern const base::Feature kFetchClientConfig;
 
 }  // namespace features
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
index 457929a..3429c85 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -17,7 +17,6 @@
 #include "base/strings/string_util.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/variations/variations_associated_data.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/proxy_server.h"
 #include "net/http/http_status_code.h"
@@ -31,10 +30,6 @@
 
 const char kEnabled[] = "Enabled";
 
-// Default URL for retrieving the Data Reduction Proxy configuration.
-const char kClientConfigURL[] =
-    "https://datasaver.googleapis.com/v1/clientConfigs";
-
 const char kExperimentsOption[] = "exp";
 
 bool IsIncludedInFieldTrial(const std::string& name) {
@@ -71,47 +66,6 @@
   return CanShowAndroidLowMemoryDevicePromo();
 }
 
-bool ForceEnableClientConfigServiceForAllDataSaverUsers() {
-  return base::FeatureList::IsEnabled(
-      data_reduction_proxy::features::kFetchClientConfig);
-}
-
-GURL GetConfigServiceURL() {
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  std::string url;
-  if (command_line->HasSwitch(switches::kDataReductionProxyConfigURL)) {
-    url = command_line->GetSwitchValueASCII(
-        switches::kDataReductionProxyConfigURL);
-  }
-
-  if (url.empty())
-    return GURL(kClientConfigURL);
-
-  GURL result(url);
-  if (result.is_valid())
-    return result;
-
-  LOG(WARNING) << "The following client config URL specified at the "
-               << "command-line or variation is invalid: " << url;
-  return GURL(kClientConfigURL);
-}
-
-int GetFieldTrialParameterAsInteger(const std::string& group,
-                                    const std::string& param_name,
-                                    int default_value,
-                                    int min_value) {
-  DCHECK(default_value >= min_value);
-  std::string param_value =
-      variations::GetVariationParamValue(group, param_name);
-  int value;
-  if (param_value.empty() || !base::StringToInt(param_value, &value) ||
-      value < min_value) {
-    return default_value;
-  }
-
-  return value;
-}
-
 std::string GetDataSaverServerExperimentsOptionName() {
   return kExperimentsOption;
 }
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
index eae7a71..6500d01 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
@@ -29,10 +29,6 @@
 // a FRE promotion for the data reduction proxy.
 bool IsIncludedInFREPromoFieldTrial();
 
-// Returns true if DRP config service should always be fetched even if DRP
-// holdback is enabled.
-bool ForceEnableClientConfigServiceForAllDataSaverUsers();
-
 // Returns the server experiments option name. This name is used in the request
 // headers to the data saver proxy. This name is also used to set the experiment
 // name using finch trial.
@@ -43,19 +39,6 @@
 // experiment is enabled.
 std::string GetDataSaverServerExperiments();
 
-// If the Data Reduction Proxy config client is being used, the URL for the
-// Data Reduction Proxy config service.
-GURL GetConfigServiceURL();
-
-// Retrieves the int stored in |param_name| from the field trial group
-// |group|. If the value is not present, cannot be parsed, or is less than
-// |min_value|, returns |default_value|.
-int GetFieldTrialParameterAsInteger(const std::string& group,
-                                    const std::string& param_name,
-                                    int default_value,
-                                    int min_value);
-
-
 }  // namespace params
 
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
index 55c0aa50..1491c21 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
@@ -19,8 +19,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/data_reduction_proxy/proto/client_config.pb.h"
-#include "components/variations/variations_associated_data.h"
 #include "net/base/proxy_server.h"
 #include "net/http/http_status_code.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -180,33 +178,4 @@
   }
 }
 
-TEST_F(DataReductionProxyParamsTest, GetConfigServiceURL) {
-  const struct {
-    std::string test_case;
-    std::string flag_value;
-    GURL expected;
-  } tests[] = {
-      {
-          "Nothing set", "",
-          GURL("https://datasaver.googleapis.com/v1/clientConfigs"),
-      },
-      {
-          "Only command line set", "http://commandline.config-service/",
-          GURL("http://commandline.config-service/"),
-      },
-  };
-
-  for (const auto& test : tests) {
-    // Reset all flags.
-    base::CommandLine::ForCurrentProcess()->InitFromArgv(0, nullptr);
-    if (!test.flag_value.empty()) {
-      base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-          switches::kDataReductionProxyConfigURL, test.flag_value);
-    }
-    EXPECT_EQ(test.expected, params::GetConfigServiceURL()) << test.test_case;
-  }
-}
-
-
-
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
index 434dc26..3cdef1a 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
@@ -37,9 +37,6 @@
 // consult the OWNERS.
 const char kDataSaverEnabled[] = "spdy_proxy.enabled";
 
-// String that specifies a persisted Data Reduction Proxy configuration.
-const char kDataReductionProxyConfig[] = "data_reduction.config";
-
 // A boolean specifying whether data usage should be collected for reporting.
 const char kDataUsageReportingEnabled[] = "data_usage_reporting.enabled";
 
@@ -62,12 +59,6 @@
 // received over the network.
 const char kHttpOriginalContentLength[] = "http_original_content_length";
 
-// Pref to store the retrieval time of the last Data Reduction Proxy
-// configuration.
-const char kDataReductionProxyLastConfigRetrievalTime[] =
-    "data_reduction.last_config_retrieval_time";
-
-
 // An integer pref that stores the number of the week when the weekly data use
 // prefs were updated.
 const char kThisWeekNumber[] = "data_reduction.this_week_number";
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
index 6652a3a9..467d6384 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
@@ -17,13 +17,11 @@
 
 extern const char kDataReductionProxy[];
 extern const char kDataSaverEnabled[];
-extern const char kDataReductionProxyConfig[];
 extern const char kDataUsageReportingEnabled[];
 extern const char kDataReductionProxyWasEnabledBefore[];
 extern const char kDataReductionProxyLastEnabledTime[];
 extern const char kHttpOriginalContentLength[];
 extern const char kHttpReceivedContentLength[];
-extern const char kDataReductionProxyLastConfigRetrievalTime[];
 
 extern const char kThisWeekNumber[];
 extern const char kThisWeekServicesDownstreamBackgroundKB[];
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
index 08391335..2651eab 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
@@ -10,9 +10,6 @@
 // The origin of the data reduction proxy.
 const char kDataReductionProxy[]         = "spdy-proxy-auth-origin";
 
-// The URL from which to retrieve the Data Reduction Proxy configuration.
-const char kDataReductionProxyConfigURL[] = "data-reduction-proxy-config-url";
-
 // The name of a Data Reduction Proxy experiment to run. These experiments are
 // defined by the proxy server. Use --force-fieldtrials for Data Reduction
 // Proxy field trials.
@@ -31,30 +28,9 @@
 const char kDataReductionProxyServerAlternative9[] = "alt9";
 const char kDataReductionProxyServerAlternative10[] = "alt10";
 
-// The origin of the data reduction proxy fallback.
-const char kDataReductionProxyFallback[] = "spdy-proxy-auth-fallback";
-
-// The semicolon-separated list of proxy server URIs to override the list of
-// HTTP proxies returned by the Data Saver API. It is illegal to use
-// |kDataReductionProxy| or |kDataReductionProxyFallback| switch in conjunction
-// with |kDataReductionProxyHttpProxies|. If the URI omits a scheme, then the
-// proxy server scheme defaults to HTTP, and if the port is omitted then the
-// default port for that scheme is used. E.g. "http://foo.net:80",
-// "http://foo.net", "foo.net:80", and "foo.net" are all equivalent.
-const char kDataReductionProxyHttpProxies[] =
-    "data-reduction-proxy-http-proxies";
-
 // A test key for data reduction proxy authentication.
 const char kDataReductionProxyKey[] = "spdy-proxy-auth-value";
 
-const char kDataReductionPingbackURL[] = "data-reduction-proxy-pingback-url";
-
-// Sets a secure proxy check URL to test before committing to using the Data
-// Reduction Proxy. Note this check does not go through the Data Reduction
-// Proxy.
-const char kDataReductionProxySecureProxyCheckURL[] =
-    "data-reduction-proxy-secure-proxy-check-url";
-
 // Disables server experiments that may be enabled through field trial.
 const char kDataReductionProxyServerExperimentsDisabled[] =
     "data-reduction-proxy-server-experiments-disabled";
@@ -66,10 +42,6 @@
 const char kEnableDataReductionProxyBypassWarning[] =
     "enable-data-reduction-proxy-bypass-warning";
 
-// Enables sending a pageload metrics pingback after every page load.
-const char kEnableDataReductionProxyForcePingback[] =
-    "enable-data-reduction-proxy-force-pingback";
-
 // Enables a 1 MB savings promo for the data reduction proxy.
 const char kEnableDataReductionProxySavingsPromo[] =
     "enable-data-reduction-proxy-savings-promo";
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
index 8b939fa..b2cacf6 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
@@ -11,14 +11,9 @@
 // All switches in alphabetical order. The switches should be documented
 // alongside the definition of their values in the .cc file.
 
-extern const char kDataReductionPingbackURL[];
 extern const char kDataReductionProxy[];
-extern const char kDataReductionProxyConfigURL[];
 extern const char kDataReductionProxyExperiment[];
-extern const char kDataReductionProxyFallback[];
-extern const char kDataReductionProxyHttpProxies[];
 extern const char kDataReductionProxyKey[];
-extern const char kDataReductionProxySecureProxyCheckURL[];
 extern const char kDataReductionProxyServerExperimentsDisabled[];
 extern const char kDataReductionProxyServerAlternative1[];
 extern const char kDataReductionProxyServerAlternative2[];
@@ -33,7 +28,6 @@
 extern const char kDataReductionProxyServerClientConfig[];
 extern const char kEnableDataReductionProxy[];
 extern const char kEnableDataReductionProxyBypassWarning[];
-extern const char kEnableDataReductionProxyForcePingback[];
 extern const char kEnableDataReductionProxySavingsPromo[];
 extern const char kOverrideHttpsImageCompressionInfobar[];
 
diff --git a/components/data_reduction_proxy/proto/BUILD.gn b/components/data_reduction_proxy/proto/BUILD.gn
index 6ed094b..2d5b4e2 100644
--- a/components/data_reduction_proxy/proto/BUILD.gn
+++ b/components/data_reduction_proxy/proto/BUILD.gn
@@ -5,8 +5,5 @@
 import("//third_party/protobuf/proto_library.gni")
 
 proto_library("data_reduction_proxy_proto") {
-  sources = [
-    "client_config.proto",
-    "data_store.proto",
-  ]
+  sources = [ "data_store.proto" ]
 }
diff --git a/components/data_reduction_proxy/proto/client_config.proto b/components/data_reduction_proxy/proto/client_config.proto
deleted file mode 100644
index 58b9b0e..0000000
--- a/components/data_reduction_proxy/proto/client_config.proto
+++ /dev/null
@@ -1,211 +0,0 @@
-// 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.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package data_reduction_proxy;
-
-// The client configuration information for using the Data Saver service.
-message ClientConfig {
-  // An opaque per-session key assigned by the server which permits use of the
-  // Data Saver HTTP proxy servers.
-  optional string session_key = 1;
-  // The time at which the client should request a new configuration. The
-  // session_key is guaranteed to be valid through this time and may be valid
-  // for some time thereafter.
-  optional Timestamp DEPRECATED_refresh_time = 2 [deprecated = true];
-  // The proxy configuration the client should use to connect to the Data Saver
-  // service.
-  optional DeprecatedProxyConfig proxy_config = 3 [deprecated = true];
-  // The duration after which the client should request a new configuration. The
-  // session_key is guaranteed to be valid through this time and may be valid
-  // for some time thereafter. If both refresh_duration and refresh_time are
-  // present, refresh_duration should take priority.
-  optional Duration refresh_duration = 4;
-  // Configuration information for reporting pageload metrics.
-  optional DeprecatedPageloadMetricsConfig pageload_metrics_config = 5
-      [deprecated = true];
-  // Prevents the host base and user base blocklisting behaviors for lite pages
-  // and server LoFi.
-  optional bool ignore_long_term_block_list_rules = 7 [deprecated = true];
-  // The configuration that the client should use to connect to the prefetch
-  // proxy.
-  optional PrefetchProxyConfig prefetch_proxy_config = 8;
-}
-
-// The configuration for reporting pageload metrics.
-message DeprecatedPageloadMetricsConfig {
-  // The fraction of pageloads for which to report pageload metrics.
-  optional float reporting_fraction = 1 [deprecated = true];
-}
-
-// N.B.:
-// The configuration service that sends the ClientConfig uses Timestamp and
-// Duration to conform to Google API standards. These proto messages should
-// live in a shared location in the Chromium tree, but for now we duplicate
-// them here.
-
-// A Timestamp represents a point in time independent of any time zone
-// or calendar, represented as seconds and fractions of seconds at
-// nanosecond resolution in UTC Epoch time.
-message Timestamp {
-  // Represents seconds of UTC time since Unix epoch
-  // 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
-  // 9999-12-31T23:59:59Z inclusive.
-  optional int64 seconds = 1;
-
-  // Non-negative fractions of a second at nanosecond resolution. Negative
-  // second values with fractions must still have non-negative nanos values
-  // that count forward in time. Must be from 0 to 999,999,999
-  // inclusive.
-  optional int32 nanos = 2;
-}
-
-// A Duration represents a signed, fixed-length span of time represented
-// as a count of seconds and fractions of seconds at nanosecond
-// resolution. It is independent of any calendar and concepts like "day"
-// or "month". It is related to Timestamp in that the difference between
-// two Timestamp values is a Duration and it can be added or subtracted
-// from a Timestamp. Range is approximately +-10,000 years.
-message Duration {
-  // Signed seconds of the span of time. Must be from -315,576,000,000
-  // to +315,576,000,000 inclusive.
-  optional int64 seconds = 1;
-
-  // Signed fractions of a second at nanosecond resolution of the span
-  // of time. Durations less than one second are represented with a 0
-  // `seconds` field and a positive or negative `nanos` field. For durations
-  // of one second or more, a non-zero value for the `nanos` field must be
-  // of the same sign as the `seconds` field. Must be from -999,999,999
-  // to +999,999,999 inclusive.
-  optional int32 nanos = 2;
-}
-
-// Data Saver proxy configuration.
-message DeprecatedProxyConfig {
-  // Provides proxy server information for HTTP URIs.
-  repeated DeprecatedProxyServer http_proxy_servers = 1 [deprecated = true];
-}
-
-// Configuration information for a specific proxy server.
-message DeprecatedProxyServer {
-  // The scheme of the proxy server.
-  enum ProxyScheme {
-    // The proxy scheme is unspecified.
-    UNSPECIFIED = 0;
-    // HTTP
-    DEPRECATED_HTTP = 1 [deprecated = true];
-    // HTTPS
-    HTTPS = 2;
-    // HTTPS over QUIC
-    DEPRECATED_QUIC = 3 [deprecated = true];
-  }
-
-  // The deployment type of the proxy server.
-  enum DeprecatedProxyType {
-    // The proxy type is unspecified.
-    UNSPECIFIED_TYPE = 0;
-    // Core Google datacenter.
-    CORE = 1;
-  }
-
-  // The scheme for the proxy server.
-  optional ProxyScheme scheme = 1;
-  // The host name for the proxy server.
-  optional string host = 2;
-  // The port number for the proxy server.
-  optional int32 port = 3;
-  // The type for the proxy server.
-  optional DeprecatedProxyType deprecated_type = 4 [deprecated = true];
-}
-
-// Information about the device the user is on.
-message ConfigDeviceInfo {
-  // Kilobytes of total device memory.
-  optional int64 total_device_memory_kb = 1;
-}
-
-// Configuration information for the prefetch proxy service.
-message PrefetchProxyConfig {
-  // Definition of the type and location of prefetch proxy to use.
-  message Proxy {
-    // The type of the proxy server.
-    enum Type {
-      // The proxy type is unspecified.
-      UNSPECIFIED_TYPE = 0;
-      // CONNECT proxy
-      CONNECT = 1;
-    }
-
-    // The scheme of the proxy.
-    enum Scheme {
-      UNSPECIFIED_SCHEME = 0;
-      HTTP = 1;
-      HTTPS = 2;
-    }
-
-    optional Type type = 1;
-
-    // Hostname and port of the prefetch proxy.
-    optional string host = 2;
-    optional int32 port = 3;
-    optional Scheme scheme = 4;
-  }
-
-  // The proxy servers that the client should connect to for the
-  // prefetch proxy service. Listed in order of preference.
-  repeated Proxy proxy_list = 1;
-}
-
-// Request object to create a client configuration object.
-message CreateClientConfigRequest {
-  // An enum representing the type of user regarding whether they are dogfooding
-  // Chrome.
-  enum DogfoodGroup {
-    // The user dogfood group is not specified.
-    UNSPECIFIED = 0;
-    // The user is not a Chrome dogfooder.
-    NONDOGFOOD = 1;
-    // The user is a Chrome dogfooder.
-    DOGFOOD = 2;
-  }
-
-  // A previous per-session key that was assigned by the service.
-  optional string session_key = 1;
-
-  // Build version information.
-  optional VersionInfo version_info = 2;
-
-  // The MCC/MNC of the telephony network operator. Represented as a string of
-  // the two numbers concatenated. E.g., "310260" for T-Mobile. Empty string if
-  // the user is not on android or if the user is on WiFi.
-  // Added in M65.
-  optional string telephony_network_operator = 3;
-
-  // The DogfoodGroup of the user.
-  // Added in M65.
-  optional DogfoodGroup dogfood_group = 4;
-
-  // Added in M65.
-  optional ConfigDeviceInfo device_info = 5;
-}
-
-// Build version information.
-message VersionInfo {
-  // The client's platform type. See
-  // components/data_reduction_proxy/core/common/data_reduction_proxy_util.h for
-  // allowed strings in CLIENT_ENUMS_LIST.
-  optional string client = 1;
-
-  // The build number, e.g. 2171
-  optional int32 build = 2;
-
-  // The patch number of the chromium client: always a non-negative integer.
-  optional int32 patch = 3;
-
-  // The production channel, e.g. "canary", "dev", "beta", "stable".
-  optional string channel = 4;
-}
diff --git a/components/exo/DEPS b/components/exo/DEPS
index c32564d..b2c68db 100644
--- a/components/exo/DEPS
+++ b/components/exo/DEPS
@@ -2,7 +2,6 @@
   "+ash",
   "+cc",
   "+chromeos/audio/chromeos_sounds.h",
-  "+chromeos/constants/chromeos_features.h",
   "+chromeos/crosapi/cpp/crosapi_constants.h",
   "+chromeos/ui/base",
   "+chromeos/ui/frame",
diff --git a/components/exo/gamepad.cc b/components/exo/gamepad.cc
index d360518..4e6cecc 100644
--- a/components/exo/gamepad.cc
+++ b/components/exo/gamepad.cc
@@ -4,9 +4,9 @@
 
 #include "components/exo/gamepad.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/logging.h"
-#include "chromeos/constants/chromeos_features.h"
 
 namespace exo {
 
diff --git a/components/exo/gamepad_unittest.cc b/components/exo/gamepad_unittest.cc
index e570306..382abef 100644
--- a/components/exo/gamepad_unittest.cc
+++ b/components/exo/gamepad_unittest.cc
@@ -4,9 +4,9 @@
 
 #include "components/exo/gamepad.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/components/exo/pointer.cc b/components/exo/pointer.cc
index 3087c49c..a35f8ed 100644
--- a/components/exo/pointer.cc
+++ b/components/exo/pointer.cc
@@ -43,9 +43,9 @@
 #include "ui/views/widget/widget.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_types.h"
 #include "ash/public/cpp/shell_window_ids.h"
-#include "chromeos/constants/chromeos_features.h"
 #endif
 
 namespace exo {
diff --git a/components/exo/pointer_unittest.cc b/components/exo/pointer_unittest.cc
index 975865b1..daa478e 100644
--- a/components/exo/pointer_unittest.cc
+++ b/components/exo/pointer_unittest.cc
@@ -43,7 +43,7 @@
 #include "ui/views/widget/widget.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif
 
 namespace exo {
diff --git a/components/memories_strings.grdp b/components/memories_strings.grdp
new file mode 100644
index 0000000..39831af
--- /dev/null
+++ b/components/memories_strings.grdp
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Strings for the chrome://memories page -->
+
+<grit-part>
+  <message name="IDS_MEMORIES_PAGE_TITLE" desc="Title of chrome://memories page.">
+    Memories
+  </message>
+</grit-part>
diff --git a/components/memories_strings_grdp/IDS_MEMORIES_PAGE_TITLE.png.sha1 b/components/memories_strings_grdp/IDS_MEMORIES_PAGE_TITLE.png.sha1
new file mode 100644
index 0000000..97e6db6
--- /dev/null
+++ b/components/memories_strings_grdp/IDS_MEMORIES_PAGE_TITLE.png.sha1
@@ -0,0 +1 @@
+19eaa3f77b1defe74d59579afb6d45634c76e819
\ No newline at end of file
diff --git a/components/metrics/metrics_provider.h b/components/metrics/metrics_provider.h
index 28bc4fa..108cd7b8 100644
--- a/components/metrics/metrics_provider.h
+++ b/components/metrics/metrics_provider.h
@@ -34,9 +34,6 @@
   virtual void AsyncInit(base::OnceClosure done_callback);
 
   // Called when a new MetricsLog is created.
-  // This can be used to log a histogram that will appear in the log. Not safe
-  // for some other uses, like user actions.
-  // TODO(crbug.com/1171830): Improve this.
   virtual void OnDidCreateMetricsLog();
 
   // Called when metrics recording has been enabled.
diff --git a/components/metrics/metrics_service.cc b/components/metrics/metrics_service.cc
index 5ba33668..611b994 100644
--- a/components/metrics/metrics_service.cc
+++ b/components/metrics/metrics_service.cc
@@ -78,7 +78,6 @@
 //
 //  INITIALIZED,          // Constructor was called.
 //  INIT_TASK_SCHEDULED,  // Waiting for deferred init tasks to finish.
-//  INIT_TASK_DONE,       // Waiting for timer to send initial log.
 //  SENDING_LOGS,         // Sending logs and creating new ones when we run out.
 //
 // In more detail, we have:
@@ -88,26 +87,20 @@
 // initial log.
 //
 //    INIT_TASK_SCHEDULED,    // Waiting for deferred init tasks to finish.
-// Typically about 30 seconds after startup, a task is sent to a second thread
-// (the file thread) to perform deferred (lower priority and slower)
-// initialization steps such as getting the list of plugins.  That task will
-// (when complete) make an async callback (via a Task) to indicate the
-// completion.
+// Typically about 30 seconds after startup, a task is sent to a background
+// thread to perform deferred (lower priority and slower) initialization steps
+// such as getting the list of plugins.  That task will (when complete) make an
+// async callback (via a Task) to indicate the completion.
 //
-//    INIT_TASK_DONE,         // Waiting for timer to send initial log.
-// The callback has arrived, and it is now possible for an initial log to be
-// created.  This callback typically arrives back less than one second after
-// the deferred init task is dispatched.
-//
-//    SENDING_LOGS,  // Sending logs an creating new ones when we run out.
-// Logs from previous sessions have been loaded, and initial logs have been
-// created (an optional stability log and the first metrics log).  We will
-// send all of these logs, and when run out, we will start cutting new logs
-// to send.  We will also cut a new log if we expect a shutdown.
+//    SENDING_LOGS,  // Sending logs and creating new ones when we run out.
+// Logs from previous sessions have been loaded, and an optional initial
+// stability log has been created.  We will send all of these logs, and when
+// they run out, we will start cutting new logs to send.  We will also cut a
+// new log if we expect a shutdown.
 //
 // The progression through the above states is simple, and sequential.
-// States proceed from INITIAL to SENDING_LOGS, and remain in the latter until
-// shutdown.
+// States proceed from INITIALIZED to SENDING_LOGS, and remain in the latter
+// until shutdown.
 //
 // Also note that whenever we successfully send a log, we mirror the list
 // of logs into the PrefService. This ensures that IF we crash, we won't start
@@ -555,17 +548,7 @@
 
 void MetricsService::FinishedInitTask() {
   DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
-  state_ = INIT_TASK_DONE;
-
-  // Create the initial log.
-  if (!initial_metrics_log_) {
-    initial_metrics_log_ = CreateLog(MetricsLog::ONGOING_LOG);
-    // Note: We explicitly do not call OnDidCreateMetricsLog() here, as this
-    // function would have already been called in Start() and this log will
-    // already contain any histograms logged there. OnDidCreateMetricsLog()
-    // will be called again after the initial log is closed, for the next log.
-    // TODO(crbug.com/1171830): Consider getting rid of |initial_metrics_log_|.
-  }
+  state_ = SENDING_LOGS;
 
   rotation_scheduler_->InitTaskComplete();
 }
@@ -648,12 +631,13 @@
   log_manager_.FinishCurrentLog(log_store());
 }
 
-void MetricsService::PushPendingLogsToPersistentStorage() {
+bool MetricsService::PushPendingLogsToPersistentStorage() {
   if (state_ < SENDING_LOGS)
-    return;  // We didn't and still don't have time to get plugin list etc.
+    return false;
 
   CloseCurrentLog();
   log_store()->TrimAndPersistUnsentLogs();
+  return true;
 }
 
 //------------------------------------------------------------------------------
@@ -676,7 +660,7 @@
 
 void MetricsService::StartScheduledUpload() {
   DVLOG(1) << "StartScheduledUpload";
-  DCHECK(state_ >= INIT_TASK_DONE);
+  DCHECK(state_ >= SENDING_LOGS);
 
   // If we're getting no notifications, then the log won't have much in it, and
   // it's possible the computer is about to go to sleep, so don't upload and
@@ -717,13 +701,11 @@
     return;
   }
 
-  if (state_ == INIT_TASK_DONE) {
-    PrepareInitialMetricsLog();
-  } else {
-    DCHECK_EQ(SENDING_LOGS, state_);
-    CloseCurrentLog();
-    OpenNewLog();
-  }
+  DCHECK_EQ(SENDING_LOGS, state_);
+  bool success = PushPendingLogsToPersistentStorage();
+  DCHECK(success);
+  OpenNewLog();
+
   reporting_service_.Start();
   rotation_scheduler_->RotationFinished();
   HandleIdleSinceLastTransmission(true);
@@ -763,48 +745,6 @@
   return true;
 }
 
-void MetricsService::PrepareInitialMetricsLog() {
-  DCHECK_EQ(INIT_TASK_DONE, state_);
-
-  RecordCurrentEnvironment(initial_metrics_log_.get(), /*complete=*/true);
-  base::TimeDelta incremental_uptime;
-  base::TimeDelta uptime;
-  GetUptimes(local_state_, &incremental_uptime, &uptime);
-
-  // Histograms only get written to the current log, so make the new log current
-  // before writing them.
-  log_manager_.PauseCurrentLog();
-  log_manager_.BeginLoggingWithLog(std::move(initial_metrics_log_));
-
-  // Note: Some stability providers may record stability stats via histograms,
-  //       so this call has to be after BeginLoggingWithLog().
-  log_manager_.current_log()->RecordCurrentSessionData(
-      &delegating_provider_, base::TimeDelta(), base::TimeDelta());
-  RecordCurrentHistograms();
-
-  DVLOG(1) << "Generated an initial log.";
-  log_manager_.FinishCurrentLog(log_store());
-  log_manager_.ResumePausedLog();
-
-  // We call OnDidCreateMetricsLog() here for the next log. Normally, this is
-  // called when the log is created, but in this special case, the log we paused
-  // was created much earlier - by Start(). The histograms that were recorded
-  // via OnDidCreateMetricsLog() are now in the initial metrics log we just
-  // processed, so we need to record new ones for the next log.
-  delegating_provider_.OnDidCreateMetricsLog();
-
-  // Store unsent logs, including the initial log that was just saved, so
-  // that they're not lost in case of a crash before upload time.
-  log_store()->TrimAndPersistUnsentLogs();
-
-  state_ = SENDING_LOGS;
-}
-
-void MetricsService::IncrementLongPrefsValue(const char* path) {
-  int64_t value = local_state_->GetInt64(path);
-  local_state_->SetInt64(path, value + 1);
-}
-
 bool MetricsService::UmaMetricsProperlyShutdown() {
   CHECK(clean_shutdown_status_ == CLEANLY_SHUTDOWN ||
         clean_shutdown_status_ == NEED_TO_SHUTDOWN);
diff --git a/components/metrics/metrics_service.h b/components/metrics/metrics_service.h
index 0dff15d..8f014e2 100644
--- a/components/metrics/metrics_service.h
+++ b/components/metrics/metrics_service.h
@@ -208,8 +208,7 @@
   enum State {
     INITIALIZED,          // Constructor was called.
     INIT_TASK_SCHEDULED,  // Waiting for deferred init tasks to finish.
-    INIT_TASK_DONE,       // Waiting for timer to send initial log.
-    SENDING_LOGS,         // Sending logs an creating new ones when we run out.
+    SENDING_LOGS,         // Sending logs and creating new ones when we run out.
   };
 
   State state() const { return state_; }
@@ -237,7 +236,7 @@
   // Calls into the client to initialize some system profile metrics.
   void StartInitTask();
 
-  // Callback that moves the state to INIT_TASK_DONE. When this is called, the
+  // Callback that moves the state to SENDING_LOGS. When this is called, the
   // state should be INIT_TASK_SCHEDULED.
   void FinishedInitTask();
 
@@ -275,8 +274,7 @@
   void CloseCurrentLog();
 
   // Pushes the text of the current and staged logs into persistent storage.
-  // Called when Chrome shuts down.
-  void PushPendingLogsToPersistentStorage();
+  bool PushPendingLogsToPersistentStorage();
 
   // Ensures that scheduler is running, assuming the current settings are such
   // that metrics should be reported. If not, this is a no-op.
@@ -297,14 +295,6 @@
   // true if a log was created.
   bool PrepareInitialStabilityLog(const std::string& prefs_previous_version);
 
-  // Prepares the initial metrics log, which includes startup histograms and
-  // profiler data, as well as incremental stability-related metrics.
-  void PrepareInitialMetricsLog();
-
-  // Reads, increments and then sets the specified long preference that is
-  // stored as a string.
-  void IncrementLongPrefsValue(const char* path);
-
   // Records that the browser was shut down cleanly.
   void LogCleanShutdown(bool end_completed);
 
@@ -378,11 +368,6 @@
   // state.
   State state_;
 
-  // The initial metrics log, used to record startup metrics (histograms and
-  // profiler data). Note that if a crash occurred in the previous session, an
-  // initial stability log may be sent before this.
-  std::unique_ptr<MetricsLog> initial_metrics_log_;
-
   // Whether the MetricsService object has received any notifications since
   // the last time a transmission was sent.
   bool idle_since_last_transmission_;
diff --git a/components/metrics/stability_metrics_helper.cc b/components/metrics/stability_metrics_helper.cc
index 6fdea53..ee65a24 100644
--- a/components/metrics/stability_metrics_helper.cc
+++ b/components/metrics/stability_metrics_helper.cc
@@ -318,11 +318,6 @@
   local_state_->SetInteger(path, value + 1);
 }
 
-void StabilityMetricsHelper::IncrementLongPrefsValue(const char* path) {
-  int64_t value = local_state_->GetInt64(path);
-  local_state_->SetInt64(path, value + 1);
-}
-
 void StabilityMetricsHelper::LogRendererHang() {
 #if defined(OS_ANDROID)
   base::android::ApplicationState app_state =
diff --git a/components/metrics/stability_metrics_helper.h b/components/metrics/stability_metrics_helper.h
index 3c2d30d2..77e0d16d 100644
--- a/components/metrics/stability_metrics_helper.h
+++ b/components/metrics/stability_metrics_helper.h
@@ -93,9 +93,6 @@
   // Increments an Integer pref value specified by |path|.
   void IncrementPrefValue(const char* path);
 
-  // Increments a 64-bit Integer pref value specified by |path|.
-  void IncrementLongPrefsValue(const char* path);
-
   // Records that a renderer launch failed.
   void LogRendererLaunchFailed(bool was_extension_process);
 
diff --git a/components/safe_browsing/content/web_ui/safe_browsing_ui.cc b/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
index c734d9d..3f84801a 100644
--- a/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
+++ b/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
@@ -1889,21 +1889,21 @@
   ResolveJavascriptCallback(base::Value(callback_id), messages_received);
 }
 
-#if BUILDFLAG(FULL_SAFE_BROWSING)
 void SafeBrowsingUIHandler::GetDeepScans(const base::ListValue* args) {
   base::ListValue pings_sent;
+#if BUILDFLAG(FULL_SAFE_BROWSING)
   for (const auto& token_and_data :
        WebUIInfoSingleton::GetInstance()->deep_scan_requests()) {
     pings_sent.Append(SerializeDeepScanDebugData(token_and_data.first,
                                                  token_and_data.second));
   }
+#endif
 
   AllowJavascript();
   std::string callback_id;
   args->GetString(0, &callback_id);
   ResolveJavascriptCallback(base::Value(callback_id), pings_sent);
 }
-#endif
 
 void SafeBrowsingUIHandler::NotifyClientDownloadRequestJsListener(
     ClientDownloadRequest* client_download_request) {
@@ -2073,11 +2073,9 @@
       "getReportingEvents",
       base::BindRepeating(&SafeBrowsingUIHandler::GetReportingEvents,
                           base::Unretained(this)));
-#if BUILDFLAG(FULL_SAFE_BROWSING)
   web_ui()->RegisterMessageCallback(
       "getDeepScans", base::BindRepeating(&SafeBrowsingUIHandler::GetDeepScans,
                                           base::Unretained(this)));
-#endif
 }
 
 void SafeBrowsingUIHandler::SetWebUIForTesting(content::WebUI* web_ui) {
diff --git a/components/safe_browsing/content/web_ui/safe_browsing_ui.h b/components/safe_browsing/content/web_ui/safe_browsing_ui.h
index e35375a1..6570a85 100644
--- a/components/safe_browsing/content/web_ui/safe_browsing_ui.h
+++ b/components/safe_browsing/content/web_ui/safe_browsing_ui.h
@@ -134,11 +134,9 @@
   // currently open chrome://safe-browsing tab was opened.
   void GetReportingEvents(const base::ListValue* args);
 
-#if BUILDFLAG(FULL_SAFE_BROWSING)
   // Get the deep scanning requests that have been collected since the oldest
   // currently open chrome://safe-browsing tab was opened.
   void GetDeepScans(const base::ListValue* args);
-#endif
 
   // Register callbacks for WebUI messages.
   void RegisterMessages() override;
diff --git a/components/safe_browsing/ios/password_protection/BUILD.gn b/components/safe_browsing/ios/password_protection/BUILD.gn
index ac897712..c9eb074 100644
--- a/components/safe_browsing/ios/password_protection/BUILD.gn
+++ b/components/safe_browsing/ios/password_protection/BUILD.gn
@@ -9,9 +9,15 @@
     "password_protection_request_ios.mm",
     "password_protection_service.h",
     "password_protection_service.mm",
+    "request_canceler_ios.h",
+    "request_canceler_ios.mm",
   ]
   deps = [
     "//base",
+    "//components/password_manager/core/browser",
+    "//components/safe_browsing/core:csd_proto",
     "//components/safe_browsing/core/password_protection",
+    "//ios/web/public",
+    "//url",
   ]
 }
diff --git a/components/safe_browsing/ios/password_protection/password_protection_request_ios.h b/components/safe_browsing/ios/password_protection/password_protection_request_ios.h
index 3d9dd46f..78a2b47 100644
--- a/components/safe_browsing/ios/password_protection/password_protection_request_ios.h
+++ b/components/safe_browsing/ios/password_protection/password_protection_request_ios.h
@@ -5,13 +5,58 @@
 #ifndef COMPONENTS_SAFE_BROWSING_IOS_PASSWORD_PROTECTION_PASSWORD_PROTECTION_REQUEST_IOS_H_
 #define COMPONENTS_SAFE_BROWSING_IOS_PASSWORD_PROTECTION_PASSWORD_PROTECTION_REQUEST_IOS_H_
 
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/safe_browsing/core/password_protection/password_protection_request.h"
+#include "components/safe_browsing/core/proto/csd.pb.h"
+
+class GURL;
+class RequestCanceler;
+
+namespace web {
+class WebState;
+}
 
 namespace safe_browsing {
 
+class PasswordProtectionServiceBase;
+
 class PasswordProtectionRequestIOS : public PasswordProtectionRequest {
+ public:
+  PasswordProtectionRequestIOS(
+      web::WebState* web_state,
+      const GURL& main_frame_url,
+      const std::string& mime_type,
+      const std::string& user_name,
+      password_manager::metrics_util::PasswordType password_type,
+      const std::vector<password_manager::MatchingReusedCredential>&
+          matching_reused_credentials,
+      LoginReputationClientRequest::TriggerType type,
+      bool password_field_exists,
+      PasswordProtectionServiceBase* pps,
+      int request_timeout_in_ms);
+
+  web::WebState* web_state() const { return web_state_; }
+
+  base::WeakPtr<PasswordProtectionRequestIOS> AsWeakPtr() {
+    return base::AsWeakPtr(this);
+  }
+
  private:
   ~PasswordProtectionRequestIOS() override;
+
+  void MaybeLogPasswordReuseLookupEvent(
+      RequestOutcome outcome,
+      const LoginReputationClientResponse* response) override;
+
+  // WebState corresponding to the password protection event.
+  web::WebState* web_state_;
+
+  // Cancels the request when it is no longer valid.
+  std::unique_ptr<RequestCanceler> request_canceler_;
 };
 
 }  // namespace safe_browsing
diff --git a/components/safe_browsing/ios/password_protection/password_protection_request_ios.mm b/components/safe_browsing/ios/password_protection/password_protection_request_ios.mm
index bf477ba..793e39b 100644
--- a/components/safe_browsing/ios/password_protection/password_protection_request_ios.mm
+++ b/components/safe_browsing/ios/password_protection/password_protection_request_ios.mm
@@ -8,8 +8,56 @@
 #error "This file requires ARC support."
 #endif
 
+#import "components/safe_browsing/core/password_protection/request_canceler.h"
+#import "components/safe_browsing/ios/password_protection/password_protection_service.h"
+#import "ios/web/public/web_state.h"
+#include "url/gurl.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using password_manager::metrics_util::PasswordType;
+
 namespace safe_browsing {
 
 PasswordProtectionRequestIOS::~PasswordProtectionRequestIOS() = default;
 
-}  // namespace safe_browsing
\ No newline at end of file
+PasswordProtectionRequestIOS::PasswordProtectionRequestIOS(
+    web::WebState* web_state,
+    const GURL& main_frame_url,
+    const std::string& mime_type,
+    const std::string& username,
+    PasswordType password_type,
+    const std::vector<password_manager::MatchingReusedCredential>&
+        matching_reused_credentials,
+    LoginReputationClientRequest::TriggerType type,
+    bool password_field_exists,
+    PasswordProtectionServiceBase* pps,
+    int request_timeout_in_ms)
+    : PasswordProtectionRequest(main_frame_url,
+                                /*password_form_action=*/GURL(),
+                                /*password_frame_url=*/GURL(),
+                                mime_type,
+                                username,
+                                password_type,
+                                matching_reused_credentials,
+                                type,
+                                password_field_exists,
+                                pps,
+                                request_timeout_in_ms),
+      web_state_(web_state) {
+  request_canceler_ =
+      RequestCanceler::CreateRequestCanceler(AsWeakPtr(), web_state);
+}
+
+void PasswordProtectionRequestIOS::MaybeLogPasswordReuseLookupEvent(
+    RequestOutcome outcome,
+    const LoginReputationClientResponse* response) {
+  PasswordProtectionService* service =
+      static_cast<PasswordProtectionService*>(password_protection_service());
+  service->MaybeLogPasswordReuseLookupEvent(web_state_, outcome,
+                                            password_type(), response);
+}
+
+}  // namespace safe_browsing
diff --git a/components/safe_browsing/ios/password_protection/request_canceler_ios.h b/components/safe_browsing/ios/password_protection/request_canceler_ios.h
new file mode 100644
index 0000000..4f41249
--- /dev/null
+++ b/components/safe_browsing/ios/password_protection/request_canceler_ios.h
@@ -0,0 +1,33 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SAFE_BROWSING_IOS_PASSWORD_PROTECTION_REQUEST_CANCELER_IOS_H_
+#define COMPONENTS_SAFE_BROWSING_IOS_PASSWORD_PROTECTION_REQUEST_CANCELER_IOS_H_
+
+#include "components/safe_browsing/core/password_protection/request_canceler.h"
+#include "ios/web/public/web_state_observer.h"
+
+namespace web {
+class WebState;
+}
+
+namespace safe_browsing {
+
+class RequestCancelerIOS : public RequestCanceler,
+                           public web::WebStateObserver {
+ public:
+  RequestCancelerIOS(base::WeakPtr<CancelableRequest> request,
+                     web::WebState* web_state);
+  ~RequestCancelerIOS() override;
+
+ private:
+  // WebStateObserver implementation
+  void WebStateDestroyed(web::WebState* web_state) override;
+
+  web::WebState* web_state_ = nullptr;
+};
+
+}  // namespace safe_browsing
+
+#endif  // COMPONENTS_SAFE_BROWSING_IOS_PASSWORD_PROTECTION_REQUEST_CANCELER_IOS_H_
diff --git a/components/safe_browsing/ios/password_protection/request_canceler_ios.mm b/components/safe_browsing/ios/password_protection/request_canceler_ios.mm
new file mode 100644
index 0000000..1ce0c51
--- /dev/null
+++ b/components/safe_browsing/ios/password_protection/request_canceler_ios.mm
@@ -0,0 +1,37 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/safe_browsing/ios/password_protection/request_canceler_ios.h"
+
+#import "ios/web/public/web_state.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace safe_browsing {
+
+std::unique_ptr<RequestCanceler> RequestCanceler::CreateRequestCanceler(
+    base::WeakPtr<CancelableRequest> request,
+    web::WebState* web_state) {
+  return std::make_unique<RequestCancelerIOS>(request, web_state);
+}
+
+RequestCancelerIOS::RequestCancelerIOS(base::WeakPtr<CancelableRequest> request,
+                                       web::WebState* web_state)
+    : RequestCanceler(request), web_state_(web_state) {
+  web_state_->AddObserver(this);
+}
+
+RequestCancelerIOS::~RequestCancelerIOS() {
+  if (web_state_)
+    web_state_->RemoveObserver(this);
+}
+
+void RequestCancelerIOS::WebStateDestroyed(web::WebState* web_state) {
+  web_state_ = nullptr;
+  request_->Cancel(/*timed_out=*/false);
+}
+
+}  // namespace safe_browsing
diff --git a/components/services/app_service/public/cpp/url_handler_info.cc b/components/services/app_service/public/cpp/url_handler_info.cc
index 913eba8..c6f1b55 100644
--- a/components/services/app_service/public/cpp/url_handler_info.cc
+++ b/components/services/app_service/public/cpp/url_handler_info.cc
@@ -8,6 +8,12 @@
 
 UrlHandlerInfo::UrlHandlerInfo() = default;
 
+UrlHandlerInfo::UrlHandlerInfo(const url::Origin& origin) : origin(origin) {}
+
+UrlHandlerInfo::UrlHandlerInfo(const url::Origin& origin,
+                               bool has_origin_wildcard)
+    : origin(origin), has_origin_wildcard(has_origin_wildcard) {}
+
 UrlHandlerInfo::UrlHandlerInfo(const UrlHandlerInfo&) = default;
 
 UrlHandlerInfo& UrlHandlerInfo::operator=(const UrlHandlerInfo&) = default;
@@ -20,7 +26,8 @@
 
 bool operator==(const UrlHandlerInfo& handler1,
                 const UrlHandlerInfo& handler2) {
-  return handler1.origin == handler2.origin;
+  return handler1.origin == handler2.origin &&
+         handler1.has_origin_wildcard == handler2.has_origin_wildcard;
 }
 
 bool operator!=(const UrlHandlerInfo& handler1,
@@ -30,6 +37,8 @@
 
 std::ostream& operator<<(std::ostream& out, const UrlHandlerInfo& handler) {
   out << "origin: " << handler.origin;
+  out << "has_origin_wildcard: "
+      << (handler.has_origin_wildcard ? "true" : "false");
   return out;
 }
 
diff --git a/components/services/app_service/public/cpp/url_handler_info.h b/components/services/app_service/public/cpp/url_handler_info.h
index 1d18de1..f865901 100644
--- a/components/services/app_service/public/cpp/url_handler_info.h
+++ b/components/services/app_service/public/cpp/url_handler_info.h
@@ -16,6 +16,8 @@
 // its web app manifest.
 struct UrlHandlerInfo {
   UrlHandlerInfo();
+  explicit UrlHandlerInfo(const url::Origin& origin);
+  UrlHandlerInfo(const url::Origin& origin, bool has_origin_wildcard);
   // Copyable to support web_app::WebApp being copyable as it has a UrlHandlers
   // member variable.
   UrlHandlerInfo(const UrlHandlerInfo&);
@@ -28,6 +30,8 @@
   ~UrlHandlerInfo();
 
   url::Origin origin;
+
+  bool has_origin_wildcard = false;
 };
 
 using UrlHandlers = std::vector<UrlHandlerInfo>;
diff --git a/components/signin/internal/identity_manager/BUILD.gn b/components/signin/internal/identity_manager/BUILD.gn
index c9843fc..9d17ea2 100644
--- a/components/signin/internal/identity_manager/BUILD.gn
+++ b/components/signin/internal/identity_manager/BUILD.gn
@@ -93,10 +93,7 @@
     ]
     public_deps += [ "//ash/components/account_manager" ]
 
-    deps += [
-      "//chromeos/constants",
-      "//components/user_manager",
-    ]
+    deps += [ "//components/user_manager" ]
   } else {
     sources += [
       "primary_account_policy_manager_impl.cc",
diff --git a/components/signin/internal/identity_manager/DEPS b/components/signin/internal/identity_manager/DEPS
index 8942fc0..22712ba7 100644
--- a/components/signin/internal/identity_manager/DEPS
+++ b/components/signin/internal/identity_manager/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
-  "+chromeos/constants/chromeos_features.h",
   "+components/signin/internal/base",
   "+components/signin/public/base",
   "+components/signin/public/identity_manager",
diff --git a/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc b/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc
index bc408d2..8cb2224 100644
--- a/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc
+++ b/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc
@@ -76,7 +76,7 @@
   return base::nullopt;
 }
 
-base::Optional<bool> TestSubresourceFilterObserver::GetIsAdSubframe(
+bool TestSubresourceFilterObserver::GetIsAdSubframe(
     int frame_tree_node_id) const {
   return base::Contains(ad_evidence_, frame_tree_node_id);
 }
diff --git a/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h b/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h
index a17dfc301..9736e05 100644
--- a/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h
+++ b/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h
@@ -56,8 +56,7 @@
       const GURL& url) const;
   base::Optional<LoadPolicy> GetSubframeLoadPolicy(const GURL& url) const;
 
-  // TODO(crbug.com/1155690): Return a bool instead of an optional here.
-  base::Optional<bool> GetIsAdSubframe(int frame_tree_node_id) const;
+  bool GetIsAdSubframe(int frame_tree_node_id) const;
 
   // Should only be called on a subframe tagged as an ad.
   const FrameAdEvidence& GetEvidenceForAdSubframe(int frame_tree_node_id) const;
diff --git a/components/sync/base/DEPS b/components/sync/base/DEPS
index fe3ae97..1806984 100644
--- a/components/sync/base/DEPS
+++ b/components/sync/base/DEPS
@@ -1,5 +1,5 @@
 include_rules = [
-  "+chromeos/constants",
+  "+ash/constants",
   "+components/invalidation",
   "+components/os_crypt",
   "+components/pref_registry",
diff --git a/components/sync/base/user_selectable_type.cc b/components/sync/base/user_selectable_type.cc
index cd31574..f60f62b 100644
--- a/components/sync/base/user_selectable_type.cc
+++ b/components/sync/base/user_selectable_type.cc
@@ -13,7 +13,7 @@
 #include "components/sync/base/pref_names.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif
 
 namespace syncer {
diff --git a/components/sync/driver/DEPS b/components/sync/driver/DEPS
index 22a3f0d..df52093 100644
--- a/components/sync/driver/DEPS
+++ b/components/sync/driver/DEPS
@@ -1,5 +1,5 @@
 include_rules = [
-  "+chromeos/constants",
+  "+ash/constants",
   "+components/invalidation",
   "+components/keyed_service/core",
   "+components/metrics",
diff --git a/components/sync/driver/sync_internals_util.cc b/components/sync/driver/sync_internals_util.cc
index 9ffef43..0269b05 100644
--- a/components/sync/driver/sync_internals_util.cc
+++ b/components/sync/driver/sync_internals_util.cc
@@ -26,7 +26,7 @@
 #include "url/gurl.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif
 
 namespace syncer {
diff --git a/components/sync/driver/sync_policy_handler.cc b/components/sync/driver/sync_policy_handler.cc
index 6a518267..a226dd7 100644
--- a/components/sync/driver/sync_policy_handler.cc
+++ b/components/sync/driver/sync_policy_handler.cc
@@ -17,7 +17,7 @@
 #include "components/sync/base/user_selectable_type.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace syncer {
diff --git a/components/sync/driver/sync_policy_handler_unittest.cc b/components/sync/driver/sync_policy_handler_unittest.cc
index e700daa3..a2eea8a 100644
--- a/components/sync/driver/sync_policy_handler_unittest.cc
+++ b/components/sync/driver/sync_policy_handler_unittest.cc
@@ -16,8 +16,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace syncer {
diff --git a/components/sync/driver/sync_user_settings_impl.cc b/components/sync/driver/sync_user_settings_impl.cc
index a9a779a..c793ecc 100644
--- a/components/sync/driver/sync_user_settings_impl.cc
+++ b/components/sync/driver/sync_user_settings_impl.cc
@@ -12,7 +12,7 @@
 #include "components/sync/driver/sync_service_crypto.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif
 
 namespace syncer {
diff --git a/components/sync/driver/sync_user_settings_unittest.cc b/components/sync/driver/sync_user_settings_unittest.cc
index 41373d1..befa12a 100644
--- a/components/sync/driver/sync_user_settings_unittest.cc
+++ b/components/sync/driver/sync_user_settings_unittest.cc
@@ -20,8 +20,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #endif
 
 namespace syncer {
diff --git a/components/sync_preferences/DEPS b/components/sync_preferences/DEPS
index ebe5cfd..2e54b05 100644
--- a/components/sync_preferences/DEPS
+++ b/components/sync_preferences/DEPS
@@ -1,5 +1,5 @@
 include_rules = [
-  "+chromeos/constants",
+  "+ash/constants",
   "+components/policy/core/browser",
   "+components/policy/core/common",
   "+components/pref_registry",
diff --git a/components/sync_preferences/pref_service_syncable.cc b/components/sync_preferences/pref_service_syncable.cc
index dd40219..1c8c2e9 100644
--- a/components/sync_preferences/pref_service_syncable.cc
+++ b/components/sync_preferences/pref_service_syncable.cc
@@ -23,7 +23,7 @@
 #include "components/sync_preferences/synced_pref_observer.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif
 
 namespace sync_preferences {
diff --git a/components/sync_preferences/pref_service_syncable_unittest.cc b/components/sync_preferences/pref_service_syncable_unittest.cc
index e417c89..b584d34 100644
--- a/components/sync_preferences/pref_service_syncable_unittest.cc
+++ b/components/sync_preferences/pref_service_syncable_unittest.cc
@@ -37,8 +37,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #endif
 
diff --git a/chrome/test/data/simple_test.tflite b/components/test/data/optimization_guide/simple_test.tflite
similarity index 100%
rename from chrome/test/data/simple_test.tflite
rename to components/test/data/optimization_guide/simple_test.tflite
Binary files differ
diff --git a/components/variations/client_filterable_state.h b/components/variations/client_filterable_state.h
index ec74b48f..7480d3a 100644
--- a/components/variations/client_filterable_state.h
+++ b/components/variations/client_filterable_state.h
@@ -64,6 +64,9 @@
   // The hardware form factor that Chrome is running on.
   Study::FormFactor form_factor;
 
+  // The CPU architecture on which Chrome is running.
+  Study::CpuArchitecture cpu_architecture;
+
   // The OS on which Chrome is running.
   Study::Platform platform;
 
diff --git a/components/variations/proto/study.proto b/components/variations/proto/study.proto
index 30f4cc6..b39cd71c 100644
--- a/components/variations/proto/study.proto
+++ b/components/variations/proto/study.proto
@@ -248,6 +248,18 @@
     MEET_DEVICE = 4;
   }
 
+  // Possible CPU architectures Chrome is running on. Only supported on M90+.
+  enum CpuArchitecture {
+    X86_64 = 0;
+    ARM64 = 1;
+    X86_32 = 2;
+    ARM32 = 3;
+
+    // A Mac-only value, indicating an x86-64 binary running on an arm64 host
+    // via "Rosetta 2" binary translation.
+    TRANSLATED_X86_64 = 4;
+  }
+
   // Enum to pass as optional bool.
   enum OptionalBool {
     // Neither True nor False. (For cases like missing / unset / default etc.)
@@ -418,6 +430,18 @@
     // Specifies the restrictions applied by the "ChromeVariations" policy to
     // the study. See the definition of the PolicyRestriction enum for details.
     optional PolicyRestriction policy_restriction = 19 [default = NONE];
+
+    // List of CPU architectures that will receive this study. If omitted, the
+    // study applies to all architectures, unless |exclude_cpu_architecture| is
+    // specified. Mutually exclusive with |exclude_cpu_architecture|. Ex:
+    // [X86_32, ARM64]
+    repeated CpuArchitecture cpu_architecture = 20;
+
+    // List of CPU architectures that will be excluded from this study. If
+    // omitted, the study applies to all architectures unless |cpu_architecture|
+    // is specified. Mutually exclusive with |cpu_architecture|. Takes the same
+    // range of values as cpu_architecture, e.g. [X86_32, ARM64].
+    repeated CpuArchitecture exclude_cpu_architecture = 21;
   }
 
   // Filtering criteria for this study. A study that is filtered out for a given
diff --git a/components/variations/service/variations_field_trial_creator.cc b/components/variations/service/variations_field_trial_creator.cc
index 1b38f92..6bb5162c 100644
--- a/components/variations/service/variations_field_trial_creator.cc
+++ b/components/variations/service/variations_field_trial_creator.cc
@@ -121,6 +121,29 @@
   return static_cast<RestrictionPolicy>(value);
 }
 
+Study::CpuArchitecture GetCurrentCpuArchitecture() {
+  std::string process_arch = base::SysInfo::ProcessCPUArchitecture();
+  if (process_arch == "ARM_64")
+    return Study::ARM64;
+  if (process_arch == "ARM")
+    return Study::ARM32;
+  if (process_arch == "x86")
+    return Study::X86_32;
+  if (process_arch == "x86_64") {
+    std::string os_arch = base::SysInfo::OperatingSystemArchitecture();
+    if (base::StartsWith(os_arch, "arm",
+                         base::CompareCase::INSENSITIVE_ASCII) ||
+        base::EqualsCaseInsensitiveASCII(os_arch, "aarch64")) {
+      // x86-64 binary running on an arm64 host via the Rosetta 2 binary
+      // translator.
+      return Study::TRANSLATED_X86_64;
+    }
+    return Study::X86_64;
+  }
+  NOTREACHED();
+  return Study::X86_64;
+}
+
 }  // namespace
 
 VariationsFieldTrialCreator::VariationsFieldTrialCreator(
@@ -224,6 +247,7 @@
   state->channel =
       ConvertProductChannelToStudyChannel(client_->GetChannelForVariations());
   state->form_factor = client_->GetCurrentFormFactor();
+  state->cpu_architecture = GetCurrentCpuArchitecture();
   state->platform = GetPlatform();
   // TODO(crbug/1111131): Expand to other platforms.
 #if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_ANDROID)
diff --git a/components/variations/service/variations_service_client.cc b/components/variations/service/variations_service_client.cc
index a55254a..3dbf227 100644
--- a/components/variations/service/variations_service_client.cc
+++ b/components/variations/service/variations_service_client.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/system/sys_info.h"
 #include "components/variations/variations_switches.h"
 #include "ui/base/device_form_factor.h"
 
diff --git a/components/variations/study_filtering.cc b/components/variations/study_filtering.cc
index 4f4631a..9416c490 100644
--- a/components/variations/study_filtering.cc
+++ b/components/variations/study_filtering.cc
@@ -66,6 +66,25 @@
   return !base::Contains(filter.exclude_form_factor(), form_factor);
 }
 
+bool CheckStudyCpuArchitecture(const Study::Filter& filter,
+                               Study::CpuArchitecture cpu_architecture) {
+  // Empty allowlist and denylist signifies matching any CPU architecture.
+  if (filter.cpu_architecture_size() == 0 &&
+      filter.exclude_cpu_architecture_size() == 0) {
+    return true;
+  }
+
+  // Allow the cpu_architecture if it matches the allowlist.
+  // Note if both a allowlist and denylist are specified, the denylist is
+  // ignored. We do not expect both to be present for Chrome due to server-side
+  // checks.
+  if (filter.cpu_architecture_size() > 0)
+    return base::Contains(filter.cpu_architecture(), cpu_architecture);
+
+  // Omit if we match the denylist.
+  return !base::Contains(filter.exclude_cpu_architecture(), cpu_architecture);
+}
+
 bool CheckStudyHardwareClass(const Study::Filter& filter,
                              const std::string& hardware_class) {
   // Empty hardware_class and exclude_hardware_class matches all.
@@ -278,6 +297,13 @@
       return false;
     }
 
+    if (!CheckStudyCpuArchitecture(study.filter(),
+                                   client_state.cpu_architecture)) {
+      DVLOG(1) << "Filtered out study " << study.name()
+               << " due to cpu architecture.";
+      return false;
+    }
+
     if (!CheckStudyLocale(study.filter(), client_state.locale)) {
       DVLOG(1) << "Filtered out study " << study.name() << " due to locale.";
       return false;
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 34ed4a4..be57762 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -92,6 +92,7 @@
   "+third_party/zlib",
 
   # Allow non-browser Chrome OS code to be used.
+  "+ash/constants",
   "+chromeos",
   "+third_party/cros_system_api",
 
diff --git a/content/browser/accessibility/accessibility_event_recorder.cc b/content/browser/accessibility/accessibility_event_recorder.cc
index 9bd490a..5c2e7e0 100644
--- a/content/browser/accessibility/accessibility_event_recorder.cc
+++ b/content/browser/accessibility/accessibility_event_recorder.cc
@@ -4,9 +4,7 @@
 
 #include "content/browser/accessibility/accessibility_event_recorder.h"
 
-#include "build/build_config.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
-#include "ui/base/buildflags.h"
 
 namespace content {
 
@@ -14,28 +12,4 @@
     BrowserAccessibilityManager* manager)
     : manager_(manager) {}
 
-#if !defined(OS_WIN) && !defined(OS_MAC) && !BUILDFLAG(USE_ATK)
-// static
-std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create(
-    BrowserAccessibilityManager* manager,
-    base::ProcessId pid,
-    const AXTreeSelector& selector) {
-  return std::make_unique<AccessibilityEventRecorder>(manager);
-}
-
-// static
-std::vector<AccessibilityEventRecorder::TestPass>
-AccessibilityEventRecorder::GetTestPasses() {
-#if defined(OS_ANDROID)
-  // Note: Android doesn't do a "blink" pass; the blink tree is different on
-  // Android because we exclude inline text boxes, for performance.
-  return {{"android", &AccessibilityEventRecorder::Create}};
-#else   // defined(OS_ANDROID)
-  return {
-      {"blink", &AccessibilityEventRecorder::Create},
-  };
-#endif  // defined(OS_ANDROID)
-}
-#endif
-
 }  // namespace content
diff --git a/content/browser/accessibility/accessibility_event_recorder.h b/content/browser/accessibility/accessibility_event_recorder.h
index da7cafad..e03c50b 100644
--- a/content/browser/accessibility/accessibility_event_recorder.h
+++ b/content/browser/accessibility/accessibility_event_recorder.h
@@ -38,23 +38,12 @@
 // As currently designed, there should only be one instance of this class.
 class CONTENT_EXPORT AccessibilityEventRecorder : public ui::AXEventRecorder {
  public:
-  // Construct the right platform-specific subclass.
-  static std::unique_ptr<AccessibilityEventRecorder> Create(
-      BrowserAccessibilityManager* manager = nullptr,
-      base::ProcessId pid = 0,
-      const AXTreeSelector& selector = {});
-
   // Get a set of factory methods to create event-recorders, one for each test
   // pass; see |DumpAccessibilityTestBase|.
   using EventRecorderFactory = std::unique_ptr<AccessibilityEventRecorder> (*)(
       BrowserAccessibilityManager* manager,
       base::ProcessId pid,
       const AXTreeSelector& selector);
-  struct TestPass {
-    const char* name;
-    EventRecorderFactory create_recorder;
-  };
-  static std::vector<TestPass> GetTestPasses();
 
   AccessibilityEventRecorder(BrowserAccessibilityManager* manager);
 
diff --git a/content/browser/accessibility/accessibility_event_recorder_auralinux.cc b/content/browser/accessibility/accessibility_event_recorder_auralinux.cc
index da72155b..45a61c7c 100644
--- a/content/browser/accessibility/accessibility_event_recorder_auralinux.cc
+++ b/content/browser/accessibility/accessibility_event_recorder_auralinux.cc
@@ -54,24 +54,6 @@
   return true;
 }
 
-// static
-std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create(
-    BrowserAccessibilityManager* manager,
-    base::ProcessId pid,
-    const AXTreeSelector& selector) {
-  return std::make_unique<AccessibilityEventRecorderAuraLinux>(manager, pid,
-                                                               selector);
-}
-
-std::vector<AccessibilityEventRecorder::TestPass>
-AccessibilityEventRecorder::GetTestPasses() {
-  // Both the Blink pass and native pass use the same recorder
-  return {
-      {"blink", &AccessibilityEventRecorder::Create},
-      {"linux", &AccessibilityEventRecorder::Create},
-  };
-}
-
 bool AccessibilityEventRecorderAuraLinux::ShouldUseATSPI() {
   return pid_ != base::GetCurrentProcId() ||
          !application_name_match_pattern_.empty();
diff --git a/content/browser/accessibility/accessibility_event_recorder_mac.h b/content/browser/accessibility/accessibility_event_recorder_mac.h
index d05178d3..01814055 100644
--- a/content/browser/accessibility/accessibility_event_recorder_mac.h
+++ b/content/browser/accessibility/accessibility_event_recorder_mac.h
@@ -19,7 +19,7 @@
  public:
   AccessibilityEventRecorderMac(BrowserAccessibilityManager* manager,
                                 base::ProcessId pid,
-                                AXUIElementRef node);
+                                const AXTreeSelector& selector);
   ~AccessibilityEventRecorderMac() override;
 
   // Callback executed every time we receive an event notification.
diff --git a/content/browser/accessibility/accessibility_event_recorder_mac.mm b/content/browser/accessibility/accessibility_event_recorder_mac.mm
index e065a8a77..285d27903 100644
--- a/content/browser/accessibility/accessibility_event_recorder_mac.mm
+++ b/content/browser/accessibility/accessibility_event_recorder_mac.mm
@@ -31,11 +31,11 @@
   this_ptr->EventReceived(element, notification, user_info);
 }
 
-// static
-std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create(
+AccessibilityEventRecorderMac::AccessibilityEventRecorderMac(
     BrowserAccessibilityManager* manager,
     base::ProcessId pid,
-    const AXTreeSelector& selector) {
+    const AXTreeSelector& selector)
+    : AccessibilityEventRecorder(manager), observer_run_loop_source_(nullptr) {
   AXUIElementRef node = nil;
   if (pid) {
     node = AXUIElementCreateApplication(pid);
@@ -49,23 +49,6 @@
     }
   }
 
-  return std::make_unique<AccessibilityEventRecorderMac>(manager, pid, node);
-}
-
-std::vector<AccessibilityEventRecorder::TestPass>
-AccessibilityEventRecorder::GetTestPasses() {
-  // Both the Blink pass and native pass use the same recorder
-  return {
-      {"blink", &AccessibilityEventRecorder::Create},
-      {"mac", &AccessibilityEventRecorder::Create},
-  };
-}
-
-AccessibilityEventRecorderMac::AccessibilityEventRecorderMac(
-    BrowserAccessibilityManager* manager,
-    base::ProcessId pid,
-    AXUIElementRef node)
-    : AccessibilityEventRecorder(manager), observer_run_loop_source_(NULL) {
   if (kAXErrorSuccess !=
       AXObserverCreateWithInfoCallback(pid, EventReceivedThunk,
                                        observer_ref_.InitializeInto())) {
diff --git a/content/browser/accessibility/accessibility_event_recorder_uia_win.cc b/content/browser/accessibility/accessibility_event_recorder_uia_win.cc
index 768d56d7..f5df018a 100644
--- a/content/browser/accessibility/accessibility_event_recorder_uia_win.cc
+++ b/content/browser/accessibility/accessibility_event_recorder_uia_win.cc
@@ -45,15 +45,6 @@
 volatile base::subtle::Atomic32 AccessibilityEventRecorderUia::instantiated_ =
     0;
 
-// static
-std::unique_ptr<AccessibilityEventRecorder>
-AccessibilityEventRecorderUia::CreateUia(BrowserAccessibilityManager* manager,
-                                         base::ProcessId pid,
-                                         const AXTreeSelector& selector) {
-  return std::make_unique<AccessibilityEventRecorderUia>(manager, pid,
-                                                         selector.pattern);
-}
-
 AccessibilityEventRecorderUia::AccessibilityEventRecorderUia(
     BrowserAccessibilityManager* manager,
     base::ProcessId pid,
diff --git a/content/browser/accessibility/accessibility_event_recorder_uia_win.h b/content/browser/accessibility/accessibility_event_recorder_uia_win.h
index 9658947..0adaf860 100644
--- a/content/browser/accessibility/accessibility_event_recorder_uia_win.h
+++ b/content/browser/accessibility/accessibility_event_recorder_uia_win.h
@@ -31,11 +31,6 @@
       const base::StringPiece& application_name_match_pattern);
   ~AccessibilityEventRecorderUia() override;
 
-  static std::unique_ptr<AccessibilityEventRecorder> CreateUia(
-      BrowserAccessibilityManager* manager,
-      base::ProcessId pid,
-      const AXTreeSelector& selector);
-
   // Called to ensure the event recorder has finished recording async events.
   void FlushAsyncEvents() override;
 
diff --git a/content/browser/accessibility/accessibility_event_recorder_win.cc b/content/browser/accessibility/accessibility_event_recorder_win.cc
index 55d6760e..324194d 100644
--- a/content/browser/accessibility/accessibility_event_recorder_win.cc
+++ b/content/browser/accessibility/accessibility_event_recorder_win.cc
@@ -80,32 +80,6 @@
     nullptr;
 
 // static
-std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create(
-    BrowserAccessibilityManager* manager,
-    base::ProcessId pid,
-    const AXTreeSelector& selector) {
-  if (!selector.pattern.empty()) {
-    LOG(FATAL) << "Recording accessibility events from an application name "
-                  "match pattern not supported on this platform yet.";
-  }
-
-  return std::make_unique<AccessibilityEventRecorderWin>(manager, pid,
-                                                         selector.pattern);
-}
-
-std::vector<AccessibilityEventRecorder::TestPass>
-AccessibilityEventRecorder::GetTestPasses() {
-  // In addition to the 'Blink' pass, Windows includes two accessibility APIs
-  // that need to be tested independently (MSAA & UIA); the Blink pass uses the
-  // same recorder as the MSAA pass.
-  return {
-      {"blink", &AccessibilityEventRecorder::Create},
-      {"win", &AccessibilityEventRecorder::Create},
-      {"uia", &AccessibilityEventRecorderUia::CreateUia},
-  };
-}
-
-// static
 CALLBACK void AccessibilityEventRecorderWin::WinEventHookThunk(
     HWINEVENTHOOK handle,
     DWORD event,
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index d5deeea..5824701 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -23,7 +23,6 @@
 #include "base/win/scoped_variant.h"
 #include "build/build_config.h"
 #include "content/browser/accessibility/accessibility_browsertest.h"
-#include "content/browser/accessibility/accessibility_event_recorder.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
@@ -835,8 +834,8 @@
   NativeWinEventWaiter(BrowserAccessibilityManager* manager,
                        const std::string& match_pattern)
       : event_recorder_(
-            AccessibilityEventRecorder::Create(manager,
-                                               base::GetCurrentProcId())),
+            AXInspectFactory::CreatePlatformRecorder(manager,
+                                                     base::GetCurrentProcId())),
         match_pattern_(match_pattern) {
     event_recorder_->ListenToEvents(base::BindRepeating(
         &NativeWinEventWaiter::OnEvent, base::Unretained(this)));
@@ -851,7 +850,7 @@
   void Wait() { run_loop_.Run(); }
 
  private:
-  std::unique_ptr<AccessibilityEventRecorder> event_recorder_;
+  std::unique_ptr<ui::AXEventRecorder> event_recorder_;
   std::string match_pattern_;
   base::RunLoop run_loop_;
 };
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index 292d7dce..d4f2695 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -77,8 +77,7 @@
 
 // DumpAccessibilityTestBase
 DumpAccessibilityTestBase::DumpAccessibilityTestBase()
-    : event_recorder_factory_(nullptr),
-      enable_accessibility_after_navigating_(false),
+    : enable_accessibility_after_navigating_(false),
       test_helper_(DumpAccessibilityTestHelper::TestPasses()[GetParam()]) {}
 
 DumpAccessibilityTestBase::~DumpAccessibilityTestBase() {}
@@ -183,21 +182,7 @@
 
 void DumpAccessibilityTestBase::RunTest(const base::FilePath file_path,
                                         const char* file_dir) {
-  // Get all the tree formatters; the test is run independently on each one.
-  auto test_passes = DumpAccessibilityTestHelper::TestPasses();
-  auto event_recorders = AccessibilityEventRecorder::GetTestPasses();
-  CHECK(event_recorders.size() == test_passes.size());
-
-  // The current test number is supplied as a test parameter.
-  size_t current_pass = GetParam();
-  CHECK_LT(current_pass, test_passes.size());
-  CHECK_EQ(test_passes.size(), event_recorders.size());
-
-  event_recorder_factory_ = event_recorders[current_pass].create_recorder;
-
   RunTestForPlatform(file_path, file_dir);
-
-  event_recorder_factory_ = nullptr;
 }
 
 void DumpAccessibilityTestBase::RunTestForPlatform(
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.h b/content/browser/accessibility/dump_accessibility_browsertest_base.h
index 1b044f7..08b9804 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.h
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.h
@@ -11,7 +11,6 @@
 
 #include "base/strings/string16.h"
 #include "base/test/scoped_feature_list.h"
-#include "content/browser/accessibility/accessibility_event_recorder.h"
 #include "content/public/browser/ax_inspect_factory.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/dump_accessibility_test_helper.h"
@@ -20,6 +19,7 @@
 namespace content {
 
 class BrowserAccessibility;
+class BrowserAccessibilityManager;
 class DumpAccessibilityTestHelper;
 
 // Base class for an accessibility browsertest that takes an HTML file as
@@ -126,9 +126,6 @@
   // The node filters loaded from the test file.
   std::vector<ui::AXNodeFilter> node_filters_;
 
-  // The current tree-formatter and event-recorder factories.
-  AccessibilityEventRecorder::EventRecorderFactory event_recorder_factory_;
-
   // Whether we should enable accessibility after navigating to the page,
   // otherwise we enable it first.
   bool enable_accessibility_after_navigating_;
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index 55cdfe4e..0191fb1 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -18,7 +18,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
-#include "content/browser/accessibility/accessibility_event_recorder.h"
 #include "content/browser/accessibility/browser_accessibility.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
@@ -101,7 +100,7 @@
   std::string final_tree_;
 };
 
-bool IsRecordingComplete(AccessibilityEventRecorder& event_recorder,
+bool IsRecordingComplete(ui::AXEventRecorder& event_recorder,
                          std::vector<std::string>& run_until) {
   // If no @*-RUN-UNTIL-EVENT directives, then having any events is enough.
   LOG(ERROR) << "=== IsRecordingComplete#1 run_until size=" << run_until.size();
@@ -139,9 +138,13 @@
   bool run_go_again = false;
   std::vector<std::string> result;
   do {
-    // Create a new Event Recorder for the run
-    std::unique_ptr<AccessibilityEventRecorder> event_recorder =
-        event_recorder_factory_(
+    // Create a new Event Recorder for the run.
+    size_t current_pass = GetParam();
+    auto test_passes = DumpAccessibilityTestHelper::TestPasses();
+
+    std::unique_ptr<ui::AXEventRecorder> event_recorder =
+        AXInspectFactory::CreateRecorder(
+            test_passes[current_pass],
             web_contents->GetRootBrowserAccessibilityManager(), pid, {});
     event_recorder->SetOnlyWebEvents(true);
 
@@ -237,9 +240,9 @@
 // Parameterize the tests so that each test-pass is run independently.
 struct DumpAccessibilityEventsTestPassToString {
   std::string operator()(const ::testing::TestParamInfo<size_t>& i) const {
-    auto passes = AccessibilityEventRecorder::GetTestPasses();
+    auto passes = DumpAccessibilityTestHelper::TestPasses();
     CHECK_LT(i.param, passes.size());
-    return passes[i.param].name;
+    return std::string(passes[i.param]);
   }
 };
 
@@ -247,7 +250,7 @@
     All,
     DumpAccessibilityEventsTest,
     ::testing::Range(size_t{0},
-                     AccessibilityEventRecorder::GetTestPasses().size()),
+                     DumpAccessibilityTestHelper::TestPasses().size()),
     DumpAccessibilityEventsTestPassToString());
 
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
diff --git a/content/browser/android/synchronous_compositor_host.cc b/content/browser/android/synchronous_compositor_host.cc
index a8387d3..2741f3c 100644
--- a/content/browser/android/synchronous_compositor_host.cc
+++ b/content/browser/android/synchronous_compositor_host.cc
@@ -93,10 +93,10 @@
       scoped_refptr<SynchronousCompositorSyncCallBridge> bridge,
       int process_id) {
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
-    mojo::MakeSelfOwnedReceiver(
-        std::make_unique<SynchronousCompositorControlHost>(std::move(bridge),
-                                                           process_id),
+    auto host_control_receiver = mojo::MakeSelfOwnedReceiver(
+        std::make_unique<SynchronousCompositorControlHost>(bridge, process_id),
         std::move(receiver));
+    bridge->SetHostControlReceiverOnIOThread(host_control_receiver);
   }
 
   // SynchronousCompositorControlHost overrides.
@@ -168,9 +168,6 @@
   if (outstanding_begin_frame_requests_ && begin_frame_source_)
     begin_frame_source_->RemoveObserver(this);
   client_->DidDestroyCompositor(this, frame_sink_id_);
-  // TODO(crbug.com/1062576): We should shutdown the host_control as well since
-  // the Host was disconnected and we should signal all the waiters that we will
-  // never send a |BeginFrame| and expect any |BeginFrameResponse|.
   bridge_->HostDestroyedOnUIThread();
 }
 
diff --git a/content/browser/android/synchronous_compositor_sync_call_bridge.cc b/content/browser/android/synchronous_compositor_sync_call_bridge.cc
index 34fe0313..94b1bde 100644
--- a/content/browser/android/synchronous_compositor_sync_call_bridge.cc
+++ b/content/browser/android/synchronous_compositor_sync_call_bridge.cc
@@ -116,6 +116,11 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(host_);
   host_ = nullptr;
+  GetIOThreadTaskRunner({})->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &SynchronousCompositorSyncCallBridge::CloseHostControlOnIOThread,
+          this));
 }
 
 bool SynchronousCompositorSyncCallBridge::IsRemoteReadyOnUIThread() {
@@ -172,4 +177,19 @@
   begin_frame_condition_.Signal();
 }
 
+void SynchronousCompositorSyncCallBridge::SetHostControlReceiverOnIOThread(
+    mojo::SelfOwnedReceiverRef<blink::mojom::SynchronousCompositorControlHost>
+        host_control_receiver) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  host_control_receiver_ = host_control_receiver;
+}
+
+void SynchronousCompositorSyncCallBridge::CloseHostControlOnIOThread() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (host_control_receiver_) {
+    host_control_receiver_->Close();
+    host_control_receiver_.reset();
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/android/synchronous_compositor_sync_call_bridge.h b/content/browser/android/synchronous_compositor_sync_call_bridge.h
index 1699c750..b32d156 100644
--- a/content/browser/android/synchronous_compositor_sync_call_bridge.h
+++ b/content/browser/android/synchronous_compositor_sync_call_bridge.h
@@ -11,6 +11,7 @@
 #include "base/thread_annotations.h"
 #include "components/viz/common/quads/compositor_frame.h"
 #include "content/public/browser/android/synchronous_compositor.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "third_party/blink/public/mojom/input/synchronous_compositor.mojom.h"
 
 namespace content {
@@ -106,6 +107,12 @@
   // Return whether the remote side is ready.
   bool IsRemoteReadyOnUIThread();
 
+  // Set a weak reference to host control receiver then we can close the host
+  // control when the host was destroyed.
+  void SetHostControlReceiverOnIOThread(
+      mojo::SelfOwnedReceiverRef<blink::mojom::SynchronousCompositorControlHost>
+          host_control_receiver);
+
  private:
   friend class base::RefCountedThreadSafe<SynchronousCompositorSyncCallBridge>;
   ~SynchronousCompositorSyncCallBridge();
@@ -122,6 +129,9 @@
   void SignalRemoteClosedToAllWaitersOnIOThread()
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
+  // Close the host control on io thread.
+  void CloseHostControlOnIOThread();
+
   using FrameFutureQueue =
       base::circular_deque<scoped_refptr<SynchronousCompositor::FrameFuture>>;
 
@@ -129,6 +139,9 @@
 
   // UI thread only.
   SynchronousCompositorHost* host_;
+  // This handles the host control receiver in browser side.
+  mojo::SelfOwnedReceiverRef<blink::mojom::SynchronousCompositorControlHost>
+      host_control_receiver_;
 
   // Shared variables between the IO thread and UI thread.
   base::Lock lock_;
diff --git a/content/browser/indexed_db/indexed_db_control_wrapper.cc b/content/browser/indexed_db/indexed_db_control_wrapper.cc
index 249faab2..55b4c83 100644
--- a/content/browser/indexed_db/indexed_db_control_wrapper.cc
+++ b/content/browser/indexed_db/indexed_db_control_wrapper.cc
@@ -71,6 +71,7 @@
 IndexedDBControlWrapper::~IndexedDBControlWrapper() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  context_->Shutdown();
   IndexedDBContextImpl::ReleaseOnIDBSequence(std::move(context_));
 }
 
diff --git a/content/browser/media/media_interface_proxy.cc b/content/browser/media/media_interface_proxy.cc
index f753117..c5e7008 100644
--- a/content/browser/media/media_interface_proxy.cc
+++ b/content/browser/media/media_interface_proxy.cc
@@ -53,7 +53,7 @@
 #endif  // defined(OS_MAC)
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
-#include "chromeos/constants/chromeos_features.h"
+#include "ash/constants/ash_features.h"
 #endif  // BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 #endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
diff --git a/content/browser/service_sandbox_type.h b/content/browser/service_sandbox_type.h
index b30dd0ff..653efc9 100644
--- a/content/browser/service_sandbox_type.h
+++ b/content/browser/service_sandbox_type.h
@@ -5,14 +5,38 @@
 #ifndef CONTENT_BROWSER_SERVICE_SANDBOX_TYPE_H_
 #define CONTENT_BROWSER_SERVICE_SANDBOX_TYPE_H_
 
-#include "base/feature_list.h"
 #include "build/build_config.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/service_process_host.h"
 #include "content/public/common/content_client.h"
-#include "sandbox/policy/features.h"
 #include "sandbox/policy/sandbox_type.h"
 
+#if !defined(OS_MAC)
+#include "base/feature_list.h"
+#include "sandbox/policy/features.h"
+#endif
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+namespace {
+
+bool isNetworkSandboxEnabled() {
+#if defined(OS_MAC)
+  return true;
+#else
+#if defined(OS_WIN)
+  if (base::win::GetVersion() < base::win::Version::WIN10)
+    return false;
+#endif  // defined(OS_WIN)
+  return base::FeatureList::IsEnabled(
+      sandbox::policy::features::kNetworkServiceSandbox);
+#endif  // defined(OS_MAC)
+}
+
+}  // namespace
+
 // This file maps service classes to sandbox types.  Services which
 // require a non-utility sandbox can be added here.  See
 // ServiceProcessHost::Launch() for how these templates are consumed.
@@ -52,14 +76,8 @@
 template <>
 inline sandbox::policy::SandboxType
 content::GetServiceSandboxType<network::mojom::NetworkService>() {
-#if defined(OS_MAC)
-  return sandbox::policy::SandboxType::kNetwork;
-#else
-  return base::FeatureList::IsEnabled(
-             sandbox::policy::features::kNetworkServiceSandbox)
-             ? sandbox::policy::SandboxType::kNetwork
-             : sandbox::policy::SandboxType::kNoSandbox;
-#endif  // defined(OS_MAC)
+  return isNetworkSandboxEnabled() ? sandbox::policy::SandboxType::kNetwork
+                                   : sandbox::policy::SandboxType::kNoSandbox;
 }
 
 // device::mojom::XRDeviceService
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 5b95031..213bbed 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -1095,9 +1095,6 @@
   if (GetServiceWorkerContext())
     GetServiceWorkerContext()->Shutdown();
 
-  if (GetIndexedDBContextInternal())
-    GetIndexedDBContextInternal()->Shutdown();
-
   if (cache_storage_context_)
     cache_storage_context_->Shutdown();
 
@@ -1480,11 +1477,6 @@
   return *indexed_db_control_wrapper_.get();
 }
 
-IndexedDBContextImpl* StoragePartitionImpl::GetIndexedDBContextInternal() {
-  DCHECK(initialized_);
-  return indexed_db_control_wrapper_->GetIndexedDBContextInternal();
-}
-
 FileSystemAccessEntryFactory*
 StoragePartitionImpl::GetFileSystemAccessEntryFactory() {
   DCHECK(initialized_);
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index fa14d8e0..23f1c62 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -83,7 +83,6 @@
 class CookieStoreContext;
 class FontAccessContext;
 class GeneratedCodeCacheContext;
-class IndexedDBContextImpl;
 class FileSystemAccessEntryFactory;
 class FileSystemAccessManagerImpl;
 class NativeIOContext;
@@ -483,8 +482,6 @@
   network::mojom::URLLoaderFactory*
   GetURLLoaderFactoryForBrowserProcessInternal(bool corb_enabled);
 
-  IndexedDBContextImpl* GetIndexedDBContextInternal();
-
   // If |local_trust_token_fulfiller_| is bound, returns immediately.
   //
   // Otherwise, if it's supported by the environment, attempts to bind
diff --git a/content/browser/utility_sandbox_delegate.h b/content/browser/utility_sandbox_delegate.h
index 13a23f33..f070fa9 100644
--- a/content/browser/utility_sandbox_delegate.h
+++ b/content/browser/utility_sandbox_delegate.h
@@ -37,6 +37,7 @@
   bool DisableDefaultPolicy() override;
   bool ShouldLaunchElevated() override;
   bool PreSpawnTarget(sandbox::TargetPolicy* policy) override;
+  bool ShouldUnsandboxedRunInJob() override;
 #endif  // OS_WIN
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
diff --git a/content/browser/utility_sandbox_delegate_win.cc b/content/browser/utility_sandbox_delegate_win.cc
index 8b6f50b..8be3fd7 100644
--- a/content/browser/utility_sandbox_delegate_win.cc
+++ b/content/browser/utility_sandbox_delegate_win.cc
@@ -9,12 +9,14 @@
 #include "base/strings/utf_string_conversions.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/content_client.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
 #include "sandbox/policy/features.h"
 #include "sandbox/policy/sandbox_type.h"
 #include "sandbox/policy/win/sandbox_win.h"
 #include "sandbox/win/src/sandbox_policy.h"
 #include "sandbox/win/src/sandbox_types.h"
+#include "services/network/public/mojom/network_service.mojom.h"
 
 namespace content {
 namespace {
@@ -57,19 +59,44 @@
   return true;
 }
 
-// Right now, this policy is essentially unsandboxed, but with default process
-// mitigations applied.
-// TODO(https://crbug.com/841001) This will be tighted up in future releases.
-bool NetworkPreSpawnTarget(sandbox::TargetPolicy* policy,
-                           const base::CommandLine& cmd_line) {
-  sandbox::ResultCode result = policy->SetTokenLevel(sandbox::USER_UNPROTECTED,
-                                                     sandbox::USER_UNPROTECTED);
-  if (result != sandbox::ResultCode::SBOX_ALL_OK)
+// Sets the sandbox policy for the network service process.
+bool NetworkPreSpawnTarget(sandbox::TargetPolicy* policy) {
+  // USER_LIMITED is as tight as this sandbox can be, because
+  // DNS running in-process is blocked by USER_RESTRICTED and
+  // below as it can't connect to the service.
+  if (policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
+                            sandbox::USER_LIMITED) != sandbox::SBOX_ALL_OK)
     return false;
-  result = sandbox::policy::SandboxWin::SetJobLevel(
-      cmd_line, sandbox::JOB_UNPROTECTED, 0, policy);
-  if (result != sandbox::ResultCode::SBOX_ALL_OK)
+
+  auto permitted_paths =
+      GetContentClient()->browser()->GetNetworkContextsParentDirectory();
+
+  for (auto permitted_path : permitted_paths) {
+    permitted_path = permitted_path.Append(FILE_PATH_LITERAL("*"));
+    if (policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
+                        sandbox::TargetPolicy::FILES_ALLOW_ANY,
+                        permitted_path.value().c_str()) !=
+        sandbox::SBOX_ALL_OK) {
+      return false;
+    }
+  }
+
+  // DNS needs to read policies which are ACLed NT AUTHORITY\Authenticated Users
+  // Allow ReadKey unlike the rest of HKLM which is BUILTIN\Users Allow ReadKey.
+  if (policy->AddRule(
+          sandbox::TargetPolicy::SUBSYS_REGISTRY,
+          sandbox::TargetPolicy::REG_ALLOW_READONLY,
+          L"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\*") !=
+      sandbox::SBOX_ALL_OK) {
     return false;
+  }
+
+  // Needed for ::GetAdaptersAddresses calls in //net.
+  if (policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
+                      sandbox::TargetPolicy::FILES_ALLOW_READONLY,
+                      L"\\DEVICE\\NETBT_TCPIP\\*") != sandbox::SBOX_ALL_OK) {
+    return false;
+  }
   return true;
 }
 }  // namespace
@@ -91,10 +118,6 @@
       // Default policy is disabled for audio process to allow audio drivers
       // to read device properties (https://crbug.com/883326).
       return true;
-    case sandbox::policy::SandboxType::kNetwork:
-      // Default policy is disabled for network process to allow incremental
-      // sandbox mitigations to be applied via experiments.
-      return true;
     case sandbox::policy::SandboxType::kXrCompositing:
       return base::FeatureList::IsEnabled(
           sandbox::policy::features::kXRSandbox);
@@ -115,7 +138,7 @@
 bool UtilitySandboxedProcessLauncherDelegate::PreSpawnTarget(
     sandbox::TargetPolicy* policy) {
   if (sandbox_type_ == sandbox::policy::SandboxType::kNetwork) {
-    if (!NetworkPreSpawnTarget(policy, cmd_line_))
+    if (!NetworkPreSpawnTarget(policy))
       return false;
   }
 
@@ -209,4 +232,12 @@
       policy, sandbox_type_, ContentBrowserClient::ChildSpawnFlags::NONE);
 }
 
+bool UtilitySandboxedProcessLauncherDelegate::ShouldUnsandboxedRunInJob() {
+  auto utility_sub_type =
+      cmd_line_.GetSwitchValueASCII(switches::kUtilitySubType);
+  if (utility_sub_type == network::mojom::NetworkService::Name_)
+    return true;
+  return false;
+}
+
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 0e95069..405ebba7 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -49,7 +49,6 @@
 #include "components/download/public/common/download_stats.h"
 #include "components/rappor/public/rappor_utils.h"
 #include "components/url_formatter/url_formatter.h"
-#include "content/browser/accessibility/accessibility_event_recorder.h"
 #include "content/browser/accessibility/browser_accessibility.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/browser_main_loop.h"
@@ -4017,7 +4016,8 @@
     auto* ax_mgr = GetOrCreateRootBrowserAccessibilityManager();
     DCHECK(ax_mgr);
     base::ProcessId pid = base::Process::Current().Pid();
-    event_recorder_ = content::AccessibilityEventRecorder::Create(ax_mgr, pid);
+    event_recorder_ =
+        content::AXInspectFactory::CreatePlatformRecorder(ax_mgr, pid);
     event_recorder_->ListenToEvents(*callback);
   } else {
     if (event_recorder_) {
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index e70f6362..e75e0854 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -352,6 +352,7 @@
           {"BlockHTMLParserOnStyleSheets",
            blink::features::kBlockHTMLParserOnStyleSheets},
           {"CSSColorSchemeUARendering", features::kCSSColorSchemeUARendering},
+          {"DeclarativeShadowDOM", blink::features::kDeclarativeShadowDOM},
           {"FeaturePolicyForClientHints",
            features::kFeaturePolicyForClientHints},
           {"EditingNG", blink::features::kEditingNG},
diff --git a/content/public/browser/ax_inspect_factory.cc b/content/public/browser/ax_inspect_factory.cc
index 95f650f..bddcbbc 100644
--- a/content/public/browser/ax_inspect_factory.cc
+++ b/content/public/browser/ax_inspect_factory.cc
@@ -5,6 +5,7 @@
 #include "content/public/browser/ax_inspect_factory.h"
 
 #include "base/notreached.h"
+#include "content/browser/accessibility/accessibility_event_recorder.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
 #include "ui/base/buildflags.h"
 
@@ -24,6 +25,14 @@
 }
 
 // static
+std::unique_ptr<ui::AXEventRecorder> AXInspectFactory::CreatePlatformRecorder(
+    BrowserAccessibilityManager* manager,
+    base::ProcessId pid,
+    const AXTreeSelector& selector) {
+  return AXInspectFactory::CreateRecorder(kBlink);
+}
+
+// static
 std::unique_ptr<ui::AXTreeFormatter> AXInspectFactory::CreateFormatter(
     AXInspectFactory::Type type) {
   switch (type) {
@@ -35,6 +44,21 @@
   return nullptr;
 }
 
+// static
+std::unique_ptr<ui::AXEventRecorder> AXInspectFactory::CreateRecorder(
+    AXInspectFactory::Type type,
+    BrowserAccessibilityManager* manager,
+    base::ProcessId pid,
+    const AXTreeSelector& selector) {
+  switch (type) {
+    case kBlink:
+      return std::make_unique<AccessibilityEventRecorder>(manager);
+    default:
+      NOTREACHED() << "Unsupported formatter type " << type;
+  }
+  return nullptr;
+}
+
 #endif
 
 AXInspectFactory::Type::operator std::string() const {
diff --git a/content/public/browser/ax_inspect_factory.h b/content/public/browser/ax_inspect_factory.h
index e9114b98..583ba7a 100644
--- a/content/public/browser/ax_inspect_factory.h
+++ b/content/public/browser/ax_inspect_factory.h
@@ -7,11 +7,18 @@
 
 #include <memory>
 
+#include "base/process/process_handle.h"
 #include "content/common/content_export.h"
+#include "ui/accessibility/platform/inspect/ax_event_recorder.h"
 #include "ui/accessibility/platform/inspect/ax_tree_formatter.h"
 
 namespace content {
 
+// TODO: we shouldn't leak internal data types outside of the content module,
+// event recorders can use native platform APIs and avoid dealing
+// with BrowserAccessibilityManager, see crbug.com/1133330.
+class BrowserAccessibilityManager;
+
 // Accessibility tree formatters and event recorders factory.
 class CONTENT_EXPORT AXInspectFactory {
  public:
@@ -21,6 +28,13 @@
   // on Linux or NSAccessibility tree on macOS.
   static std::unique_ptr<ui::AXTreeFormatter> CreatePlatformFormatter();
 
+  // Creates the appropriate event recorder for the platform we are currently
+  // running on.
+  static std::unique_ptr<ui::AXEventRecorder> CreatePlatformRecorder(
+      BrowserAccessibilityManager* manager = nullptr,
+      base::ProcessId pid = 0,
+      const ui::AXTreeSelector& selector = {});
+
   // Creates the internal accessibility tree formatter, AKA the Blink tree
   // formatter, which is used to dump the Blink accessibility tree to a string
   static std::unique_ptr<ui::AXTreeFormatter> CreateBlinkFormatter();
@@ -49,6 +63,13 @@
 
   // Creates a tree formatter of a given inspect type if supported by platform.
   static std::unique_ptr<ui::AXTreeFormatter> CreateFormatter(Type);
+
+  // Creates an event recorder of a given inspect type if supported by platform.
+  static std::unique_ptr<ui::AXEventRecorder> CreateRecorder(
+      Type,
+      BrowserAccessibilityManager* manager = nullptr,
+      base::ProcessId pid = 0,
+      const ui::AXTreeSelector& selector = {});
 };
 
 }  // namespace content
diff --git a/content/public/browser/ax_inspect_factory_android.cc b/content/public/browser/ax_inspect_factory_android.cc
index 1ca71c7..a6ec94e1 100644
--- a/content/public/browser/ax_inspect_factory_android.cc
+++ b/content/public/browser/ax_inspect_factory_android.cc
@@ -5,6 +5,7 @@
 #include "content/public/browser/ax_inspect_factory.h"
 
 #include "base/notreached.h"
+#include "content/browser/accessibility/accessibility_event_recorder.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_android.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
 
@@ -17,6 +18,14 @@
 }
 
 // static
+std::unique_ptr<ui::AXEventRecorder> AXInspectFactory::CreatePlatformRecorder(
+    BrowserAccessibilityManager* manager,
+    base::ProcessId pid,
+    const ui::AXTreeSelector& selector) {
+  return AXInspectFactory::CreateRecorder(kAndroid, manager, pid, selector);
+}
+
+// static
 std::unique_ptr<ui::AXTreeFormatter> AXInspectFactory::CreateFormatter(
     AXInspectFactory::Type type) {
   switch (type) {
@@ -30,4 +39,20 @@
   return nullptr;
 }
 
+// static
+std::unique_ptr<ui::AXEventRecorder> AXInspectFactory::CreateRecorder(
+    AXInspectFactory::Type type,
+    BrowserAccessibilityManager* manager,
+    base::ProcessId pid,
+    const ui::AXTreeSelector& selector) {
+  switch (type) {
+    case kAndroid:
+    case kBlink:
+      return std::make_unique<AccessibilityEventRecorder>(manager);
+    default:
+      NOTREACHED() << "Unsupported formatter type " << type;
+  }
+  return nullptr;
+}
+
 }  // namespace content
diff --git a/content/public/browser/ax_inspect_factory_auralinux.cc b/content/public/browser/ax_inspect_factory_auralinux.cc
index ca63827..21eb096 100644
--- a/content/public/browser/ax_inspect_factory_auralinux.cc
+++ b/content/public/browser/ax_inspect_factory_auralinux.cc
@@ -5,6 +5,7 @@
 #include "content/public/browser/ax_inspect_factory.h"
 
 #include "base/notreached.h"
+#include "content/browser/accessibility/accessibility_event_recorder_auralinux.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_auralinux.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
 
@@ -17,6 +18,14 @@
 }
 
 // static
+std::unique_ptr<ui::AXEventRecorder> AXInspectFactory::CreatePlatformRecorder(
+    BrowserAccessibilityManager* manager,
+    base::ProcessId pid,
+    const ui::AXTreeSelector& selector) {
+  return AXInspectFactory::CreateRecorder(kLinux, manager, pid, selector);
+}
+
+// static
 std::unique_ptr<ui::AXTreeFormatter> AXInspectFactory::CreateFormatter(
     AXInspectFactory::Type type) {
   switch (type) {
@@ -30,4 +39,22 @@
   return nullptr;
 }
 
+// static
+std::unique_ptr<ui::AXEventRecorder> AXInspectFactory::CreateRecorder(
+    AXInspectFactory::Type type,
+    BrowserAccessibilityManager* manager,
+    base::ProcessId pid,
+    const ui::AXTreeSelector& selector) {
+  switch (type) {
+    case kBlink:
+      return std::make_unique<AccessibilityEventRecorder>(manager);
+    case kLinux:
+      return std::make_unique<AccessibilityEventRecorderAuraLinux>(manager, pid,
+                                                                   selector);
+    default:
+      NOTREACHED() << "Unsupported formatter type " << type;
+  }
+  return nullptr;
+}
+
 }  // namespace content
diff --git a/content/public/browser/ax_inspect_factory_mac.mm b/content/public/browser/ax_inspect_factory_mac.mm
index 38626695..64d5dc8 100644
--- a/content/public/browser/ax_inspect_factory_mac.mm
+++ b/content/public/browser/ax_inspect_factory_mac.mm
@@ -4,6 +4,7 @@
 
 #include "content/public/browser/ax_inspect_factory.h"
 
+#include "content/browser/accessibility/accessibility_event_recorder_mac.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_mac.h"
 
@@ -16,6 +17,14 @@
 }
 
 // static
+std::unique_ptr<ui::AXEventRecorder> AXInspectFactory::CreatePlatformRecorder(
+    BrowserAccessibilityManager* manager,
+    base::ProcessId pid,
+    const ui::AXTreeSelector& selector) {
+  return AXInspectFactory::CreateRecorder(kMac, manager, pid, selector);
+}
+
+// static
 std::unique_ptr<ui::AXTreeFormatter> AXInspectFactory::CreateFormatter(
     AXInspectFactory::Type type) {
   switch (type) {
@@ -29,4 +38,22 @@
   return nullptr;
 }
 
+// static
+std::unique_ptr<ui::AXEventRecorder> AXInspectFactory::CreateRecorder(
+    AXInspectFactory::Type type,
+    BrowserAccessibilityManager* manager,
+    base::ProcessId pid,
+    const ui::AXTreeSelector& selector) {
+  switch (type) {
+    case kBlink:
+      return std::make_unique<AccessibilityEventRecorder>(manager);
+    case kMac:
+      return std::make_unique<AccessibilityEventRecorderMac>(manager, pid,
+                                                             selector);
+    default:
+      NOTREACHED() << "Unsupported formatter type " << type;
+  }
+  return nullptr;
+}
+
 }  // namespace content
diff --git a/content/public/browser/ax_inspect_factory_win.cc b/content/public/browser/ax_inspect_factory_win.cc
index 87232c9e..b9f3854 100644
--- a/content/public/browser/ax_inspect_factory_win.cc
+++ b/content/public/browser/ax_inspect_factory_win.cc
@@ -4,8 +4,11 @@
 
 #include "content/public/browser/ax_inspect_factory.h"
 
+#include "base/logging.h"
 #include "base/notreached.h"
 #include "base/win/com_init_util.h"
+#include "content/browser/accessibility/accessibility_event_recorder_uia_win.h"
+#include "content/browser/accessibility/accessibility_event_recorder_win.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_uia_win.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_win.h"
@@ -19,6 +22,14 @@
 }
 
 // static
+std::unique_ptr<ui::AXEventRecorder> AXInspectFactory::CreatePlatformRecorder(
+    BrowserAccessibilityManager* manager,
+    base::ProcessId pid,
+    const ui::AXTreeSelector& selector) {
+  return AXInspectFactory::CreateRecorder(kWinIA2, manager, pid, selector);
+}
+
+// static
 std::unique_ptr<ui::AXTreeFormatter> AXInspectFactory::CreateFormatter(
     AXInspectFactory::Type type) {
   switch (type) {
@@ -36,4 +47,30 @@
   return nullptr;
 }
 
+// static
+std::unique_ptr<ui::AXEventRecorder> AXInspectFactory::CreateRecorder(
+    AXInspectFactory::Type type,
+    BrowserAccessibilityManager* manager,
+    base::ProcessId pid,
+    const ui::AXTreeSelector& selector) {
+  if (!selector.pattern.empty()) {
+    LOG(FATAL) << "Recording accessibility events from an application name "
+                  "match pattern not supported on this platform yet.";
+  }
+
+  switch (type) {
+    case kBlink:
+      return std::make_unique<AccessibilityEventRecorder>(manager);
+    case kWinIA2:
+      return std::make_unique<AccessibilityEventRecorderWin>(manager, pid,
+                                                             selector.pattern);
+    case kWinUIA:
+      return std::make_unique<AccessibilityEventRecorderUia>(manager, pid,
+                                                             selector.pattern);
+    default:
+      NOTREACHED() << "Unsupported formatter type " << type;
+  }
+  return nullptr;
+}
+
 }  // namespace content
diff --git a/content/public/common/sandboxed_process_launcher_delegate.cc b/content/public/common/sandboxed_process_launcher_delegate.cc
index b32286fe..0be58eb 100644
--- a/content/public/common/sandboxed_process_launcher_delegate.cc
+++ b/content/public/common/sandboxed_process_launcher_delegate.cc
@@ -30,6 +30,10 @@
 bool SandboxedProcessLauncherDelegate::ShouldLaunchElevated() {
   return false;
 }
+
+bool SandboxedProcessLauncherDelegate::ShouldUnsandboxedRunInJob() {
+  return false;
+}
 #endif  // defined(OS_WIN)
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
diff --git a/content/public/common/sandboxed_process_launcher_delegate.h b/content/public/common/sandboxed_process_launcher_delegate.h
index 0aebb73b..c88e1f18 100644
--- a/content/public/common/sandboxed_process_launcher_delegate.h
+++ b/content/public/common/sandboxed_process_launcher_delegate.h
@@ -35,6 +35,7 @@
   bool GetAppContainerId(std::string* appcontainer_id) override;
   bool PreSpawnTarget(sandbox::TargetPolicy* policy) override;
   void PostSpawnTarget(base::ProcessHandle process) override;
+  bool ShouldUnsandboxedRunInJob() override;
 
   // Override to return true if the process should be launched as an elevated
   // process (which implies no sandbox).
diff --git a/content/utility/utility_main.cc b/content/utility/utility_main.cc
index fefb91a..267d1604 100644
--- a/content/utility/utility_main.cc
+++ b/content/utility/utility_main.cc
@@ -174,6 +174,13 @@
     // Ensure RtlGenRandom is warm before the token is lowered; otherwise,
     // base::RandBytes() will CHECK fail when v8 is initialized.
     base::RandBytes(&buffer, sizeof(buffer));
+
+    // Network service process needs FWPUCLNT.DLL to be loaded otherwise
+    // getaddrinfo fails.
+    if (sandbox_type == sandbox::policy::SandboxType::kNetwork) {
+      HMODULE fwpuclnt_pin = ::LoadLibrary(L"FWPUCLNT.DLL");
+      UNREFERENCED_PARAMETER(fwpuclnt_pin);
+    }
     g_utility_target_services->LowerToken();
   }
 #endif
diff --git a/device/DEPS b/device/DEPS
index c10373c1..5374692 100644
--- a/device/DEPS
+++ b/device/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+ash/constants",
   "+chromeos",
   "+components/device_event_log",
   "+mojo/public",
diff --git a/device/bluetooth/chromeos/bluetooth_utils.cc b/device/bluetooth/chromeos/bluetooth_utils.cc
index 9a6e393..74cafaf 100644
--- a/device/bluetooth/chromeos/bluetooth_utils.cc
+++ b/device/bluetooth/chromeos/bluetooth_utils.cc
@@ -4,6 +4,7 @@
 
 #include "device/bluetooth/chromeos/bluetooth_utils.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
@@ -12,7 +13,6 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 
 #include "device/base/features.h"
diff --git a/device/bluetooth/chromeos/bluetooth_utils_unittest.cc b/device/bluetooth/chromeos/bluetooth_utils_unittest.cc
index 5743ab90..246408d 100644
--- a/device/bluetooth/chromeos/bluetooth_utils_unittest.cc
+++ b/device/bluetooth/chromeos/bluetooth_utils_unittest.cc
@@ -4,13 +4,13 @@
 
 #include "device/bluetooth/chromeos/bluetooth_utils.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
diff --git a/device/bluetooth/dbus/bluez_dbus_manager.cc b/device/bluetooth/dbus/bluez_dbus_manager.cc
index 9144a1bf..3db8aef1 100644
--- a/device/bluetooth/dbus/bluez_dbus_manager.cc
+++ b/device/bluetooth/dbus/bluez_dbus_manager.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
@@ -16,7 +17,6 @@
 #include "base/threading/thread.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "dbus/bus.h"
 #include "dbus/dbus_statistics.h"
 #include "dbus/message.h"
diff --git a/docs/speed/metrics_changelog/2021_02_cls.md b/docs/speed/metrics_changelog/2021_02_cls.md
new file mode 100644
index 0000000..5758393
--- /dev/null
+++ b/docs/speed/metrics_changelog/2021_02_cls.md
@@ -0,0 +1,11 @@
+# Cumulative Layout Shift Changes in Chrome 90
+
+### Bug fixes involving changes to transform, effect or position
+
+[Source code for change 1](https://chromium-review.googlesource.com/c/chromium/src/+/2660679)
+[Source code for change 2](https://chromium-review.googlesource.com/c/chromium/src/+/2666949)
+[Source code for change 3](https://chromium-review.googlesource.com/c/chromium/src/+/2665761)
+
+## When were users affected?
+
+Chrome 90 is currently scheduled to be released the week of April 30, 2021.
diff --git a/docs/speed/metrics_changelog/cls.md b/docs/speed/metrics_changelog/cls.md
index 112846e..f49a0f0 100644
--- a/docs/speed/metrics_changelog/cls.md
+++ b/docs/speed/metrics_changelog/cls.md
@@ -2,6 +2,10 @@
 
 This is a list of changes to [Cumulative Layout Shift](https://web.dev/cls).
 
+* Chrome 90
+  * Metric definition improvement: [Bug fixes involving changes to transform, effect or position
+](2021_02_cls.md)
+
 * Chrome 89
   * Metric definition improvement: [Ignore layout shift under opacity:0](2020_12_cls.md)
   * Metric definition improvement: [Clip layout shift rect by visual viewport](2020_12_cls.md)
diff --git a/extensions/common/extension.cc b/extensions/common/extension.cc
index 88dbba5c..ab0e3dcc 100644
--- a/extensions/common/extension.cc
+++ b/extensions/common/extension.cc
@@ -766,7 +766,7 @@
     }
   }
 
-  manifest_version_ = manifest_->GetManifestVersion();
+  manifest_version_ = manifest_->manifest_version();
   std::string warning;
   if (!IsManifestSupported(manifest_version_, GetType(), creation_flags_,
                            &warning)) {
diff --git a/extensions/common/manifest.cc b/extensions/common/manifest.cc
index 55f457a..828f439 100644
--- a/extensions/common/manifest.cc
+++ b/extensions/common/manifest.cc
@@ -93,6 +93,15 @@
   return rank;
 }
 
+int GetManifestVersion(const base::DictionaryValue& manifest_value,
+                       Manifest::Type type) {
+  // Platform apps were launched after manifest version 2 was the preferred
+  // version, so they default to that.
+  int manifest_version = type == Manifest::TYPE_PLATFORM_APP ? 2 : 1;
+  manifest_value.GetInteger(keys::kManifestVersion, &manifest_version);
+  return manifest_version;
+}
+
 // Helper class to filter available values from a manifest.
 class AvailableValuesFilter {
  public:
@@ -156,7 +165,7 @@
     return feature
         ->IsAvailableToManifest(manifest.hashed_id(), manifest.type(),
                                 manifest.location(),
-                                manifest.GetManifestVersion())
+                                manifest.manifest_version())
         .is_available();
   }
 
@@ -256,7 +265,8 @@
       hashed_id_(HashedExtensionId(extension_id_)),
       location_(location),
       value_(std::move(value)),
-      type_(GetTypeFromManifestValue(*value_, for_login_screen)) {
+      type_(GetTypeFromManifestValue(*value_, for_login_screen)),
+      manifest_version_(GetManifestVersion(*value_, type_)) {
   DCHECK(!extension_id_.empty());
 
   available_values_ = base::DictionaryValue::From(
@@ -282,7 +292,7 @@
       continue;
 
     Feature::Availability result = map_entry.second->IsAvailableToManifest(
-        hashed_id_, type_, location_, GetManifestVersion());
+        hashed_id_, type_, location_, manifest_version_);
     if (!result.is_available())
       warnings->push_back(InstallWarning(result.message(), map_entry.first));
   }
@@ -375,17 +385,4 @@
          extension_id_ == other.extension_id_;
 }
 
-int Manifest::GetManifestVersion() const {
-  // Platform apps were launched after manifest version 2 was the preferred
-  // version, so they default to that.
-
-  // Subtle: This is also called in the constructor via
-  // `ComputeAvailableValues()`. Hence this should keep relying on |value_| and
-  // not change to using |available_values_| (since it might be uninitialized
-  // when this is called).
-  int manifest_version = type_ == TYPE_PLATFORM_APP ? 2 : 1;
-  value_->GetInteger(keys::kManifestVersion, &manifest_version);
-  return manifest_version;
-}
-
 }  // namespace extensions
diff --git a/extensions/common/manifest.h b/extensions/common/manifest.h
index dcbce5d..dbd2f61 100644
--- a/extensions/common/manifest.h
+++ b/extensions/common/manifest.h
@@ -169,7 +169,7 @@
   // version when making breaking changes to the extension system. If the
   // manifest contains no explicit manifest version, this returns the current
   // system default.
-  int GetManifestVersion() const;
+  int manifest_version() const { return manifest_version_; }
 
   // Returns the manifest type.
   Type type() const { return type_; }
@@ -259,6 +259,8 @@
 
   const Type type_;
 
+  const int manifest_version_;
+
   DISALLOW_COPY_AND_ASSIGN(Manifest);
 };
 
diff --git a/fuchsia/engine/renderer/web_engine_content_renderer_client.cc b/fuchsia/engine/renderer/web_engine_content_renderer_client.cc
index 3198233..ba1c91d 100644
--- a/fuchsia/engine/renderer/web_engine_content_renderer_client.cc
+++ b/fuchsia/engine/renderer/web_engine_content_renderer_client.cc
@@ -7,9 +7,11 @@
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/macros.h"
+#include "base/util/memory_pressure/multi_source_memory_pressure_monitor.h"
 #include "components/cdm/renderer/widevine_key_system_properties.h"
 #include "components/media_control/renderer/media_playback_options.h"
 #include "components/on_load_script_injector/renderer/on_load_script_injector.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/renderer/render_frame.h"
 #include "fuchsia/engine/common/cast_streaming.h"
 #include "fuchsia/engine/renderer/cast_streaming_demuxer.h"
@@ -134,6 +136,17 @@
   DCHECK_EQ(count, 1u);
 }
 
+void WebEngineContentRendererClient::RenderThreadStarted() {
+  // Behavior of browser tests should not depend on things outside of their
+  // control (like the amount of memory on the system running the tests).
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kBrowserTest))
+    return;
+
+  memory_pressure_monitor_ =
+      std::make_unique<util::MultiSourceMemoryPressureMonitor>();
+  memory_pressure_monitor_->Start();
+}
+
 void WebEngineContentRendererClient::RenderFrameCreated(
     content::RenderFrame* render_frame) {
   // Add WebEngine services to the new RenderFrame.
diff --git a/fuchsia/engine/renderer/web_engine_content_renderer_client.h b/fuchsia/engine/renderer/web_engine_content_renderer_client.h
index 8c16a11..9d71857 100644
--- a/fuchsia/engine/renderer/web_engine_content_renderer_client.h
+++ b/fuchsia/engine/renderer/web_engine_content_renderer_client.h
@@ -9,6 +9,10 @@
 #include "content/public/renderer/content_renderer_client.h"
 #include "fuchsia/engine/renderer/web_engine_render_frame_observer.h"
 
+namespace util {
+class MultiSourceMemoryPressureMonitor;
+}  // namespace util
+
 class WebEngineContentRendererClient : public content::ContentRendererClient {
  public:
   WebEngineContentRendererClient();
@@ -25,6 +29,7 @@
   void OnRenderFrameDeleted(int render_frame_id);
 
   // content::ContentRendererClient overrides.
+  void RenderThreadStarted() override;
   void RenderFrameCreated(content::RenderFrame* render_frame) override;
   void AddSupportedKeySystems(
       std::vector<std::unique_ptr<media::KeySystemProperties>>* key_systems)
@@ -48,6 +53,11 @@
   std::map<int, std::unique_ptr<WebEngineRenderFrameObserver>>
       render_frame_id_to_observer_map_;
 
+  // Initiates cache purges and Blink/V8 garbage collection when free memory
+  // is limited.
+  std::unique_ptr<util::MultiSourceMemoryPressureMonitor>
+      memory_pressure_monitor_;
+
   DISALLOW_COPY_AND_ASSIGN(WebEngineContentRendererClient);
 };
 
diff --git a/fuchsia/engine/test/web_engine_test_launcher.cc b/fuchsia/engine/test/web_engine_test_launcher.cc
index 18a8543..7c16e55 100644
--- a/fuchsia/engine/test/web_engine_test_launcher.cc
+++ b/fuchsia/engine/test/web_engine_test_launcher.cc
@@ -54,6 +54,11 @@
   command_line->AppendSwitchASCII(switches::kEnableLogging, "stderr");
   command_line->AppendSwitch(switches::kDisableGpu);
 
+  // Indicate to all processes that they are being run as part of a browser
+  // test, so that dependencies which might compromise test isolation
+  // won't be used (e.g. memory pressure).
+  command_line->AppendSwitch(switches::kBrowserTest);
+
   size_t parallel_jobs = base::NumParallelJobs(/*cores_per_job=*/2);
   if (parallel_jobs == 0U)
     return 1;
diff --git a/headless/lib/browser/headless_content_browser_client.cc b/headless/lib/browser/headless_content_browser_client.cc
index 8bcee472..7acc916f 100644
--- a/headless/lib/browser/headless_content_browser_client.cc
+++ b/headless/lib/browser/headless_content_browser_client.cc
@@ -367,4 +367,11 @@
   stub_badge_service_->Bind(std::move(receiver));
 }
 
+bool HeadlessContentBrowserClient::CanAcceptUntrustedExchangesIfNeeded() {
+  // We require --user-data-dir flag too so that no dangerous changes are made
+  // in the user's regular profile.
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kUserDataDir);
+}
+
 }  // namespace headless
diff --git a/headless/lib/browser/headless_content_browser_client.h b/headless/lib/browser/headless_content_browser_client.h
index e39ac90..6e3272d 100644
--- a/headless/lib/browser/headless_content_browser_client.h
+++ b/headless/lib/browser/headless_content_browser_client.h
@@ -71,6 +71,8 @@
   std::string GetProduct() override;
   std::string GetUserAgent() override;
 
+  bool CanAcceptUntrustedExchangesIfNeeded() override;
+
  private:
   class StubBadgeService;
 
diff --git a/infra/config/generated/commit-queue.cfg b/infra/config/generated/commit-queue.cfg
index 9013217f..241f7df 100644
--- a/infra/config/generated/commit-queue.cfg
+++ b/infra/config/generated/commit-queue.cfg
@@ -1042,6 +1042,10 @@
         includable_only: true
       }
       builders {
+        name: "chromium/try/linux-chromeos-js-code-coverage"
+        includable_only: true
+      }
+      builders {
         name: "chromium/try/linux-chromeos-rel"
         location_regexp: ".*"
         location_regexp_exclude: ".+/[+]/docs/.+"
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 905babb..75138b6 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -42013,6 +42013,68 @@
       }
     }
     builders {
+      name: "linux-chromeos-js-code-coverage"
+      swarming_host: "chromium-swarm.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-16.04"
+      dimensions: "pool:luci.chromium.try"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/master"
+        cmd: "recipes"
+      }
+      properties: "{\"$build/code_coverage\":{\"use_clang_coverage\":true,\"use_javascript_coverage\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"tryserver.chromium.chromiumos\",\"recipe\":\"chromium_trybot\"}"
+      execution_timeout_secs: 14400
+      expiration_secs: 7200
+      caches {
+        name: "win_toolchain"
+        path: "win_toolchain"
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      task_template_canary_percentage {
+        value: 5
+      }
+      experiments {
+        key: "chromium.resultdb.result_sink"
+        value: 100
+      }
+      experiments {
+        key: "chromium.resultdb.result_sink.junit_tests"
+        value: 100
+      }
+      experiments {
+        key: "luci.use_realms"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "gpu_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+    }
+    builders {
       name: "linux-chromeos-rel"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg
index d1ee28d..b6d4c31b 100644
--- a/infra/config/generated/luci-milo.cfg
+++ b/infra/config/generated/luci-milo.cfg
@@ -12545,6 +12545,9 @@
     name: "buildbucket/luci.chromium.try/linux-chromeos-inverse-fieldtrials-fyi-rel"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/linux-chromeos-js-code-coverage"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/linux-chromeos-rel"
   }
   builders {
@@ -13270,6 +13273,9 @@
     name: "buildbucket/luci.chromium.try/linux-chromeos-inverse-fieldtrials-fyi-rel"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/linux-chromeos-js-code-coverage"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/linux-chromeos-rel"
   }
   builders {
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star
index a7fb86a..33b3449 100644
--- a/infra/config/subprojects/chromium/try.star
+++ b/infra/config/subprojects/chromium/try.star
@@ -719,6 +719,12 @@
 )
 
 try_.chromium_chromiumos_builder(
+    name = "linux-chromeos-js-code-coverage",
+    use_clang_coverage = True,
+    use_javascript_coverage = True,
+)
+
+try_.chromium_chromiumos_builder(
     name = "linux-lacros-rel",
     builderless = not settings.is_master,
     cores = 16,
diff --git a/ios/chrome/browser/crash_report/BUILD.gn b/ios/chrome/browser/crash_report/BUILD.gn
index bd3d965..4c5111c 100644
--- a/ios/chrome/browser/crash_report/BUILD.gn
+++ b/ios/chrome/browser/crash_report/BUILD.gn
@@ -29,8 +29,8 @@
   configs += [ "//build/config/compiler:enable_arc" ]
 
   deps = [
-    ":constants",
     "//base",
+    "//components/breadcrumbs/core",
     "//components/crash/core/common",
     "//components/previous_session_info",
     "//components/upload_list",
@@ -44,10 +44,6 @@
   ]
 }
 
-source_set("constants") {
-  sources = [ "crash_reporter_breadcrumb_constants.h" ]
-}
-
 source_set("crash_report_internal") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
@@ -99,11 +95,11 @@
     "synthetic_crash_report_util_unittest.mm",
   ]
   deps = [
-    ":constants",
     ":crash_report",
     ":crash_report_internal",
     "//base",
     "//base/test:test_support",
+    "//components/breadcrumbs/core",
     "//components/previous_session_info",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browser_state:test_support",
diff --git a/ios/chrome/browser/crash_report/DEPS b/ios/chrome/browser/crash_report/DEPS
new file mode 100644
index 0000000..6f0081c
--- /dev/null
+++ b/ios/chrome/browser/crash_report/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/breadcrumbs/core",
+]
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/BUILD.gn b/ios/chrome/browser/crash_report/breadcrumbs/BUILD.gn
index df027900..ee3a627 100644
--- a/ios/chrome/browser/crash_report/breadcrumbs/BUILD.gn
+++ b/ios/chrome/browser/crash_report/breadcrumbs/BUILD.gn
@@ -16,12 +16,12 @@
 source_set("breadcrumbs") {
   deps = [
     "//base",
+    "//components/breadcrumbs/core",
     "//components/infobars/core",
     "//components/keyed_service/core",
     "//components/keyed_service/ios",
     "//ios/chrome/browser:chrome_url_constants",
     "//ios/chrome/browser/browser_state",
-    "//ios/chrome/browser/crash_report:constants",
     "//ios/chrome/browser/infobars",
     "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/overlays",
@@ -80,10 +80,10 @@
     ":breadcrumbs",
     ":generate_not_user_triggered_actions",
     "//base/test:test_support",
+    "//components/breadcrumbs/core",
     "//ios/chrome/browser:chrome_url_constants",
     "//ios/chrome/browser/browser_state:test_support",
     "//ios/chrome/browser/crash_report",
-    "//ios/chrome/browser/crash_report:constants",
     "//ios/chrome/browser/download",
     "//ios/chrome/browser/infobars",
     "//ios/chrome/browser/infobars/test",
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/DEPS b/ios/chrome/browser/crash_report/breadcrumbs/DEPS
new file mode 100644
index 0000000..6f0081c
--- /dev/null
+++ b/ios/chrome/browser/crash_report/breadcrumbs/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/breadcrumbs/core",
+]
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/OWNERS b/ios/chrome/browser/crash_report/breadcrumbs/OWNERS
index 49ba79e..9ac1853 100644
--- a/ios/chrome/browser/crash_report/breadcrumbs/OWNERS
+++ b/ios/chrome/browser/crash_report/breadcrumbs/OWNERS
@@ -1 +1 @@
-michaeldo@chromium.org
+file://components/breadcrumbs/OWNERS
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager.cc b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager.cc
index ddd0c26..fe0baea 100644
--- a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager.cc
+++ b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager.cc
@@ -6,8 +6,8 @@
 
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
+#include "components/breadcrumbs/core/crash_reporter_breadcrumb_constants.h"
 #include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_observer.h"
-#include "ios/chrome/browser/crash_report/crash_reporter_breadcrumb_constants.h"
 
 namespace {
 
@@ -19,7 +19,7 @@
 // upper limit of useful events. (Most events + timestamp breadcrumbs are
 // currently longer than 10 characters.)
 constexpr unsigned long kMaxUsefulBreadcrumbEvents =
-    kMaxBreadcrumbsDataLength / 10;
+    breadcrumbs::kMaxDataLength / 10;
 
 // The minimum number of event buckets to keep, even if they are expired.
 const int kMinEventsBuckets = 2;
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_persistent_storage_manager.h b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_persistent_storage_manager.h
index 2726d5b2..8e117bc 100644
--- a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_persistent_storage_manager.h
+++ b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_persistent_storage_manager.h
@@ -11,15 +11,15 @@
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/timer/timer.h"
+#include "components/breadcrumbs/core/crash_reporter_breadcrumb_constants.h"
 #include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_observer.h"
-#include "ios/chrome/browser/crash_report/crash_reporter_breadcrumb_constants.h"
 
 // The filesize for the file at |breadcrumbs_file_path_|. The file will always
 // be this constant size because it is accessed using a memory mapped file. The
-// file is twice as large as |kMaxBreadcrumbsDataLength| which leaves room for
-// appending breadcrumb events. Once the file is full of events, the contents
-// will be reduced to kMaxBreadcrumbsDataLength.
-constexpr size_t kPersistedFilesizeInBytes = kMaxBreadcrumbsDataLength * 2;
+// file is twice as large as |kMaxDataLength| which leaves room for appending
+// breadcrumb events. Once the file is full of events, the contents will be
+// reduced to kMaxDataLength.
+constexpr size_t kPersistedFilesizeInBytes = breadcrumbs::kMaxDataLength * 2;
 
 namespace base {
 class FilePath;
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_persistent_storage_manager.mm b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_persistent_storage_manager.mm
index 9e017160..0d986a5 100644
--- a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_persistent_storage_manager.mm
+++ b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_persistent_storage_manager.mm
@@ -227,7 +227,7 @@
       const int event_with_seperator_size =
           event_it->size() + strlen(kEventSeparator);
       if (event_with_seperator_size + current_mapped_file_position_.value() >=
-          kMaxBreadcrumbsDataLength) {
+          breadcrumbs::kMaxDataLength) {
         break;
       }
 
diff --git a/ios/chrome/browser/crash_report/breakpad_helper_unittest.mm b/ios/chrome/browser/crash_report/breakpad_helper_unittest.mm
index 15cd1e2..6994a67 100644
--- a/ios/chrome/browser/crash_report/breakpad_helper_unittest.mm
+++ b/ios/chrome/browser/crash_report/breakpad_helper_unittest.mm
@@ -5,9 +5,9 @@
 #import "ios/chrome/browser/crash_report/breakpad_helper.h"
 
 #include "base/strings/sys_string_conversions.h"
+#include "components/breadcrumbs/core/crash_reporter_breadcrumb_constants.h"
 #import "ios/chrome/browser/crash_report/crash_keys_helper.h"
 #include "ios/chrome/browser/crash_report/crash_report_helper.h"
-#include "ios/chrome/browser/crash_report/crash_reporter_breadcrumb_constants.h"
 #include "ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.h"
 #include "ios/chrome/browser/crash_report/main_thread_freeze_detector.h"
 #import "ios/chrome/test/ocmock/OCMockObject+BreakpadControllerTesting.h"
@@ -82,7 +82,7 @@
   crash_keys::MediaStreamPlaybackDidStart();
 
   // Set a max-length breadcrumbs string.
-  std::string breadcrumbs(kMaxBreadcrumbsDataLength, 'A');
+  std::string breadcrumbs(breadcrumbs::kMaxDataLength, 'A');
   crash_keys::SetBreadcrumbEvents(base::SysUTF8ToNSString(breadcrumbs));
 }
 
diff --git a/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_constants.h b/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_constants.h
deleted file mode 100644
index 341ca4ed..0000000
--- a/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_constants.h
+++ /dev/null
@@ -1,14 +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 IOS_CHROME_BROWSER_CRASH_REPORT_CRASH_REPORTER_BREADCRUMB_CONSTANTS_H_
-#define IOS_CHROME_BROWSER_CRASH_REPORT_CRASH_REPORTER_BREADCRUMB_CONSTANTS_H_
-
-// The maximum string length for breadcrumbs data. The breadcrumbs size cannot
-// be larger than the maximum length of a single Breakpad product data value
-// (currently 2550 bytes). This value should be large enough to include enough
-//  events so that they are useful for diagnosing crashes.
-constexpr unsigned long kMaxBreadcrumbsDataLength = 1530;
-
-#endif  // IOS_CHROME_BROWSER_CRASH_REPORT_CRASH_REPORTER_BREADCRUMB_CONSTANTS_H_
diff --git a/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.mm b/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.mm
index 78618eb..aca07ba 100644
--- a/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.mm
+++ b/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.mm
@@ -5,10 +5,10 @@
 #include "ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.h"
 
 #include "base/strings/sys_string_conversions.h"
+#include "components/breadcrumbs/core/crash_reporter_breadcrumb_constants.h"
 #include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager.h"
 #import "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_observer_bridge.h"
 #include "ios/chrome/browser/crash_report/crash_keys_helper.h"
-#include "ios/chrome/browser/crash_report/crash_reporter_breadcrumb_constants.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -89,10 +89,10 @@
 }
 
 - (void)updateBreadcrumbEventsCrashKey {
-  if (_breadcrumbs.length > kMaxBreadcrumbsDataLength) {
+  if (_breadcrumbs.length > breadcrumbs::kMaxDataLength) {
     NSRange trimRange =
-        NSMakeRange(kMaxBreadcrumbsDataLength,
-                    _breadcrumbs.length - kMaxBreadcrumbsDataLength);
+        NSMakeRange(breadcrumbs::kMaxDataLength,
+                    _breadcrumbs.length - breadcrumbs::kMaxDataLength);
     [_breadcrumbs deleteCharactersInRange:trimRange];
   }
 
diff --git a/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer_unittest.mm b/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer_unittest.mm
index 529ada5..fd0b421 100644
--- a/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer_unittest.mm
+++ b/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer_unittest.mm
@@ -7,13 +7,13 @@
 #import "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
 #include "base/test/task_environment.h"
+#include "components/breadcrumbs/core/crash_reporter_breadcrumb_constants.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager.h"
 #include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_keyed_service.h"
 #include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_keyed_service_factory.h"
 #import "ios/chrome/browser/crash_report/breakpad_helper.h"
 #include "ios/chrome/browser/crash_report/crash_keys_helper.h"
-#include "ios/chrome/browser/crash_report/crash_reporter_breadcrumb_constants.h"
 #import "ios/chrome/test/ocmock/OCMockObject+BreakpadControllerTesting.h"
 #import "ios/testing/scoped_block_swizzler.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -141,14 +141,14 @@
 
   // Build a sample breadcrumbs string greater than the maximum allowed size.
   NSMutableString* breadcrumbs = [[NSMutableString alloc] init];
-  while (breadcrumbs.length < kMaxBreadcrumbsDataLength) {
+  while (breadcrumbs.length < breadcrumbs::kMaxDataLength) {
     [breadcrumbs appendString:@"12:01 Fake Breadcrumb Event/n"];
   }
   [breadcrumbs appendString:@"12:01 Fake Breadcrumb Event/n"];
-  ASSERT_GT([breadcrumbs length], kMaxBreadcrumbsDataLength);
+  ASSERT_GT([breadcrumbs length], breadcrumbs::kMaxDataLength);
 
   id validation_block = [OCMArg checkWithBlock:^(id value) {
-    EXPECT_EQ(kMaxBreadcrumbsDataLength, [value length]);
+    EXPECT_EQ(breadcrumbs::kMaxDataLength, [value length]);
     return YES;
   }];
   [[mock_breakpad_controller_ expect]
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
index d1972f4..998ab72 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-f2271e415867b72fb8aa21a5bb6e92cc986d866e
\ No newline at end of file
+6a7f902139eefab707c554567564fc1979f7608a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
index edf18cd..d46a995 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-161b1f72f4cb89f8bca40a243ddd22b7a1f77941
\ No newline at end of file
+7b1cdaefb39ef7bf0255f4d8cf211c64f86e9832
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
index e38f3c6..a4077b31 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-f313f5b0c10336d36aeeca618c3da3e88998de40
\ No newline at end of file
+e9266f2bf3e7a99ab52cbcef3a42c5fa75c396fc
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
index ec5863e..33f74a0 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-c16f0660a041d34845d46b3298328a07c82cc49f
\ No newline at end of file
+686e014f0dc501b9d2a9ee460c1c2bd562455e9d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
index df62eb8..af8869b 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-46a525345f663a514116a62d2aa92e9b9e710e3f
\ No newline at end of file
+b4bfc89e22b13e557c07e884d42257b3a5d90722
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
index 80d0466..036591f 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-8334a3c91838908110eaf84e9ccf015d4611c76d
\ No newline at end of file
+5d34969f1ee1502b87e6dec4218117c7a043e5cf
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
index 33b1ae64..1854acd9 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-f9b5b60d75735c5008b1e2e1fd9af6e169fd4723
\ No newline at end of file
+28aae8925cb5ebb9d29e60feb4544f606f1ffa93
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
index bfe15f24..9efd02e9 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-11b19b76ea2dddc7e3768d678a9de5783d36f29e
\ No newline at end of file
+1a859a0890970d9845462755fdeb7f9d944c0df5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
index 0624b8b..9303d560 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-dca774ddc806ef5504d5e65c9ee47141ebc1ed3c
\ No newline at end of file
+5310fb36cf166ed7586fc74266287938416b0eb0
\ No newline at end of file
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
index d1438ab5..e306807 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
@@ -129,12 +129,12 @@
      * @param name The codec name, e.g. from MediaCodecInfo.getName().
      */
     public static boolean isSoftwareCodec(String name) {
-        // This is structured identically to libstagefright/OMXCodec.cpp .
+        // This is taken from libstagefright/OMXCodec.cpp for pre codec2.
         if (name.startsWith("OMX.google.")) return true;
+        // Codec2 names sw decoders this way. See hardware/google/av/codec2/vndk/C2Store.cpp .
+        if (name.startsWith("c2.google.")) return true;
 
-        if (name.startsWith("OMX.")) return false;
-
-        return true;
+        return false;
     }
 
     /**
diff --git a/media/capture/video/chromeos/DEPS b/media/capture/video/chromeos/DEPS
index e0f9b18..db76c2a 100644
--- a/media/capture/video/chromeos/DEPS
+++ b/media/capture/video/chromeos/DEPS
@@ -1,5 +1,5 @@
 include_rules = [
-  "+chromeos/constants/chromeos_features.h",
+  "+ash/constants/ash_features.h",
   "+chromeos/dbus",
   "+components/chromeos_camera",
   "+third_party/libsync",
diff --git a/media/capture/video/chromeos/camera_device_delegate.cc b/media/capture/video/chromeos/camera_device_delegate.cc
index 0ba7081..4d18a29d 100644
--- a/media/capture/video/chromeos/camera_device_delegate.cc
+++ b/media/capture/video/chromeos/camera_device_delegate.cc
@@ -11,6 +11,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/no_destructor.h"
@@ -18,7 +19,6 @@
 #include "base/posix/safe_strerror.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/trace_event/trace_event.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/capture/mojom/image_capture_types.h"
 #include "media/capture/video/blob_utils.h"
diff --git a/media/gpu/android/codec_allocator.cc b/media/gpu/android/codec_allocator.cc
index 724c54a..0f80ad4 100644
--- a/media/gpu/android/codec_allocator.cc
+++ b/media/gpu/android/codec_allocator.cc
@@ -95,6 +95,16 @@
   if (force_sw_codecs_)
     codec_config->codec_type = CodecType::kSoftware;
 
+  // If we're still allowed to pick any type we want, then limit to software for
+  // low resolution.  https://crbug.com/1166833
+  if (codec_config->codec_type == CodecType::kAny &&
+      (codec_config->initial_expected_coded_size.width() <
+           kMinHardwareResolution.width() ||
+       codec_config->initial_expected_coded_size.height() <
+           kMinHardwareResolution.height())) {
+    codec_config->codec_type = CodecType::kSoftware;
+  }
+
   const auto start_time = tick_clock_->NowTicks();
   pending_operations_.push_back(start_time);
 
diff --git a/media/gpu/android/codec_allocator.h b/media/gpu/android/codec_allocator.h
index 1340d8bc..8f42905 100644
--- a/media/gpu/android/codec_allocator.h
+++ b/media/gpu/android/codec_allocator.h
@@ -31,6 +31,10 @@
 // path is hung up.
 class MEDIA_GPU_EXPORT CodecAllocator {
  public:
+  // Minimum coded size that we'll allow to get a hardware instance, since not
+  // all hw implementation support it.  See crbug.com/1166833 .
+  static constexpr gfx::Size kMinHardwareResolution{96, 96};
+
   static CodecAllocator* GetInstance(
       scoped_refptr<base::SequencedTaskRunner> task_runner);
 
diff --git a/media/gpu/android/codec_allocator_unittest.cc b/media/gpu/android/codec_allocator_unittest.cc
index f9568c33..7b08de5 100644
--- a/media/gpu/android/codec_allocator_unittest.cc
+++ b/media/gpu/android/codec_allocator_unittest.cc
@@ -108,6 +108,16 @@
   MOCK_METHOD1(OnCodecCreated, void(CodecType));
   MOCK_METHOD0(OnCodecReleased, void());
 
+  // Allocate and return a config that allows any codec, and is suitable for
+  // hardware decode.
+  std::unique_ptr<VideoCodecConfig> CreateConfig() {
+    auto config = std::make_unique<VideoCodecConfig>();
+    config->codec_type = CodecType::kAny;
+    config->initial_expected_coded_size =
+        CodecAllocator::kMinHardwareResolution;
+    return config;
+  }
+
  protected:
   // So that we can get the thread's task runner.
   base::test::TaskEnvironment task_environment_;
@@ -130,8 +140,7 @@
 TEST_F(CodecAllocatorTest, NormalCreation) {
   ASSERT_FALSE(IsPrimaryTaskRunnerLikelyHung());
 
-  auto config = std::make_unique<VideoCodecConfig>();
-  config->codec_type = CodecType::kAny;
+  auto config = CreateConfig();
 
   base::RunLoop run_loop;
   allocator_->CreateMediaCodecAsync(
@@ -147,7 +156,7 @@
 TEST_F(CodecAllocatorTest, NormalSecureCreation) {
   ASSERT_FALSE(IsPrimaryTaskRunnerLikelyHung());
 
-  auto config = std::make_unique<VideoCodecConfig>();
+  auto config = CreateConfig();
   config->codec_type = CodecType::kSecure;
 
   base::RunLoop run_loop;
@@ -164,8 +173,7 @@
 TEST_F(CodecAllocatorTest, MultipleCreation) {
   ASSERT_FALSE(IsPrimaryTaskRunnerLikelyHung());
 
-  auto config = std::make_unique<VideoCodecConfig>();
-  config->codec_type = CodecType::kAny;
+  auto config = CreateConfig();
 
   base::RunLoop run_loop;
   allocator_->CreateMediaCodecAsync(
@@ -178,7 +186,7 @@
   tick_clock_.Advance(base::TimeDelta::FromMilliseconds(400));
   ASSERT_FALSE(IsPrimaryTaskRunnerLikelyHung());
 
-  auto config_secure = std::make_unique<VideoCodecConfig>();
+  auto config_secure = CreateConfig();
   config_secure->codec_type = CodecType::kSecure;
 
   allocator_->CreateMediaCodecAsync(
@@ -232,7 +240,7 @@
   ASSERT_FALSE(IsPrimaryTaskRunnerLikelyHung());
 
   // Create codec, but don't pump message loop.
-  auto config = std::make_unique<VideoCodecConfig>();
+  auto config = CreateConfig();
   config->codec_type = CodecType::kSecure;
   allocator_->CreateMediaCodecAsync(base::DoNothing(), std::move(config));
   tick_clock_.Advance(base::TimeDelta::FromSeconds(1));
@@ -249,7 +257,7 @@
   ASSERT_TRUE(IsPrimaryTaskRunnerLikelyHung());
 
   // Secure creation should fail since we're now using software codecs.
-  auto config = std::make_unique<VideoCodecConfig>();
+  auto config = CreateConfig();
   config->codec_type = CodecType::kSecure;
   base::RunLoop run_loop;
   allocator_->CreateMediaCodecAsync(
@@ -280,9 +288,8 @@
   tick_clock_.Advance(base::TimeDelta::FromSeconds(1));
   ASSERT_TRUE(IsPrimaryTaskRunnerLikelyHung());
 
-  // Secure creation should fail since we're now using software codecs.
-  auto config = std::make_unique<VideoCodecConfig>();
-  config->codec_type = CodecType::kAny;
+  // Creation should fall back to software.
+  auto config = CreateConfig();
   base::RunLoop run_loop;
   allocator_->CreateMediaCodecAsync(
       base::BindOnce(&CodecAllocatorTest::OnCodecCreatedInternal,
@@ -312,7 +319,7 @@
   ASSERT_TRUE(IsPrimaryTaskRunnerLikelyHung());
 
   // Release software codec, ensure it runs on secondary task runner.
-  auto config = std::make_unique<VideoCodecConfig>();
+  auto config = CreateConfig();
   config->codec_type = CodecType::kSoftware;
   auto sw_codec = MockMediaCodecBridge::CreateVideoDecoder(*config);
   reinterpret_cast<MockMediaCodecBridge*>(sw_codec.get())
@@ -354,8 +361,7 @@
 
   {
     base::RunLoop run_loop;
-    auto config = std::make_unique<VideoCodecConfig>();
-    config->codec_type = CodecType::kAny;
+    auto config = CreateConfig();
 
     allocator_->CreateMediaCodecAsync(
         base::BindOnce(&CodecAllocatorTest::OnCodecCreatedInternal,
@@ -376,4 +382,18 @@
   }
 }
 
+TEST_F(CodecAllocatorTest, LowResolutionGetsSoftware) {
+  auto config = CreateConfig();
+  config->initial_expected_coded_size =
+      CodecAllocator::kMinHardwareResolution - gfx::Size(1, 1);
+  base::RunLoop run_loop;
+  allocator_->CreateMediaCodecAsync(
+      base::BindOnce(&CodecAllocatorTest::OnCodecCreatedInternal,
+                     base::Unretained(this), run_loop.QuitClosure()),
+      std::move(config));
+
+  EXPECT_CALL(*this, OnCodecCreated(CodecType::kSoftware));
+  run_loop.Run();
+}
+
 }  // namespace media
diff --git a/mojo/core/BUILD.gn b/mojo/core/BUILD.gn
index aeb77dd..ae3c1b23 100644
--- a/mojo/core/BUILD.gn
+++ b/mojo/core/BUILD.gn
@@ -105,6 +105,7 @@
 
     public_deps = [
       "//base",
+      "//mojo/core/embedder:features",
       "//mojo/core/ports",
       "//mojo/public/c/system:headers",
       "//mojo/public/cpp/platform",
@@ -124,6 +125,15 @@
           "channel_posix.h",
         ]
       }
+
+      if ((is_linux || is_chromeos || is_android) && !is_nacl) {
+        sources += [
+          "channel_linux.cc",
+          "channel_linux.h",
+        ]
+
+        public += [ "channel_linux.h" ]
+      }
     }
 
     if (is_mac) {
diff --git a/mojo/core/channel.cc b/mojo/core/channel.cc
index 4fe42510..8609404 100644
--- a/mojo/core/channel.cc
+++ b/mojo/core/channel.cc
@@ -480,9 +480,7 @@
     data_ = MakeAlignedBuffer(size_);
   }
 
-  ~ReadBuffer() {
-    DCHECK(data_);
-  }
+  ~ReadBuffer() { DCHECK(data_); }
 
   const char* occupied_bytes() const {
     return data_.get() + num_discarded_bytes_;
@@ -729,5 +727,19 @@
   return false;
 }
 
+// Currently only Non-nacl CrOs, Linux, and Android support upgrades.
+#if defined(OS_NACL) || \
+    (!(defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_ANDROID)))
+// static
+MOJO_SYSTEM_IMPL_EXPORT bool Channel::SupportsChannelUpgrade() {
+  return false;
+}
+
+MOJO_SYSTEM_IMPL_EXPORT void Channel::OfferChannelUpgrade() {
+  NOTREACHED();
+  return;
+}
+#endif
+
 }  // namespace core
 }  // namespace mojo
diff --git a/mojo/core/channel.h b/mojo/core/channel.h
index 3b01b39..6e672f05 100644
--- a/mojo/core/channel.h
+++ b/mojo/core/channel.h
@@ -76,6 +76,16 @@
 #endif
       // A normal message that uses Header and can contain extra header values.
       NORMAL,
+
+      // The UPGRADE_OFFER control message offers to upgrade the channel to
+      // another side who has advertised support for an upgraded channel.
+      UPGRADE_OFFER,
+      // The UPGRADE_ACCEPT control message is returned when an upgrade offer is
+      // accepted.
+      UPGRADE_ACCEPT,
+      // The UPGRADE_REJECT control message is returned when the receiver cannot
+      // or chooses not to upgrade the channel.
+      UPGRADE_REJECT,
     };
 
 #pragma pack(push, 1)
@@ -281,7 +291,15 @@
 #if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MAC)
   // At this point only ChannelPosix needs InitFeatures.
   static void set_posix_use_writev(bool use_writev);
-#endif
+#endif  // defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MAC)
+
+  // SupportsChannelUpgrade will return true if this channel is capable of being
+  // upgraded.
+  static bool SupportsChannelUpgrade();
+
+  // OfferChannelUpgrade will inform this channel that it should offer an
+  // upgrade to the remote.
+  void OfferChannelUpgrade();
 
   // Allows the caller to change the Channel's HandlePolicy after construction.
   void set_handle_policy(HandlePolicy policy) { handle_policy_ = policy; }
@@ -328,6 +346,9 @@
 
   Delegate* delegate() const { return delegate_; }
 
+  // Allows the caller to determine the current HandlePolicy.
+  HandlePolicy handle_policy() const { return handle_policy_; }
+
   // Called by the implementation when it wants somewhere to stick data.
   // |*buffer_capacity| may be set by the caller to indicate the desired buffer
   // size. If 0, a sane default size will be used instead.
diff --git a/mojo/core/channel_linux.cc b/mojo/core/channel_linux.cc
new file mode 100644
index 0000000..60a5087
--- /dev/null
+++ b/mojo/core/channel_linux.cc
@@ -0,0 +1,869 @@
+// 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 "mojo/core/channel_linux.h"
+
+#include <fcntl.h>
+#include <linux/futex.h>
+#include <linux/memfd.h>
+#include <sys/eventfd.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <atomic>
+#include <cstring>
+#include <limits>
+#include <memory>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/scoped_file.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory_security_policy.h"
+#include "base/message_loop/message_pump_for_io.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/task_runner.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "mojo/core/core.h"
+#include "mojo/core/embedder/features.h"
+
+namespace mojo {
+namespace core {
+
+// DataAvailableNotifier is a simple interface which allows us to
+// substitute how we notify the reader that we've made data available,
+// implementations might be EventFDNotifier or FutexNotifier.
+class DataAvailableNotifier {
+ public:
+  DataAvailableNotifier() = default;
+  explicit DataAvailableNotifier(base::RepeatingClosure callback)
+      : callback_(std::move(callback)) {}
+
+  virtual ~DataAvailableNotifier() = default;
+
+  // The writer should notify the reader by invoking Notify.
+  virtual bool Notify() = 0;
+
+  // A reader should clear the notification (if appropriate) by calling Clear.
+  virtual bool Clear() = 0;
+
+  // Is_valid will return true if the implementation is valid and can be used.
+  virtual bool is_valid() const = 0;
+
+ protected:
+  // DataAvailable will be called by implementations of DataAvailableNotifier to
+  // dispatch this message into the registered callback.
+  void DataAvailable() {
+    DCHECK(callback_);
+    callback_.Run();
+  }
+
+  base::RepeatingClosure callback_;
+};
+
+namespace {
+
+constexpr int kMemFDSeals = F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW;
+
+std::atomic_bool g_params_set{false};
+std::atomic_bool g_use_shared_mem{false};
+std::atomic_uint32_t g_shared_mem_pages{4};
+
+struct UpgradeOfferMessage {
+  constexpr static int kEventFdNotifier = 1;
+  constexpr static int kSupportedVersion = kEventFdNotifier;
+
+  constexpr static int kDefaultPages = 4;
+
+  int version = kSupportedVersion;
+  int num_pages = kDefaultPages;
+};
+
+constexpr size_t RoundUpToWordBoundary(size_t size) {
+  return (size + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1);
+}
+
+base::ScopedFD CreateSealedMemFD(size_t size) {
+  CHECK_GT(size, 0u);
+  CHECK_EQ(size % base::GetPageSize(), 0u);
+  base::ScopedFD fd(syscall(__NR_memfd_create, "mojo_channel_linux",
+                            MFD_CLOEXEC | MFD_ALLOW_SEALING));
+  if (!fd.is_valid()) {
+    PLOG(ERROR) << "Unable to create memfd for shared memory channel";
+    return {};
+  }
+
+  if (ftruncate(fd.get(), size) < 0) {
+    PLOG(ERROR) << "Unable to truncate memfd for shared memory channel";
+    return {};
+  }
+
+  // We make sure to use F_SEAL_SEAL to prevent any further changes to the
+  // seals and F_SEAL_SHRINK guarantees that we won't accidentally decrease
+  // the size, and similarly F_SEAL_GROW for increasing size.
+  if (fcntl(fd.get(), F_ADD_SEALS, kMemFDSeals) < 0) {
+    PLOG(ERROR) << "Unable to seal memfd for shared memory channel";
+    return {};
+  }
+
+  return fd;
+}
+
+// It's very important that we always verify that the FD we're passing and the
+// FD we're receive is a properly sealed MemFD.
+bool ValidateFDIsProperlySealedMemFD(const base::ScopedFD& fd) {
+  int seals = 0;
+  if ((seals = fcntl(fd.get(), F_GET_SEALS)) < 0) {
+    PLOG(ERROR) << "Unable to get seals on memfd for shared memory channel";
+    return false;
+  }
+
+  return seals == kMemFDSeals;
+}
+
+// EventFDNotifier is an implementation of the DataAvailableNotifier interface
+// which uses EventFDNotifier to signal the reader.
+class EventFDNotifier : public DataAvailableNotifier,
+                        public base::MessagePumpForIO::FdWatcher {
+ public:
+  EventFDNotifier(EventFDNotifier&& efd) = default;
+  ~EventFDNotifier() override { reset(); }
+
+  static constexpr int kEfdFlags = EFD_CLOEXEC | EFD_NONBLOCK;
+
+  static std::unique_ptr<EventFDNotifier> CreateWriteNotifier() {
+    int fd = eventfd(0, kEfdFlags);
+    if (fd < 0) {
+      PLOG(ERROR) << "Unable to create an eventfd";
+      return nullptr;
+    }
+
+    return WrapFD(base::ScopedFD(fd));
+  }
+
+  // The EventFD read notifier MUST be created on the IOThread. Luckily you're
+  // typically creating the read notifier in response to an OFFER_UPGRADE
+  // message which was received on the IOThread.
+  static std::unique_ptr<EventFDNotifier> CreateReadNotifier(
+      base::ScopedFD efd,
+      base::RepeatingClosure cb,
+      scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
+    DCHECK(io_task_runner->RunsTasksInCurrentSequence());
+    DCHECK(cb);
+
+    return WrapFDWithCallback(std::move(efd), std::move(cb), io_task_runner);
+  }
+
+  static bool KernelSupported() {
+    // Try to create an eventfd with bad flags if we get -EINVAL it's supported
+    // if we get -ENOSYS it's not, we also support -EPERM because seccomp
+    // policies can cause it to be returned.
+    int ret = eventfd(0, ~0);
+    PCHECK(ret < 0 && (errno == EINVAL || errno == ENOSYS || errno == EPERM));
+    return (ret < 0 && errno == EINVAL);
+  }
+
+  // DataAvailableNotifier impl:
+  bool Clear() override {
+    uint64_t value = 0;
+    ssize_t res = HANDLE_EINTR(
+        read(fd_.get(), reinterpret_cast<void*>(&value), sizeof(value)));
+    if (res < static_cast<int64_t>(sizeof(value))) {
+      PLOG_IF(ERROR, errno != EWOULDBLOCK) << "eventfd read error";
+    }
+    return res == sizeof(value);
+  }
+
+  bool Notify() override {
+    uint64_t value = 1;
+    ssize_t res = HANDLE_EINTR(write(fd_.get(), &value, sizeof(value)));
+    return res == sizeof(value);
+  }
+
+  bool is_valid() const override { return fd_.is_valid(); }
+
+  // base::MessagePumpForIO::FdWatcher impl:
+  void OnFileCanReadWithoutBlocking(int fd) override {
+    DCHECK(fd == fd_.get());
+
+    // Invoke the callback to inform them that data is available to read.
+    DataAvailable();
+  }
+
+  void OnFileCanWriteWithoutBlocking(int fd) override {}
+
+  base::ScopedFD take() { return std::move(fd_); }
+  base::ScopedFD take_dup() {
+    return base::ScopedFD(HANDLE_EINTR(dup(fd_.get())));
+  }
+
+  void reset() {
+    watcher_.reset();
+    fd_.reset();
+  }
+
+  int fd() { return fd_.get(); }
+
+ private:
+  explicit EventFDNotifier(base::ScopedFD fd) : fd_(std::move(fd)) {}
+  explicit EventFDNotifier(
+      base::ScopedFD fd,
+      base::RepeatingClosure cb,
+      scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
+      : DataAvailableNotifier(std::move(cb)),
+        fd_(std::move(fd)),
+        io_task_runner_(io_task_runner) {
+    DCHECK(watcher_);
+    watcher_ =
+        std::make_unique<base::MessagePumpForIO::FdWatchController>(FROM_HERE);
+    WaitForEventFDOnIOThread();
+  }
+
+  static std::unique_ptr<EventFDNotifier> WrapFD(base::ScopedFD fd) {
+    return base::WrapUnique<EventFDNotifier>(
+        new EventFDNotifier(std::move(fd)));
+  }
+
+  static std::unique_ptr<EventFDNotifier> WrapFDWithCallback(
+      base::ScopedFD fd,
+      base::RepeatingClosure cb,
+      scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
+    return base::WrapUnique<EventFDNotifier>(
+        new EventFDNotifier(std::move(fd), std::move(cb), io_task_runner));
+  }
+
+  void WaitForEventFDOnIOThread() {
+    DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+    base::CurrentIOThread::Get()->WatchFileDescriptor(
+        fd_.get(), true, base::MessagePumpForIO::WATCH_READ, watcher_.get(),
+        this);
+  }
+
+  base::ScopedFD fd_;
+  std::unique_ptr<base::MessagePumpForIO::FdWatchController> watcher_;
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(EventFDNotifier);
+};
+
+}  // namespace
+
+// SharedBuffer is an abstraction around a region of shared memory, it has
+// methods to facilitate safely reading and writing into the shared region.
+// SharedBuffer only handles the access to the shared memory any notifications
+// must be performed separately.
+class ChannelLinux::SharedBuffer {
+ public:
+  SharedBuffer(SharedBuffer&& other) = default;
+  ~SharedBuffer() { reset(); }
+
+  enum class Error { kSuccess = 0, kGeneralError = 1, kControlCorruption = 2 };
+
+  static std::unique_ptr<SharedBuffer> Create(const base::ScopedFD& memfd,
+                                              size_t size) {
+    if (!memfd.is_valid()) {
+      return nullptr;
+    }
+
+    // Enforce the system shared memory security policy.
+    if (!base::SharedMemorySecurityPolicy::AcquireReservationForMapping(size)) {
+      LOG(ERROR)
+          << "Unable to create shared buffer: unable to acquire reservation";
+      return nullptr;
+    }
+
+    uint8_t* ptr = reinterpret_cast<uint8_t*>(
+        mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED,
+             memfd.get(), 0));
+
+    if (ptr == MAP_FAILED) {
+      PLOG(ERROR) << "Unable to map shared memory";
+
+      // Always clean up our reservation if we actually fail to map.
+      base::SharedMemorySecurityPolicy::ReleaseReservationForMapping(size);
+      return nullptr;
+    }
+
+    return base::WrapUnique<SharedBuffer>(new SharedBuffer(ptr, size));
+  }
+
+  uint8_t* usable_region_ptr() const { return base_ptr_ + kReservedSpace; }
+  size_t usable_len() const { return len_ - kReservedSpace; }
+  bool is_valid() const { return base_ptr_ != nullptr && len_ > 0; }
+
+  void reset() {
+    if (is_valid()) {
+      if (munmap(base_ptr_, len_) < 0) {
+        PLOG(ERROR) << "Unable to unmap shared buffer";
+        return;
+      }
+
+      base::SharedMemorySecurityPolicy::ReleaseReservationForMapping(len_);
+      base_ptr_ = nullptr;
+      len_ = 0;
+    }
+  }
+
+  // Only one side should call Initialize, this will initialize the first
+  // sizeof(ControlStructure) bytes as our control structure. This should be
+  // done when offering fast comms.
+  void Initialize() { new (static_cast<void*>(base_ptr_)) ControlStructure; }
+
+  // TryWrite will attempt to append |data| of |len| to the shared buffer, this
+  // call will only succeed if there is no one else trying to write AND there is
+  // enough space currently in the buffer.
+  Error TryWrite(const void* data, size_t len) {
+    DCHECK(data);
+    DCHECK(len);
+
+    if (len > usable_len()) {
+      UMA_HISTOGRAM_COUNTS_100000(
+          "Mojo.Channel.Linux.SharedMemWriteBytes_Fail_TooLarge", len);
+      return Error::kGeneralError;
+    }
+
+    if (!TryLockForWriting()) {
+      UMA_HISTOGRAM_COUNTS_100000(
+          "Mojo.Channel.Linux.SharedMemWriteBytes_Fail_NoLock", len);
+      return Error::kGeneralError;
+    }
+
+    // At this point we know that the space available can only grow because
+    // we're the only writer we will write from write_pos -> end and 0 -> (len
+    // - (end - write_pos)) where end is usable_len().
+    uint32_t cur_read_pos = read_pos().load();
+    uint32_t cur_write_pos = write_pos().load();
+
+    if (!ValidateReadWritePositions(cur_read_pos, cur_write_pos)) {
+      UnlockForWriting();
+      return Error::kControlCorruption;
+    }
+
+    uint32_t space_available =
+        usable_len() - NumBytesInUse(cur_read_pos, cur_write_pos);
+
+    if (space_available <= len) {
+      UnlockForWriting();
+      UMA_HISTOGRAM_COUNTS_100000(
+          "Mojo.Channel.Linux.SharedMemWriteBytes_Fail_NoSpace", len);
+
+      return Error::kGeneralError;
+    }
+
+    // If we do not have enough space from the current write position to the end
+    // then we will be forced to wrap around. If we do have enough space we can
+    // just start writing at the write position, otherwise we start writing at
+    // the write position up to the end of the usable area and then we write the
+    // remainder of the payload starting at position 0.
+    if ((usable_len() - cur_write_pos) > len) {
+      memcpy(usable_region_ptr() + cur_write_pos, data, len);
+    } else {
+      size_t copy1_len = usable_len() - cur_write_pos;
+      memcpy(usable_region_ptr() + cur_write_pos, data, copy1_len);
+      memcpy(usable_region_ptr(),
+             reinterpret_cast<const uint8_t*>(data) + copy1_len,
+             len - copy1_len);
+    }
+
+    // Atomically update the write position.
+    // We also verify that the write position did not advance, it SHOULD NEVER
+    // advance since we were holding the write lock.
+    if (write_pos().exchange((cur_write_pos + len) % usable_len()) !=
+        cur_write_pos) {
+      UnlockForWriting();
+      return Error::kControlCorruption;
+    }
+
+    UnlockForWriting();
+
+    return Error::kSuccess;
+  }
+
+  Error TryReadLocked(void* data, uint32_t len, uint32_t* bytes_read) {
+    uint32_t cur_read_pos = read_pos().load();
+    uint32_t cur_write_pos = write_pos().load();
+
+    if (!ValidateReadWritePositions(cur_read_pos, cur_write_pos)) {
+      return Error::kControlCorruption;
+    }
+
+    // The most we can read is the smaller of what's in use in the shared memory
+    // usable area and the buffer size we've been passed.
+    uint32_t bytes_available_to_read =
+        NumBytesInUse(cur_read_pos, cur_write_pos);
+    bytes_available_to_read = std::min(bytes_available_to_read, len);
+    if (bytes_available_to_read == 0) {
+      *bytes_read = 0;
+      return Error::kSuccess;
+    }
+
+    // We have two cases when reading, the first is the read position is behind
+    // the write position, in that case we can simply read all data between the
+    // read and write position (up to our buffer size). The second case is when
+    // the write position is behind the read position. In this situation we must
+    // read from the read position to the end of the available area, and
+    // continue reading from the 0 position up to the write position or the
+    // maximum buffer size (bytes_available_to_read).
+    if (cur_read_pos < cur_write_pos) {
+      memcpy(data, usable_region_ptr() + cur_read_pos, bytes_available_to_read);
+    } else {
+      // We first start by reading to the end of the the usable area, if we
+      // cannot read all the way (because our buffer is too small, we're done).
+      uint32_t bytes_from_read_to_end = usable_len() - cur_read_pos;
+      bytes_from_read_to_end =
+          std::min(bytes_from_read_to_end, bytes_available_to_read);
+      memcpy(data, usable_region_ptr() + cur_read_pos, bytes_from_read_to_end);
+
+      if (bytes_from_read_to_end < bytes_available_to_read) {
+        memcpy(reinterpret_cast<uint8_t*>(data) + bytes_from_read_to_end,
+               usable_region_ptr(),
+               bytes_available_to_read - bytes_from_read_to_end);
+      }
+    }
+
+    // Atomically update the read position.
+    // We also verify that the read position did not advance, it SHOULD NEVER
+    // advance since we were holding the read lock.
+    uint32_t new_read_pos =
+        (cur_read_pos + bytes_available_to_read) % usable_len();
+    if (read_pos().exchange(new_read_pos) != cur_read_pos) {
+      *bytes_read = 0;
+      return Error::kControlCorruption;
+    }
+
+    *bytes_read = bytes_available_to_read;
+    return Error::kSuccess;
+  }
+
+  bool TryLockForReading() {
+    // We return true if we set the flag (meaning it was false).
+    return !read_flag().test_and_set(std::memory_order_acquire);
+  }
+
+  void UnlockForReading() { read_flag().clear(std::memory_order_release); }
+
+ private:
+  struct ControlStructure {
+    std::atomic_flag write_flag{false};
+    std::atomic_uint32_t write_pos{0};
+
+    std::atomic_flag read_flag{false};
+    std::atomic_uint32_t read_pos{0};
+
+    // If we're using a notification mechanism that relies on futex, make the
+    // space available for one, if not these 32bits are unused. The kernel
+    // requires they be 32bit aligned.
+    alignas(4) volatile uint32_t futex = 0;
+  };
+
+  // This function will only validate that the values provided for write and
+  // read positions are valid based on usable size of the shared memory region.
+  // This should ALWAYS be called before attempting a write or read using
+  // atomically loaded values from the control structure.
+  bool ValidateReadWritePositions(uint32_t read_pos, uint32_t write_pos) {
+    // The only valid values for read and write positions are [0 - usable_len
+    // - 1].
+    if (write_pos >= usable_len()) {
+      LOG(ERROR) << "Write position of shared buffer is currently beyond the "
+                    "usable length";
+      return false;
+    }
+
+    if (read_pos >= usable_len()) {
+      LOG(ERROR) << "Read position of shared buffer is currently beyond the "
+                    "usable length";
+      return false;
+    }
+
+    return true;
+  }
+
+  // NumBytesInUse will calculate how many bytes in the shared buffer are
+  // currently in use.
+  uint32_t NumBytesInUse(uint32_t read_pos, uint32_t write_pos) {
+    uint32_t bytes_in_use = 0;
+    if (read_pos <= write_pos) {
+      bytes_in_use = write_pos - read_pos;
+    } else {
+      bytes_in_use = write_pos + (usable_len() - read_pos);
+    }
+
+    return bytes_in_use;
+  }
+
+  bool TryLockForWriting() {
+    // We return true if we set the flag (meaning it was false).
+    return !write_flag().test_and_set(std::memory_order_acquire);
+  }
+
+  void UnlockForWriting() { write_flag().clear(std::memory_order_release); }
+
+  // This is the space we need to reserve in this shared buffer for our control
+  // structure at the start.
+  constexpr static size_t kReservedSpace =
+      RoundUpToWordBoundary(sizeof(ControlStructure));
+
+  std::atomic_flag& write_flag() {
+    DCHECK(is_valid());
+    return reinterpret_cast<ControlStructure*>(base_ptr_)->write_flag;
+  }
+
+  std::atomic_flag& read_flag() {
+    DCHECK(is_valid());
+    return reinterpret_cast<ControlStructure*>(base_ptr_)->read_flag;
+  }
+
+  std::atomic_uint32_t& read_pos() {
+    DCHECK(is_valid());
+    return reinterpret_cast<ControlStructure*>(base_ptr_)->read_pos;
+  }
+
+  std::atomic_uint32_t& write_pos() {
+    DCHECK(is_valid());
+    return reinterpret_cast<ControlStructure*>(base_ptr_)->write_pos;
+  }
+
+  SharedBuffer(uint8_t* ptr, size_t len) : base_ptr_(ptr), len_(len) {}
+
+  uint8_t* base_ptr_ = nullptr;
+  size_t len_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedBuffer);
+};
+
+ChannelLinux::ChannelLinux(
+    Delegate* delegate,
+    ConnectionParams connection_params,
+    HandlePolicy handle_policy,
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
+    : ChannelPosix(delegate,
+                   std::move(connection_params),
+                   handle_policy,
+                   io_task_runner),
+      num_pages_(g_shared_mem_pages.load()) {}
+
+ChannelLinux::~ChannelLinux() = default;
+
+void ChannelLinux::Write(MessagePtr message) {
+  if (!shared_mem_writer_ || message->has_handles() || reject_writes_) {
+    // Let the ChannelPosix deal with this.
+    return ChannelPosix::Write(std::move(message));
+  }
+
+  // Can we use the fast shared memory buffer?
+  SharedBuffer::Error write_result =
+      write_buffer_->TryWrite(message->data(), message->data_num_bytes());
+  if (write_result == SharedBuffer::Error::kGeneralError) {
+    // We can handle this with the posix channel.
+    return ChannelPosix::Write(std::move(message));
+  } else if (write_result == SharedBuffer::Error::kControlCorruption) {
+    // We will no longer be issuing writes via shared memory, and we will
+    // dispatch a write error.
+    reject_writes_ = true;
+
+    // Theoretically we could fall back to only using PosixChannel::Write
+    // but if this situation happens it's likely something else is going
+    // horribly wrong.
+    io_task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&ChannelLinux::OnWriteError, this,
+                                  Channel::Error::kReceivedMalformedData));
+    return;
+  }
+
+  //  The write with shared memory was successful.
+  UMA_HISTOGRAM_COUNTS_100000("Mojo.Channel.Linux.SharedMemWriteBytes",
+                              message->data_num_bytes());
+  write_notifier_->Notify();
+}
+
+void ChannelLinux::OfferSharedMemUpgrade() {
+  if (!offered_.test_and_set() && UpgradesEnabled()) {
+    // Before we offer we need to make sure we can send handles, if we can't
+    // then no point in trying.
+    if (handle_policy() == HandlePolicy::kAcceptHandles) {
+      OfferSharedMemUpgradeInternal();
+    }
+  }
+}
+
+bool ChannelLinux::OnControlMessage(Message::MessageType message_type,
+                                    const void* payload,
+                                    size_t payload_size,
+                                    std::vector<PlatformHandle> handles) {
+  switch (message_type) {
+    case Message::MessageType::UPGRADE_OFFER: {
+      if (payload_size < sizeof(UpgradeOfferMessage)) {
+        LOG(ERROR) << "Received an UPGRADE_OFFER without a payload";
+        return true;
+      }
+
+      const UpgradeOfferMessage* msg =
+          reinterpret_cast<const UpgradeOfferMessage*>(payload);
+      if (msg->version != UpgradeOfferMessage::kSupportedVersion) {
+        LOG(ERROR) << "Reject shared mem upgrade unexpected version: "
+                   << msg->version;
+        RejectUpgradeOffer();
+        return true;
+      }
+
+      if (handles.size() != 2) {
+        LOG(ERROR) << "Received an UPGRADE_OFFER without two FDs";
+        RejectUpgradeOffer();
+        return true;
+      }
+
+      if (read_buffer_ || read_notifier_) {
+        LOG(ERROR) << "Received an UPGRADE_OFFER on already upgraded channel";
+        return true;
+      }
+
+      base::ScopedFD memfd(handles[0].TakeFD());
+      if (memfd.is_valid() && !ValidateFDIsProperlySealedMemFD(memfd)) {
+        PLOG(ERROR) << "Passed FD was not properly sealed";
+        DLOG(FATAL) << "MemFD was NOT properly sealed";
+        memfd.reset();
+      }
+
+      if (!memfd.is_valid()) {
+        RejectUpgradeOffer();
+        return true;
+      }
+
+      if (msg->num_pages <= 0 || msg->num_pages > 128) {
+        LOG(ERROR) << "SharedMemory upgrade offer was received with invalid "
+                      "number of pages: "
+                   << msg->num_pages;
+        RejectUpgradeOffer();
+      }
+
+      std::unique_ptr<DataAvailableNotifier> read_notifier;
+      if (msg->version == UpgradeOfferMessage::kEventFdNotifier) {
+        read_notifier = EventFDNotifier::CreateReadNotifier(
+            handles[1].TakeFD(),
+            base::BindRepeating(&ChannelLinux::SharedMemReadReady, this),
+            io_task_runner_);
+      }
+
+      if (!read_notifier) {
+        RejectUpgradeOffer();
+        return true;
+      }
+
+      read_notifier_ = std::move(read_notifier);
+
+      std::unique_ptr<SharedBuffer> read_sb = SharedBuffer::Create(
+          std::move(memfd), msg->num_pages * base::GetPageSize());
+      if (!read_sb || !read_sb->is_valid()) {
+        RejectUpgradeOffer();
+        return true;
+      }
+
+      read_buffer_ = std::move(read_sb);
+
+      read_buf_.resize(read_buffer_->usable_len());
+      AcceptUpgradeOffer();
+
+      // And if we haven't offered ourselves just go ahead and do it now.
+      OfferSharedMemUpgrade();
+      return true;
+    }
+
+    case Message::MessageType::UPGRADE_ACCEPT: {
+      if (!write_buffer_ || !write_notifier_ || !write_notifier_->is_valid()) {
+        LOG(ERROR) << "Received unexpected UPGRADE_ACCEPT";
+
+        // Clean up anything that may have been set.
+        shared_mem_writer_ = false;
+        write_buffer_.reset();
+        write_notifier_.reset();
+        return true;
+      }
+
+      shared_mem_writer_ = true;
+      return true;
+    }
+
+    case Message::MessageType::UPGRADE_REJECT: {
+      // We can free our resources.
+      shared_mem_writer_ = false;
+      write_buffer_.reset();
+      write_notifier_.reset();
+
+      return true;
+    }
+    default:
+      break;
+  }
+
+  return ChannelPosix::OnControlMessage(message_type, payload, payload_size,
+                                        std::move(handles));
+}
+
+void ChannelLinux::SharedMemReadReady() {
+  CHECK(read_buffer_);
+  if (read_buffer_->TryLockForReading()) {
+    read_notifier_->Clear();
+    do {
+      uint32_t bytes_read = 0;
+      SharedBuffer::Error read_res = read_buffer_->TryReadLocked(
+          read_buf_.data(), read_buf_.size(), &bytes_read);
+      if (read_res == SharedBuffer::Error::kControlCorruption) {
+        // This is an error we cannot recover from.
+        OnError(Error::kReceivedMalformedData);
+        read_buffer_->UnlockForReading();
+        break;
+      }
+
+      if (bytes_read == 0) {
+        break;
+      }
+
+      UMA_HISTOGRAM_COUNTS_100000("Mojo.Channel.Linux.SharedMemReadBytes",
+                                  bytes_read);
+
+      // Now dispatch the message, we KNOW it's at least one full message
+      // because we checked the message size before putting it into the
+      // shared buffer, this mechanism can never write a partial message.
+      off_t data_offset = 0;
+      while (bytes_read - data_offset > 0) {
+        size_t read_size_hint;
+        DispatchResult result = TryDispatchMessage(
+            base::make_span(
+                reinterpret_cast<char*>(read_buf_.data() + data_offset),
+                bytes_read - data_offset),
+            &read_size_hint);
+
+        // We cannot have a message parse failure, we KNOW that we wrote a
+        // full message if we get one something has gone horribly wrong.
+        if (result != DispatchResult::kOK) {
+          LOG(ERROR) << "Recevied a bad message via shared memory";
+          OnError(Error::kReceivedMalformedData);
+          break;
+        }
+
+        // The next message will start after read_size_hint bytes the writer
+        // guarantees that we wrote a full message and we've guaranteed that the
+        // message was dispatched correctly so we know where the next message
+        // starts.
+        data_offset += read_size_hint;
+      }
+    } while (true);
+    read_buffer_->UnlockForReading();
+  }
+}
+
+void ChannelLinux::OnWriteError(Error error) {
+  reject_writes_ = true;
+  ChannelPosix::OnWriteError(error);
+}
+
+void ChannelLinux::ShutDownOnIOThread() {
+  reject_writes_ = true;
+  read_notifier_.reset();
+  write_notifier_.reset();
+
+  ChannelPosix::ShutDownOnIOThread();
+}
+
+void ChannelLinux::StartOnIOThread() {
+  ChannelPosix::StartOnIOThread();
+}
+
+void ChannelLinux::OfferSharedMemUpgradeInternal() {
+  if (reject_writes_) {
+    return;
+  }
+
+  if (write_buffer_ || write_notifier_) {
+    LOG(ERROR) << "Upgrade attempted on an already upgraded channel";
+    return;
+  }
+
+  const size_t kSize = num_pages_ * base::GetPageSize();
+  base::ScopedFD memfd = CreateSealedMemFD(kSize);
+  if (!memfd.is_valid()) {
+    PLOG(ERROR) << "Unable to create memfd";
+    return;
+  }
+
+  bool properly_sealed = ValidateFDIsProperlySealedMemFD(memfd);
+  if (!properly_sealed) {
+    // We will not attempt an offer, something has gone wrong.
+    LOG(ERROR) << "FD was not properly sealed we cannot offer upgrade.";
+    return;
+  }
+
+  std::unique_ptr<SharedBuffer> write_buffer =
+      SharedBuffer::Create(memfd, kSize);
+  if (!write_buffer || !write_buffer->is_valid()) {
+    PLOG(ERROR) << "Unable to map shared memory";
+    return;
+  }
+
+  write_buffer->Initialize();
+
+  std::unique_ptr<EventFDNotifier> write_notifier =
+      EventFDNotifier::CreateWriteNotifier();
+  if (!write_notifier) {
+    PLOG(ERROR) << "Failed to create eventfd write notifier";
+    return;
+  }
+
+  std::vector<PlatformHandle> fds;
+  fds.emplace_back(std::move(memfd));
+  fds.emplace_back(write_notifier->take_dup());
+
+  write_notifier_ = std::move(write_notifier);
+  write_buffer_ = std::move(write_buffer);
+
+  UpgradeOfferMessage offer_msg;
+  offer_msg.num_pages = num_pages_;
+  MessagePtr msg(new Channel::Message(sizeof(UpgradeOfferMessage),
+                                      /*num handles=*/fds.size(),
+                                      Message::MessageType::UPGRADE_OFFER));
+  msg->SetHandles(std::move(fds));
+  memcpy(msg->mutable_payload(), &offer_msg, sizeof(offer_msg));
+
+  ChannelPosix::Write(std::move(msg));
+}
+
+// static
+bool ChannelLinux::KernelSupportsUpgradeRequirements() {
+  static bool supported = []() -> bool {
+    // Do we have memfd_create support, we check by seeing if we get an -ENOSYS
+    // or an -EINVAL. We also support -EPERM because of seccomp rules this is
+    // another possible outcome.
+    int ret = syscall(__NR_memfd_create, "", ~0);
+    PCHECK(ret < 0 && (errno == EINVAL || errno == ENOSYS || errno == EPERM));
+    bool memfd_supported = (ret < 0 && errno == EINVAL);
+    return memfd_supported && EventFDNotifier::KernelSupported();
+  }();
+  return supported;
+}
+
+// static
+bool ChannelLinux::UpgradesEnabled() {
+  if (!g_params_set.load())
+    return g_use_shared_mem.load();
+
+  return base::FeatureList::IsEnabled(kMojoLinuxChannelSharedMem);
+}
+
+// static
+void ChannelLinux::SetSharedMemParameters(bool enabled, uint32_t num_pages) {
+  g_params_set.store(true);
+  g_use_shared_mem.store(enabled);
+  g_shared_mem_pages.store(num_pages);
+}
+
+}  // namespace core
+}  // namespace mojo
diff --git a/mojo/core/channel_linux.h b/mojo/core/channel_linux.h
new file mode 100644
index 0000000..9793804a
--- /dev/null
+++ b/mojo/core/channel_linux.h
@@ -0,0 +1,95 @@
+// 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 MOJO_CORE_CHANNEL_LINUX_H_
+#define MOJO_CORE_CHANNEL_LINUX_H_
+
+#include <atomic>
+#include <memory>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "mojo/core/channel_posix.h"
+
+namespace mojo {
+namespace core {
+
+class DataAvailableNotifier;
+
+// ChannelLinux is a specialization of ChannelPosix which has support for shared
+// memory via Mojo channel upgrades. By default on Linux, CrOS, and Android
+// every channel will be of type ChannelLinux which can be upgraded at runtime
+// to take advantage of shared memory when all required kernel features are
+// present.
+class MOJO_SYSTEM_IMPL_EXPORT ChannelLinux : public ChannelPosix {
+ public:
+  ChannelLinux(Delegate* delegate,
+               ConnectionParams connection_params,
+               HandlePolicy handle_policy,
+               scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
+
+  ChannelLinux(const ChannelLinux&) = delete;
+  ChannelLinux& operator=(const ChannelLinux&) = delete;
+
+  // KernelSupportsUpgradeRequirements will return true if the kernel supports
+  // the features necessary to use an upgrade channel. How the channel will be
+  // upgraded is an implementation detail and this just tells the caller that
+  // calling Channel::UpgradeChannel() will have some effect.
+  static bool KernelSupportsUpgradeRequirements();
+
+  // Will return true if at least one feature that is available via upgrade is
+  // enabled.
+  static bool UpgradesEnabled();
+
+  // SetSharedMemParams will control whether shared memory is used for this
+  // channel.
+  static void SetSharedMemParameters(bool enabled, uint32_t num_pages);
+
+  // ChannelPosix impl:
+  void Write(MessagePtr message) override;
+  void OfferSharedMemUpgrade();
+  bool OnControlMessage(Message::MessageType message_type,
+                        const void* payload,
+                        size_t payload_size,
+                        std::vector<PlatformHandle> handles) override;
+  void OnWriteError(Error error) override;
+
+  void StartOnIOThread() override;
+  void ShutDownOnIOThread() override;
+
+ private:
+  ~ChannelLinux() override;
+
+  class SharedBuffer;
+
+  void OfferSharedMemUpgradeInternal();
+  void SharedMemReadReady();
+
+  // We only offer once, we use an atomic flag to guarantee no races to offer.
+  std::atomic_flag offered_{false};
+
+  // This flag keeps track of whether or not we've established a shared memory
+  // channel with the remote. If false we always fall back to the PosixChannel
+  // (socket).
+  bool shared_mem_writer_ = false;
+
+  std::unique_ptr<DataAvailableNotifier> write_notifier_;
+  std::unique_ptr<SharedBuffer> write_buffer_;
+
+  std::unique_ptr<DataAvailableNotifier> read_notifier_;
+  std::unique_ptr<SharedBuffer> read_buffer_;
+
+  uint32_t num_pages_ = 0;
+
+  bool reject_writes_ = false;
+
+  // This is a temporary buffer we use to remove messages from the shared buffer
+  // for validation and dispatching.
+  std::vector<uint8_t> read_buf_;
+};
+
+}  // namespace core
+}  // namespace mojo
+
+#endif
diff --git a/mojo/core/channel_posix.cc b/mojo/core/channel_posix.cc
index 2335e8d2..5dd7359 100644
--- a/mojo/core/channel_posix.cc
+++ b/mojo/core/channel_posix.cc
@@ -31,15 +31,20 @@
 #if !defined(OS_NACL)
 #include <limits.h>
 #include <sys/uio.h>
+
+#if (defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID))
+#include "mojo/core/channel_linux.h"
 #endif
 
+#endif  // !defined(OS_NACL)
+
 namespace mojo {
 namespace core {
 
 namespace {
 #if !defined(OS_NACL)
 std::atomic<bool> g_use_writev{false};
-#endif
+#endif  // !defined(OS_NACL)
 
 const size_t kMaxBatchReadCapacity = 256 * 1024;
 }  // namespace
@@ -256,11 +261,11 @@
     ignore_result(server_.TakePlatformHandle());
   }
 #if defined(OS_IOS)
-    fds_to_close_.clear();
+  fds_to_close_.clear();
 #endif
 
-    // May destroy the |this| if it was the last reference.
-    self_ = nullptr;
+  // May destroy the |this| if it was the last reference.
+  self_ = nullptr;
 }
 
 void ChannelPosix::WillDestroyCurrentMessageLoop() {
@@ -273,68 +278,67 @@
   if (server_.is_valid()) {
     CHECK_EQ(fd, server_.platform_handle().GetFD().get());
 #if !defined(OS_NACL)
-      read_watcher_.reset();
-      base::CurrentThread::Get()->RemoveDestructionObserver(this);
+    read_watcher_.reset();
+    base::CurrentThread::Get()->RemoveDestructionObserver(this);
 
-      AcceptSocketConnection(server_.platform_handle().GetFD().get(), &socket_);
-      ignore_result(server_.TakePlatformHandle());
-      if (!socket_.is_valid()) {
-        OnError(Error::kConnectionFailed);
-        return;
-      }
-      StartOnIOThread();
-#else
-      NOTREACHED();
-#endif
+    AcceptSocketConnection(server_.platform_handle().GetFD().get(), &socket_);
+    ignore_result(server_.TakePlatformHandle());
+    if (!socket_.is_valid()) {
+      OnError(Error::kConnectionFailed);
       return;
-  }
-    CHECK_EQ(fd, socket_.get());
-
-    bool validation_error = false;
-    bool read_error = false;
-    size_t next_read_size = 0;
-    size_t buffer_capacity = 0;
-    size_t total_bytes_read = 0;
-    size_t bytes_read = 0;
-    do {
-      buffer_capacity = next_read_size;
-      char* buffer = GetReadBuffer(&buffer_capacity);
-      DCHECK_GT(buffer_capacity, 0u);
-
-      std::vector<base::ScopedFD> incoming_fds;
-      ssize_t read_result =
-          SocketRecvmsg(socket_.get(), buffer, buffer_capacity, &incoming_fds);
-      for (auto& incoming_fd : incoming_fds)
-        incoming_fds_.emplace_back(std::move(incoming_fd));
-
-      if (read_result > 0) {
-        bytes_read = static_cast<size_t>(read_result);
-        total_bytes_read += bytes_read;
-        if (!OnReadComplete(bytes_read, &next_read_size)) {
-          read_error = true;
-          validation_error = true;
-          break;
-        }
-      } else if (read_result == 0 ||
-                 (errno != EAGAIN && errno != EWOULDBLOCK)) {
-        read_error = true;
-        break;
-      } else {
-        // We expect more data but there is none to read. The
-        // FileDescriptorWatcher will wake us up again once there is.
-        DCHECK(errno == EAGAIN || errno == EWOULDBLOCK);
-        return;
-      }
-    } while (bytes_read == buffer_capacity &&
-             total_bytes_read < kMaxBatchReadCapacity && next_read_size > 0);
-    if (read_error) {
-      // Stop receiving read notifications.
-      read_watcher_.reset();
-      if (validation_error)
-        OnError(Error::kReceivedMalformedData);
-      else
-        OnError(Error::kDisconnected);
     }
+    StartOnIOThread();
+#else
+    NOTREACHED();
+#endif
+    return;
+  }
+  CHECK_EQ(fd, socket_.get());
+
+  bool validation_error = false;
+  bool read_error = false;
+  size_t next_read_size = 0;
+  size_t buffer_capacity = 0;
+  size_t total_bytes_read = 0;
+  size_t bytes_read = 0;
+  do {
+    buffer_capacity = next_read_size;
+    char* buffer = GetReadBuffer(&buffer_capacity);
+    DCHECK_GT(buffer_capacity, 0u);
+
+    std::vector<base::ScopedFD> incoming_fds;
+    ssize_t read_result =
+        SocketRecvmsg(socket_.get(), buffer, buffer_capacity, &incoming_fds);
+    for (auto& incoming_fd : incoming_fds)
+      incoming_fds_.emplace_back(std::move(incoming_fd));
+
+    if (read_result > 0) {
+      bytes_read = static_cast<size_t>(read_result);
+      total_bytes_read += bytes_read;
+      if (!OnReadComplete(bytes_read, &next_read_size)) {
+        read_error = true;
+        validation_error = true;
+        break;
+      }
+    } else if (read_result == 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
+      read_error = true;
+      break;
+    } else {
+      // We expect more data but there is none to read. The
+      // FileDescriptorWatcher will wake us up again once there is.
+      DCHECK(errno == EAGAIN || errno == EWOULDBLOCK);
+      return;
+    }
+  } while (bytes_read == buffer_capacity &&
+           total_bytes_read < kMaxBatchReadCapacity && next_read_size > 0);
+  if (read_error) {
+    // Stop receiving read notifications.
+    read_watcher_.reset();
+    if (validation_error)
+      OnError(Error::kReceivedMalformedData);
+    else
+      OnError(Error::kDisconnected);
+  }
 }
 
 void ChannelPosix::OnFileCanWriteWithoutBlocking(int fd) {
@@ -377,29 +381,29 @@
       result = SendmsgWithHandles(socket_.get(), &iov, 1, fds);
       if (result >= 0) {
 #if defined(OS_IOS)
-          // There is a bug in XNU which makes it dangerous to close
-          // a file descriptor while it is in transit. So instead we
-          // store the file descriptor in a set and send a message to
-          // the recipient, which is queued AFTER the message that
-          // sent the FD. The recipient will reply to the message,
-          // letting us know that it is now safe to close the file
-          // descriptor. For more information, see:
-          // http://crbug.com/298276
-          MessagePtr fds_message(new Channel::Message(
-              sizeof(int) * fds.size(), 0, Message::MessageType::HANDLES_SENT));
-          int* fd_data = reinterpret_cast<int*>(fds_message->mutable_payload());
-          for (size_t i = 0; i < fds.size(); ++i)
-            fd_data[i] = fds[i].get();
-          outgoing_messages_.emplace_back(std::move(fds_message), 0);
-          {
-            base::AutoLock l(fds_to_close_lock_);
-            for (auto& fd : fds)
-              fds_to_close_.emplace_back(std::move(fd));
-          }
+        // There is a bug in XNU which makes it dangerous to close
+        // a file descriptor while it is in transit. So instead we
+        // store the file descriptor in a set and send a message to
+        // the recipient, which is queued AFTER the message that
+        // sent the FD. The recipient will reply to the message,
+        // letting us know that it is now safe to close the file
+        // descriptor. For more information, see:
+        // http://crbug.com/298276
+        MessagePtr fds_message(new Channel::Message(
+            sizeof(int) * fds.size(), 0, Message::MessageType::HANDLES_SENT));
+        int* fd_data = reinterpret_cast<int*>(fds_message->mutable_payload());
+        for (size_t i = 0; i < fds.size(); ++i)
+          fd_data[i] = fds[i].get();
+        outgoing_messages_.emplace_back(std::move(fds_message), 0);
+        {
+          base::AutoLock l(fds_to_close_lock_);
+          for (auto& fd : fds)
+            fds_to_close_.emplace_back(std::move(fd));
+        }
 #endif  // defined(OS_IOS)
-          handles_written += num_handles_to_send;
-          DCHECK_LE(handles_written, num_handles);
-          message_view.set_num_handles_sent(handles_written);
+        handles_written += num_handles_to_send;
+        DCHECK_LE(handles_written, num_handles);
+        message_view.set_num_handles_sent(handles_written);
       } else {
         // Message transmission failed, so pull the FDs back into |handles|
         // so they can be held by the Message again.
@@ -413,76 +417,86 @@
                            message_view.data_num_bytes());
     }
 
-      if (result < 0) {
-        if (errno != EAGAIN &&
-            errno != EWOULDBLOCK
+    if (result < 0) {
+      if (errno != EAGAIN &&
+          errno != EWOULDBLOCK
 #if defined(OS_IOS)
-            // On iOS if sendmsg() is trying to send fds between processes and
-            // there isn't enough room in the output buffer to send the fd
-            // structure over atomically then EMSGSIZE is returned.
-            //
-            // EMSGSIZE presents a problem since the system APIs can only call
-            // us when there's room in the socket buffer and not when there is
-            // "enough" room.
-            //
-            // The current behavior is to return to the event loop when EMSGSIZE
-            // is received and hopefull service another FD.  This is however
-            // still technically a busy wait since the event loop will call us
-            // right back until the receiver has read enough data to allow
-            // passing the FD over atomically.
-            && errno != EMSGSIZE
+          // On iOS if sendmsg() is trying to send fds between processes and
+          // there isn't enough room in the output buffer to send the fd
+          // structure over atomically then EMSGSIZE is returned.
+          //
+          // EMSGSIZE presents a problem since the system APIs can only call
+          // us when there's room in the socket buffer and not when there is
+          // "enough" room.
+          //
+          // The current behavior is to return to the event loop when EMSGSIZE
+          // is received and hopefully service another FD.  This is however
+          // still technically a busy wait since the event loop will call us
+          // right back until the receiver has read enough data to allow
+          // passing the FD over atomically.
+          && errno != EMSGSIZE
 #endif
-        ) {
-          return false;
-        }
-        message_view.SetHandles(std::move(handles));
-        outgoing_messages_.emplace_front(std::move(message_view));
-        WaitForWriteOnIOThreadNoLock();
-        return true;
+      ) {
+        return false;
       }
+      message_view.SetHandles(std::move(handles));
+      outgoing_messages_.emplace_front(std::move(message_view));
+      WaitForWriteOnIOThreadNoLock();
+      return true;
+    }
 
-      bytes_written = static_cast<size_t>(result);
+    bytes_written = static_cast<size_t>(result);
   } while (handles_written < num_handles ||
            bytes_written < message_view.data_num_bytes());
 
-    return FlushOutgoingMessagesNoLock();
+  return FlushOutgoingMessagesNoLock();
 }
 
 bool ChannelPosix::FlushOutgoingMessagesNoLock() {
 #if !defined(OS_NACL)
-    if (g_use_writev)
-      return FlushOutgoingMessagesWritevNoLock();
+  if (g_use_writev)
+    return FlushOutgoingMessagesWritevNoLock();
 #endif
 
-    base::circular_deque<MessageView> messages;
-    std::swap(outgoing_messages_, messages);
+  base::circular_deque<MessageView> messages;
+  std::swap(outgoing_messages_, messages);
 
-    if (!messages.empty()) {
-      UMA_HISTOGRAM_COUNTS_1000("Mojo.Channel.WriteQueuePendingMessages",
-                                messages.size());
-    }
+  if (!messages.empty()) {
+    UMA_HISTOGRAM_COUNTS_1000("Mojo.Channel.WriteQueuePendingMessages",
+                              messages.size());
+  }
 
-    while (!messages.empty()) {
-      if (!WriteNoLock(std::move(messages.front())))
-        return false;
+  while (!messages.empty()) {
+    if (!WriteNoLock(std::move(messages.front())))
+      return false;
 
-      messages.pop_front();
-      if (!outgoing_messages_.empty()) {
-        // The message was requeued by WriteNoLock(), so we have to wait for
-        // pipe to become writable again. Repopulate the message queue and exit.
-        // If sending the message triggered any control messages, they may be
-        // in |outgoing_messages_| in addition to or instead of the message
-        // being sent.
-        std::swap(messages, outgoing_messages_);
-        while (!messages.empty()) {
-          outgoing_messages_.push_front(std::move(messages.back()));
-          messages.pop_back();
-        }
-        return true;
+    messages.pop_front();
+    if (!outgoing_messages_.empty()) {
+      // The message was requeued by WriteNoLock(), so we have to wait for
+      // pipe to become writable again. Repopulate the message queue and exit.
+      // If sending the message triggered any control messages, they may be
+      // in |outgoing_messages_| in addition to or instead of the message
+      // being sent.
+      std::swap(messages, outgoing_messages_);
+      while (!messages.empty()) {
+        outgoing_messages_.push_front(std::move(messages.back()));
+        messages.pop_back();
       }
+      return true;
     }
+  }
 
-    return true;
+  return true;
+}
+
+void ChannelPosix::RejectUpgradeOffer() {
+  Write(std::make_unique<Channel::Message>(
+      0, 0, Message::MessageType::UPGRADE_REJECT));
+}
+
+void ChannelPosix::AcceptUpgradeOffer() {
+  Write(std::make_unique<Channel::Message>(
+      0, 0, Message::MessageType::UPGRADE_ACCEPT));
 }
 
 void ChannelPosix::OnWriteError(Error error) {
@@ -607,12 +621,19 @@
 }
 #endif  // !defined(OS_NACL)
 
-#if defined(OS_IOS)
 bool ChannelPosix::OnControlMessage(Message::MessageType message_type,
                                     const void* payload,
                                     size_t payload_size,
                                     std::vector<PlatformHandle> handles) {
   switch (message_type) {
+    case Message::MessageType::UPGRADE_OFFER: {
+      // ChannelPosix itself does not support upgrades, if the message was
+      // delivered here it could have been when this channel was created we
+      // didn't support upgrades but another process does.
+      RejectUpgradeOffer();
+      return true;
+    }
+#if defined(OS_IOS)
     case Message::MessageType::HANDLES_SENT: {
       if (payload_size == 0)
         break;
@@ -633,7 +654,7 @@
         break;
       return true;
     }
-
+#endif
     default:
       break;
   }
@@ -641,6 +662,7 @@
   return false;
 }
 
+#if defined(OS_IOS)
 // Closes handles referenced by |fds|. Returns false if |num_fds| is 0, or if
 // |fds| does not match a sequence of handles in |fds_to_close_|.
 bool ChannelPosix::CloseHandles(const int* fds, size_t num_fds) {
@@ -675,12 +697,12 @@
 }
 #endif  // defined(OS_IOS)
 
-// static
 #if !defined(OS_NACL)
+// static
 void Channel::set_posix_use_writev(bool use_writev) {
   g_use_writev = use_writev;
 }
-#endif
+#endif  // !defined(OS_NACL)
 
 // static
 scoped_refptr<Channel> Channel::Create(
@@ -688,9 +710,33 @@
     ConnectionParams connection_params,
     HandlePolicy handle_policy,
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
+#if !defined(OS_NACL)
+#if (defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID))
+  return new ChannelLinux(delegate, std::move(connection_params), handle_policy,
+                          io_task_runner);
+#endif
+#endif
+
   return new ChannelPosix(delegate, std::move(connection_params), handle_policy,
                           io_task_runner);
 }
 
+#if !defined(OS_NACL)
+#if (defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID))
+// static
+bool Channel::SupportsChannelUpgrade() {
+  return ChannelLinux::KernelSupportsUpgradeRequirements() &&
+         ChannelLinux::UpgradesEnabled();
+}
+
+void Channel::OfferChannelUpgrade() {
+  if (!SupportsChannelUpgrade()) {
+    return;
+  }
+  static_cast<ChannelLinux*>(this)->OfferSharedMemUpgrade();
+}
+#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#endif  // !defined(OS_NACL)
+
 }  // namespace core
 }  // namespace mojo
diff --git a/mojo/core/channel_posix.h b/mojo/core/channel_posix.h
index 33a33aa..e64e64c 100644
--- a/mojo/core/channel_posix.h
+++ b/mojo/core/channel_posix.h
@@ -43,14 +43,28 @@
                               size_t extra_header_size,
                               std::vector<PlatformHandle>* handles,
                               bool* deferred) override;
+  bool OnControlMessage(Message::MessageType message_type,
+                        const void* payload,
+                        size_t payload_size,
+                        std::vector<PlatformHandle> handles) override;
+
+ protected:
+  ~ChannelPosix() override;
+  virtual void StartOnIOThread();
+  virtual void ShutDownOnIOThread();
+  virtual void OnWriteError(Error error);
+
+  void RejectUpgradeOffer();
+  void AcceptUpgradeOffer();
+
+  // Keeps the Channel alive at least until explicit shutdown on the IO thread.
+  scoped_refptr<Channel> self_;
+
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
 
  private:
-  ~ChannelPosix() override;
-
-  void StartOnIOThread();
   void WaitForWriteOnIOThread();
   void WaitForWriteOnIOThreadNoLock();
-  void ShutDownOnIOThread();
 
   // base::CurrentThread::DestructionObserver:
   void WillDestroyCurrentMessageLoop() override;
@@ -78,18 +92,9 @@
 #endif  // !defined(OS_NACL)
 
 #if defined(OS_IOS)
-  bool OnControlMessage(Message::MessageType message_type,
-                        const void* payload,
-                        size_t payload_size,
-                        std::vector<PlatformHandle> handles) override;
   bool CloseHandles(const int* fds, size_t num_fds);
 #endif  // defined(OS_IOS)
 
-  void OnWriteError(Error error);
-
-  // Keeps the Channel alive at least until explicit shutdown on the IO thread.
-  scoped_refptr<Channel> self_;
-
   // We may be initialized with a server socket, in which case this will be
   // valid until it accepts an incoming connection.
   PlatformChannelServerEndpoint server_;
@@ -98,8 +103,6 @@
   // or accepted over |server_|.
   base::ScopedFD socket_;
 
-  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
-
   // These watchers must only be accessed on the IO thread.
   std::unique_ptr<base::MessagePumpForIO::FdWatchController> read_watcher_;
   std::unique_ptr<base::MessagePumpForIO::FdWatchController> write_watcher_;
diff --git a/mojo/core/embedder/BUILD.gn b/mojo/core/embedder/BUILD.gn
index a2b8772..59495848 100644
--- a/mojo/core/embedder/BUILD.gn
+++ b/mojo/core/embedder/BUILD.gn
@@ -21,7 +21,19 @@
   public_deps = [ "//base" ]
 
   deps = [
+    ":features",
     "//mojo/core:embedder_internal",
     "//mojo/public/c/system",
   ]
 }
+
+component("features") {
+  output_name = "mojo_core_embedder_features"
+
+  defines = [ "IS_MOJO_CORE_EMBEDDER_FEATURES_IMPL" ]
+
+  public = [ "features.h" ]
+  sources = [ "features.cc" ]
+
+  public_deps = [ "//base" ]
+}
diff --git a/mojo/core/embedder/configuration.h b/mojo/core/embedder/configuration.h
index f4621dc..41e50ca 100644
--- a/mojo/core/embedder/configuration.h
+++ b/mojo/core/embedder/configuration.h
@@ -39,6 +39,9 @@
 
   // Maximum size of a single shared memory segment, in bytes.
   size_t max_shared_memory_num_bytes = 1024 * 1024 * 1024;
+
+  // If true we will not advertise our capabilities to our peer.
+  bool dont_advertise_capabilities = false;
 };
 
 }  // namespace core
diff --git a/mojo/core/embedder/embedder.cc b/mojo/core/embedder/embedder.cc
index 29b6d05..30189c494 100644
--- a/mojo/core/embedder/embedder.cc
+++ b/mojo/core/embedder/embedder.cc
@@ -15,26 +15,40 @@
 #include "mojo/core/channel.h"
 #include "mojo/core/configuration.h"
 #include "mojo/core/core.h"
+#include "mojo/core/embedder/features.h"
 #include "mojo/core/entrypoints.h"
 #include "mojo/core/node_controller.h"
 #include "mojo/public/c/system/thunks.h"
 
+#if !defined(OS_NACL)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#include "mojo/core/channel_linux.h"
+#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#endif  // !defined(OS_NACL)
+
 namespace mojo {
 namespace core {
 
-namespace {
-#if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MAC)
-const base::Feature kMojoPosixUseWritev{"MojoPosixUseWritev",
-                                        base::FEATURE_DISABLED_BY_DEFAULT};
-#endif
-}  // namespace
-
 // InitFeatures will be called as soon as the base::FeatureList is initialized.
 void InitFeatures() {
 #if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MAC)
   Channel::set_posix_use_writev(
       base::FeatureList::IsEnabled(kMojoPosixUseWritev));
-#endif
+
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+  bool shared_mem_enabled =
+      base::FeatureList::IsEnabled(kMojoLinuxChannelSharedMem);
+  int num_pages = kMojoLinuxChannelSharedMemPages.Get();
+  if (num_pages < 0) {
+    num_pages = 4;
+  } else if (num_pages > 128) {
+    num_pages = 128;
+  }
+
+  ChannelLinux::SetSharedMemParameters(shared_mem_enabled,
+                                       static_cast<unsigned int>(num_pages));
+#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#endif  // defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MAC)
 }
 
 void Init(const Configuration& configuration) {
diff --git a/mojo/core/embedder/features.cc b/mojo/core/embedder/features.cc
new file mode 100644
index 0000000..ed3f4f2
--- /dev/null
+++ b/mojo/core/embedder/features.cc
@@ -0,0 +1,26 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/core/embedder/features.h"
+
+namespace mojo {
+namespace core {
+
+#if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MAC)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+COMPONENT_EXPORT(MOJO_CORE_EMBEDDER_FEATURES)
+const base::Feature kMojoLinuxChannelSharedMem{
+    "MojoLinuxChannelSharedMem", base::FEATURE_DISABLED_BY_DEFAULT};
+COMPONENT_EXPORT(MOJO_CORE_EMBEDDER_FEATURES)
+const base::FeatureParam<int> kMojoLinuxChannelSharedMemPages{
+    &kMojoLinuxChannelSharedMem, "MojoLinuxChannelSharedMemPages", 4};
+#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+
+COMPONENT_EXPORT(MOJO_CORE_EMBEDDER_FEATURES)
+const base::Feature kMojoPosixUseWritev{"MojoPosixUseWritev",
+                                        base::FEATURE_DISABLED_BY_DEFAULT};
+#endif  // defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MAC)
+
+}  // namespace core
+}  // namespace mojo
diff --git a/mojo/core/embedder/features.h b/mojo/core/embedder/features.h
new file mode 100644
index 0000000..5125335
--- /dev/null
+++ b/mojo/core/embedder/features.h
@@ -0,0 +1,27 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_CORE_EMBEDDER_FEATURES_H_
+#define MOJO_CORE_EMBEDDER_FEATURES_H_
+
+#include "base/component_export.h"
+#include "base/feature_list.h"
+#include "build/build_config.h"
+
+namespace mojo {
+namespace core {
+
+#if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MAC)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+extern const base::Feature kMojoLinuxChannelSharedMem;
+extern const base::FeatureParam<int> kMojoLinuxChannelSharedMemPages;
+#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+
+extern const base::Feature kMojoPosixUseWritev;
+#endif  // defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MAC)
+
+}  // namespace core
+}  // namespace mojo
+
+#endif  // MOJO_CORE_EMBEDDER_FEATURES_H_
diff --git a/mojo/core/multiprocess_message_pipe_unittest.cc b/mojo/core/multiprocess_message_pipe_unittest.cc
index 26e2c80..c4e74a21 100644
--- a/mojo/core/multiprocess_message_pipe_unittest.cc
+++ b/mojo/core/multiprocess_message_pipe_unittest.cc
@@ -1371,6 +1371,7 @@
     All,
     MultiprocessMessagePipeTestWithPeerSupport,
     testing::Values(test::MojoTestBase::LaunchType::CHILD,
+                    test::MojoTestBase::LaunchType::CHILD_WITHOUT_CAPABILITIES,
                     test::MojoTestBase::LaunchType::PEER,
                     test::MojoTestBase::LaunchType::ASYNC
 #if !defined(OS_FUCHSIA)
diff --git a/mojo/core/node_channel.cc b/mojo/core/node_channel.cc
index c48fb57..e108f8e 100644
--- a/mojo/core/node_channel.cc
+++ b/mojo/core/node_channel.cc
@@ -59,14 +59,22 @@
   ports::NodeName token;
 };
 
-using AcceptInviteeData = AcceptInviteeDataV0;
+struct alignas(8) AcceptInviteeDataV1 : AcceptInviteeDataV0 {
+  uint64_t capabilities = kNodeCapabilityNone;
+};
+
+using AcceptInviteeData = AcceptInviteeDataV1;
 
 struct alignas(8) AcceptInvitationDataV0 {
   ports::NodeName token;
   ports::NodeName invitee_name;
 };
 
-using AcceptInvitationData = AcceptInvitationDataV0;
+struct alignas(8) AcceptInvitationDataV1 : AcceptInvitationDataV0 {
+  uint64_t capabilities = kNodeCapabilityNone;
+};
+
+using AcceptInvitationData = AcceptInvitationDataV1;
 
 struct alignas(8) AcceptPeerDataV0 {
   ports::NodeName token;
@@ -106,7 +114,12 @@
   ports::NodeName broker_name;
 };
 
-using AcceptBrokerClientData = AcceptBrokerClientDataV0;
+struct alignas(8) AcceptBrokerClientDataV1 : AcceptBrokerClientDataV0 {
+  uint64_t capabilities = kNodeCapabilityNone;
+  uint64_t broker_capabilities = kNodeCapabilityNone;
+};
+
+using AcceptBrokerClientData = AcceptBrokerClientDataV1;
 
 // This is followed by arbitrary payload data which is interpreted as a token
 // string for port location.
@@ -117,15 +130,19 @@
 
 // Used for both REQUEST_INTRODUCTION and INTRODUCE.
 //
-// For INTRODUCE the message also includes a valid platform handle for a channel
-// the receiver may use to communicate with the named node directly, or an
-// invalid platform handle if the node is unknown to the sender or otherwise
-// cannot be introduced.
+// For INTRODUCE the message also includes a valid platform handle for a
+// channel the receiver may use to communicate with the named node directly,
+// or an invalid platform handle if the node is unknown to the sender or
+// otherwise cannot be introduced.
 struct alignas(8) IntroductionDataV0 {
   ports::NodeName name;
 };
 
-using IntroductionData = IntroductionDataV0;
+struct alignas(8) IntroductionDataV1 : IntroductionDataV0 {
+  uint64_t capabilities = kNodeCapabilityNone;
+};
+
+using IntroductionData = IntroductionDataV1;
 
 // This message is just a PlatformHandle. The data struct alignas(8) here has
 // only a padding field to ensure an aligned, non-zero-length payload.
@@ -141,7 +158,8 @@
   ports::NodeName destination;
 };
 
-// This struct alignas(8) is followed by the full payload of a relayed message.
+// This struct alignas(8) is followed by the full payload of a relayed
+// message.
 struct alignas(8) EventMessageFromRelayDataV0 {
   ports::NodeName source;
 };
@@ -190,21 +208,23 @@
   return msg_ptr;
 }
 
-// This method takes a second template argument which is another datatype which
-// represents the smallest size this payload can be to be considered valid this
-// MUST be used when there is more than one version of a message to specify the
-// oldest version of the message.
+// This method takes a second template argument which is another datatype
+// which represents the smallest size this payload can be to be considered
+// valid this MUST be used when there is more than one version of a message to
+// specify the oldest version of the message.
 template <typename DataType, typename MinSizedDataType>
 bool GetMessagePayloadMinimumSized(const void* bytes,
                                    size_t num_bytes,
                                    DataType* out_data) {
   static_assert(sizeof(DataType) > 0, "DataType must have non-zero size.");
-  if (num_bytes < sizeof(Header) + sizeof(MinSizedDataType))
+  if (num_bytes < sizeof(Header) + sizeof(MinSizedDataType)) {
     return false;
+  }
 
-  // Always make sure that the full object is zeored and default constructed as
-  // we may not have the complete type. The default construction allows fields
-  // to be default initialized to be resilient to older message versions.
+  // Always make sure that the full object is zeored and default constructed
+  // as we may not have the complete type. The default construction allows
+  // fields to be default initialized to be resilient to older message
+  // versions.
   memset(out_data, 0, sizeof(*out_data));
   new (out_data) DataType;
 
@@ -322,6 +342,7 @@
       MessageType::ACCEPT_INVITEE, sizeof(AcceptInviteeData), 0, &data);
   data->inviter_name = inviter_name;
   data->token = token;
+  data->capabilities = local_capabilities_;
   WriteChannelMessage(std::move(message));
 }
 
@@ -332,6 +353,7 @@
       MessageType::ACCEPT_INVITATION, sizeof(AcceptInvitationData), 0, &data);
   data->token = token;
   data->invitee_name = invitee_name;
+  data->capabilities = local_capabilities_;
   WriteChannelMessage(std::move(message));
 }
 
@@ -380,7 +402,8 @@
 }
 
 void NodeChannel::AcceptBrokerClient(const ports::NodeName& broker_name,
-                                     PlatformHandle broker_channel) {
+                                     PlatformHandle broker_channel,
+                                     const uint64_t broker_capabilities) {
   AcceptBrokerClientData* data;
   std::vector<PlatformHandle> handles;
   if (broker_channel.is_valid())
@@ -390,6 +413,8 @@
                     sizeof(AcceptBrokerClientData), handles.size(), &data);
   message->SetHandles(std::move(handles));
   data->broker_name = broker_name;
+  data->broker_capabilities = broker_capabilities;
+  data->capabilities = local_capabilities_;
   WriteChannelMessage(std::move(message));
 }
 
@@ -413,7 +438,8 @@
 }
 
 void NodeChannel::Introduce(const ports::NodeName& name,
-                            PlatformHandle channel_handle) {
+                            PlatformHandle channel_handle,
+                            uint64_t capabilities) {
   IntroductionData* data;
   std::vector<PlatformHandle> handles;
   if (channel_handle.is_valid())
@@ -422,6 +448,9 @@
       MessageType::INTRODUCE, sizeof(IntroductionData), handles.size(), &data);
   message->SetHandles(std::move(handles));
   data->name = name;
+  // Note that these are not our capabilities, but the capabilities of the peer
+  // we're introducing.
+  data->capabilities = capabilities;
   WriteChannelMessage(std::move(message));
 }
 
@@ -516,6 +545,7 @@
                                std::move(io_task_runner)))
 #endif
 {
+  InitializeLocalCapabilities();
 }
 
 NodeChannel::~NodeChannel() {
@@ -549,7 +579,10 @@
   switch (header->type) {
     case MessageType::ACCEPT_INVITEE: {
       AcceptInviteeData data;
-      if (GetMessagePayload(payload, payload_size, &data)) {
+      if (GetMessagePayloadMinimumSized<AcceptInviteeData, AcceptInviteeDataV0>(
+              payload, payload_size, &data)) {
+        // Attach any capabilities that the other side advertised.
+        SetRemoteCapabilities(data.capabilities);
         delegate_->OnAcceptInvitee(remote_node_name_, data.inviter_name,
                                    data.token);
         return;
@@ -559,7 +592,11 @@
 
     case MessageType::ACCEPT_INVITATION: {
       AcceptInvitationData data;
-      if (GetMessagePayload(payload, payload_size, &data)) {
+      if (GetMessagePayloadMinimumSized<AcceptInvitationData,
+                                        AcceptInvitationDataV0>(
+              payload, payload_size, &data)) {
+        // Attach any capabilities that the other side advertised.
+        SetRemoteCapabilities(data.capabilities);
         delegate_->OnAcceptInvitation(remote_node_name_, data.token,
                                       data.invitee_name);
         return;
@@ -606,7 +643,9 @@
 
     case MessageType::ACCEPT_BROKER_CLIENT: {
       AcceptBrokerClientData data;
-      if (GetMessagePayload(payload, payload_size, &data)) {
+      if (GetMessagePayloadMinimumSized<AcceptBrokerClientData,
+                                        AcceptBrokerClientDataV0>(
+              payload, payload_size, &data)) {
         PlatformHandle broker_channel;
         if (handles.size() > 1) {
           DLOG(ERROR) << "Dropping invalid AcceptBrokerClient message.";
@@ -615,8 +654,11 @@
         if (handles.size() == 1)
           broker_channel = std::move(handles[0]);
 
+        // Attach any capabilities that the other side advertised.
+        SetRemoteCapabilities(data.capabilities);
         delegate_->OnAcceptBrokerClient(remote_node_name_, data.broker_name,
-                                        std::move(broker_channel));
+                                        std::move(broker_channel),
+                                        data.broker_capabilities);
         return;
       }
       break;
@@ -659,7 +701,8 @@
 
     case MessageType::INTRODUCE: {
       IntroductionData data;
-      if (GetMessagePayload(payload, payload_size, &data)) {
+      if (GetMessagePayloadMinimumSized<IntroductionData, IntroductionDataV0>(
+              payload, payload_size, &data)) {
         if (handles.size() > 1) {
           DLOG(ERROR) << "Dropping invalid introduction message.";
           break;
@@ -668,8 +711,11 @@
         if (handles.size() == 1)
           channel_handle = std::move(handles[0]);
 
+        // The node channel for this introduction will be created later, so we
+        // can only pass up the capabilities we received from the broker for
+        // that remote.
         delegate_->OnIntroduce(remote_node_name_, data.name,
-                               std::move(channel_handle));
+                               std::move(channel_handle), data.capabilities);
         return;
       }
       break;
@@ -788,8 +834,8 @@
     process_error_callback_.Run("Channel received a malformed message");
   }
 
-  // |OnChannelError()| may cause |this| to be destroyed, but still need access
-  // to the name after that destruction. So make a copy of
+  // |OnChannelError()| may cause |this| to be destroyed, but still need
+  // access to the name after that destruction. So make a copy of
   // |remote_node_name_| so it can be used if |this| becomes destroyed.
   ports::NodeName node_name = remote_node_name_;
   delegate_->OnChannelError(node_name, this);
@@ -803,5 +849,50 @@
     channel_->Write(std::move(message));
 }
 
+void NodeChannel::OfferChannelUpgrade() {
+#if !defined(OS_NACL)
+  base::AutoLock lock(channel_lock_);
+  channel_->OfferChannelUpgrade();
+#endif
+}
+
+uint64_t NodeChannel::RemoteCapabilities() const {
+  return remote_capabilities_;
+}
+
+bool NodeChannel::HasRemoteCapability(const uint64_t capability) const {
+  return (remote_capabilities_ & capability) == capability;
+}
+
+void NodeChannel::SetRemoteCapabilities(const uint64_t capabilities) {
+  remote_capabilities_ |= capabilities;
+}
+
+uint64_t NodeChannel::LocalCapabilities() const {
+  return local_capabilities_;
+}
+
+bool NodeChannel::HasLocalCapability(const uint64_t capability) const {
+  return (local_capabilities_ & capability) == capability;
+}
+
+void NodeChannel::SetLocalCapabilities(const uint64_t capabilities) {
+  if (GetConfiguration().dont_advertise_capabilities) {
+    return;
+  }
+
+  local_capabilities_ |= capabilities;
+}
+
+void NodeChannel::InitializeLocalCapabilities() {
+  if (GetConfiguration().dont_advertise_capabilities) {
+    return;
+  }
+
+  if (core::Channel::SupportsChannelUpgrade()) {
+    SetLocalCapabilities(kNodeCapabilitySupportsUpgrade);
+  }
+}
+
 }  // namespace core
 }  // namespace mojo
diff --git a/mojo/core/node_channel.h b/mojo/core/node_channel.h
index 74306a5..b037054 100644
--- a/mojo/core/node_channel.h
+++ b/mojo/core/node_channel.h
@@ -26,6 +26,9 @@
 namespace mojo {
 namespace core {
 
+constexpr uint64_t kNodeCapabilityNone = 0;
+constexpr uint64_t kNodeCapabilitySupportsUpgrade = 1;
+
 // Wraps a Channel to send and receive Node control messages.
 class MOJO_SYSTEM_IMPL_EXPORT NodeChannel
     : public base::RefCountedDeleteOnSequence<NodeChannel>,
@@ -48,7 +51,8 @@
                                      PlatformHandle broker_channel) = 0;
     virtual void OnAcceptBrokerClient(const ports::NodeName& from_node,
                                       const ports::NodeName& broker_name,
-                                      PlatformHandle broker_channel) = 0;
+                                      PlatformHandle broker_channel,
+                                      const uint64_t broker_capabilities) = 0;
     virtual void OnEventMessage(const ports::NodeName& from_node,
                                 Channel::MessagePtr message) = 0;
     virtual void OnRequestPortMerge(const ports::NodeName& from_node,
@@ -58,7 +62,8 @@
                                        const ports::NodeName& name) = 0;
     virtual void OnIntroduce(const ports::NodeName& from_node,
                              const ports::NodeName& name,
-                             PlatformHandle channel_handle) = 0;
+                             PlatformHandle channel_handle,
+                             const uint64_t remote_capabilities) = 0;
     virtual void OnBroadcast(const ports::NodeName& from_node,
                              Channel::MessagePtr message) = 0;
 #if defined(OS_WIN)
@@ -130,15 +135,26 @@
   void BrokerClientAdded(const ports::NodeName& client_name,
                          PlatformHandle broker_channel);
   void AcceptBrokerClient(const ports::NodeName& broker_name,
-                          PlatformHandle broker_channel);
+                          PlatformHandle broker_channel,
+                          const uint64_t broker_capabilities);
   void RequestPortMerge(const ports::PortName& connector_port_name,
                         const std::string& token);
   void RequestIntroduction(const ports::NodeName& name);
-  void Introduce(const ports::NodeName& name, PlatformHandle channel_handle);
+  void Introduce(const ports::NodeName& name,
+                 PlatformHandle channel_handle,
+                 uint64_t capabilities);
   void SendChannelMessage(Channel::MessagePtr message);
   void Broadcast(Channel::MessagePtr message);
   void BindBrokerHost(PlatformHandle broker_host_handle);
 
+  uint64_t RemoteCapabilities() const;
+  bool HasRemoteCapability(const uint64_t capability) const;
+  void SetRemoteCapabilities(const uint64_t capability);
+
+  uint64_t LocalCapabilities() const;
+  bool HasLocalCapability(const uint64_t capability) const;
+  void SetLocalCapabilities(const uint64_t capability);
+
 #if defined(OS_WIN)
   // Relay the message to the specified node via this channel.  This is used to
   // pass windows handles between two processes that do not have permission to
@@ -154,6 +170,8 @@
                              Channel::MessagePtr message);
 #endif
 
+  void OfferChannelUpgrade();
+
  private:
   friend class base::RefCountedDeleteOnSequence<NodeChannel>;
   friend class base::DeleteHelper<NodeChannel>;
@@ -181,6 +199,10 @@
 
   void WriteChannelMessage(Channel::MessagePtr message);
 
+  // This method is responsible for setting up the default set of capabilities
+  // for this channel.
+  void InitializeLocalCapabilities();
+
   Delegate* const delegate_;
   const ProcessErrorCallback process_error_callback_;
 
@@ -190,6 +212,9 @@
   // Must only be accessed from the owning task runner's thread.
   ports::NodeName remote_node_name_;
 
+  uint64_t remote_capabilities_ = kNodeCapabilityNone;
+  uint64_t local_capabilities_ = kNodeCapabilityNone;
+
   base::Lock remote_process_handle_lock_;
   base::Process remote_process_handle_;
 
diff --git a/mojo/core/node_controller.cc b/mojo/core/node_controller.cc
index 86b397df..014dfd9a 100644
--- a/mojo/core/node_controller.cc
+++ b/mojo/core/node_controller.cc
@@ -867,7 +867,8 @@
 
     if (!inviter) {
       // Yes, we're the broker. We can initialize the client directly.
-      channel->AcceptBrokerClient(name_, PlatformHandle());
+      channel->AcceptBrokerClient(name_, PlatformHandle(),
+                                  channel->LocalCapabilities());
     } else {
       // We aren't the broker, so wait for a broker connection.
       base::AutoLock lock(broker_lock_);
@@ -935,12 +936,14 @@
 
   DVLOG(1) << "Client " << client_name << " accepted by broker " << from_node;
 
-  client->AcceptBrokerClient(from_node, std::move(broker_channel));
+  client->AcceptBrokerClient(from_node, std::move(broker_channel),
+                             GetBrokerChannel()->RemoteCapabilities());
 }
 
 void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node,
                                           const ports::NodeName& broker_name,
-                                          PlatformHandle broker_channel) {
+                                          PlatformHandle broker_channel,
+                                          const uint64_t broker_capabilities) {
   DCHECK(!GetConfiguration().is_broker_process);
 
   // This node should already have an inviter in bootstrap mode.
@@ -979,6 +982,7 @@
         ConnectionParams(PlatformChannelEndpoint(std::move(broker_channel))),
         Channel::HandlePolicy::kAcceptHandles, io_task_runner_,
         ProcessErrorCallback());
+    broker->SetRemoteCapabilities(broker_capabilities);
     AddPeer(broker_name, broker, true /* start_channel */);
   }
 
@@ -1014,6 +1018,10 @@
     }
   }
 #endif
+  if (inviter->HasLocalCapability(kNodeCapabilitySupportsUpgrade) &&
+      inviter->HasRemoteCapability(kNodeCapabilitySupportsUpgrade)) {
+    inviter->OfferChannelUpgrade();
+  }
 
   DVLOG(1) << "Client " << name_ << " accepted by broker " << broker_name;
 }
@@ -1092,19 +1100,22 @@
   scoped_refptr<NodeChannel> new_friend = GetPeerChannel(name);
   if (!new_friend) {
     // We don't know who they're talking about!
-    requestor->Introduce(name, PlatformHandle());
+    requestor->Introduce(name, PlatformHandle(), kNodeCapabilityNone);
   } else {
     PlatformChannel new_channel;
     requestor->Introduce(name,
-                         new_channel.TakeLocalEndpoint().TakePlatformHandle());
-    new_friend->Introduce(
-        from_node, new_channel.TakeRemoteEndpoint().TakePlatformHandle());
+                         new_channel.TakeLocalEndpoint().TakePlatformHandle(),
+                         new_friend->RemoteCapabilities());
+    new_friend->Introduce(from_node,
+                          new_channel.TakeRemoteEndpoint().TakePlatformHandle(),
+                          requestor->RemoteCapabilities());
   }
 }
 
 void NodeController::OnIntroduce(const ports::NodeName& from_node,
                                  const ports::NodeName& name,
-                                 PlatformHandle channel_handle) {
+                                 PlatformHandle channel_handle,
+                                 const uint64_t remote_capabilities) {
   DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
 
   if (!channel_handle.is_valid()) {
@@ -1131,6 +1142,13 @@
 
   DVLOG(1) << "Adding new peer " << name << " via broker introduction.";
   AddPeer(name, channel, true /* start_channel */);
+
+  channel->SetRemoteCapabilities(remote_capabilities);
+
+  if (channel->HasLocalCapability(kNodeCapabilitySupportsUpgrade) &&
+      channel->HasRemoteCapability(kNodeCapabilitySupportsUpgrade)) {
+    channel->OfferChannelUpgrade();
+  }
 }
 
 void NodeController::OnBroadcast(const ports::NodeName& from_node,
@@ -1339,11 +1357,13 @@
 
 NodeController::IsolatedConnection::~IsolatedConnection() = default;
 
-NodeController::IsolatedConnection& NodeController::IsolatedConnection::
-operator=(const IsolatedConnection& other) = default;
+NodeController::IsolatedConnection&
+NodeController::IsolatedConnection::operator=(const IsolatedConnection& other) =
+    default;
 
-NodeController::IsolatedConnection& NodeController::IsolatedConnection::
-operator=(IsolatedConnection&& other) = default;
+NodeController::IsolatedConnection&
+NodeController::IsolatedConnection::operator=(IsolatedConnection&& other) =
+    default;
 
 }  // namespace core
 }  // namespace mojo
diff --git a/mojo/core/node_controller.h b/mojo/core/node_controller.h
index 254efe4..affbeda 100644
--- a/mojo/core/node_controller.h
+++ b/mojo/core/node_controller.h
@@ -206,7 +206,8 @@
                            PlatformHandle broker_channel) override;
   void OnAcceptBrokerClient(const ports::NodeName& from_node,
                             const ports::NodeName& broker_name,
-                            PlatformHandle broker_channel) override;
+                            PlatformHandle broker_channel,
+                            const uint64_t broker_capabilities) override;
   void OnEventMessage(const ports::NodeName& from_node,
                       Channel::MessagePtr message) override;
   void OnRequestPortMerge(const ports::NodeName& from_node,
@@ -216,7 +217,8 @@
                              const ports::NodeName& name) override;
   void OnIntroduce(const ports::NodeName& from_node,
                    const ports::NodeName& name,
-                   PlatformHandle channel_handle) override;
+                   PlatformHandle channel_handle,
+                   const uint64_t remote_capailities) override;
   void OnBroadcast(const ports::NodeName& from_node,
                    Channel::MessagePtr message) override;
 #if defined(OS_WIN)
diff --git a/mojo/core/test/mock_node_channel_delegate.h b/mojo/core/test/mock_node_channel_delegate.h
index 06ca968..f58552f 100644
--- a/mojo/core/test/mock_node_channel_delegate.h
+++ b/mojo/core/test/mock_node_channel_delegate.h
@@ -54,7 +54,8 @@
               OnAcceptBrokerClient,
               (const NodeName& from_node,
                const NodeName& broker_name,
-               PlatformHandle broker_channel),
+               PlatformHandle broker_channel,
+               const uint64_t capabilities),
               (override));
   MOCK_METHOD(void,
               OnEventMessage,
@@ -74,7 +75,8 @@
               OnIntroduce,
               (const NodeName& from_node,
                const NodeName& name,
-               PlatformHandle channel_handle),
+               PlatformHandle channel_handle,
+               const uint64_t remote_capabilites),
               (override));
   MOCK_METHOD(void,
               OnBroadcast,
diff --git a/mojo/core/test/multiprocess_test_helper.cc b/mojo/core/test/multiprocess_test_helper.cc
index acf2d73..530a0fd5 100644
--- a/mojo/core/test/multiprocess_test_helper.cc
+++ b/mojo/core/test/multiprocess_test_helper.cc
@@ -51,6 +51,7 @@
 const char kRunAsBrokerClient[] = "run-as-broker-client";
 const char kAcceptInvitationAsync[] = "accept-invitation-async";
 const char kTestChildMessagePipeName[] = "test_pipe";
+const char kDisableAllCapabilities[] = "disable-all-capabilities";
 
 // For use (and only valid) in a test child process:
 base::LazyInstance<IsolatedConnection>::Leaky g_child_isolated_connection;
@@ -115,6 +116,7 @@
   base::LaunchOptions options;
   switch (launch_type) {
     case LaunchType::CHILD:
+    case LaunchType::CHILD_WITHOUT_CAPABILITIES:
     case LaunchType::PEER:
     case LaunchType::ASYNC:
       channel.PrepareToPassRemoteEndpoint(&options, &command_line);
@@ -161,6 +163,7 @@
   PlatformChannelServerEndpoint server_endpoint;
   switch (launch_type) {
     case LaunchType::CHILD:
+    case LaunchType::CHILD_WITHOUT_CAPABILITIES:
     case LaunchType::PEER:
     case LaunchType::ASYNC:
       local_channel_endpoint = channel.TakeLocalEndpoint();
@@ -180,8 +183,12 @@
   OutgoingInvitation child_invitation;
   ScopedMessagePipeHandle pipe;
   switch (launch_type) {
+    case LaunchType::CHILD_WITHOUT_CAPABILITIES:
     case LaunchType::ASYNC:
-      command_line.AppendSwitch(kAcceptInvitationAsync);
+      // It's one or the other
+      command_line.AppendSwitch(launch_type == LaunchType::ASYNC
+                                    ? kAcceptInvitationAsync
+                                    : kDisableAllCapabilities);
       FALLTHROUGH;
     case LaunchType::CHILD:
 #if !defined(OS_FUCHSIA)
@@ -211,12 +218,14 @@
   test_child_ =
       base::SpawnMultiProcessTestChild(test_child_main, command_line, options);
 
-  if (launch_type == LaunchType::CHILD || launch_type == LaunchType::PEER ||
-      launch_type == LaunchType::ASYNC) {
+  if (launch_type == LaunchType::CHILD ||
+      launch_type == LaunchType::CHILD_WITHOUT_CAPABILITIES ||
+      launch_type == LaunchType::PEER || launch_type == LaunchType::ASYNC) {
     channel.RemoteProcessLaunchAttempted();
   }
 
-  if (launch_type == LaunchType::CHILD) {
+  if (launch_type == LaunchType::CHILD ||
+      launch_type == LaunchType::CHILD_WITHOUT_CAPABILITIES) {
     DCHECK(local_channel_endpoint.is_valid());
     OutgoingInvitation::Send(std::move(child_invitation), test_child_.Handle(),
                              std::move(local_channel_endpoint),
diff --git a/mojo/core/test/multiprocess_test_helper.h b/mojo/core/test/multiprocess_test_helper.h
index f74ec31..b0cc7fe 100644
--- a/mojo/core/test/multiprocess_test_helper.h
+++ b/mojo/core/test/multiprocess_test_helper.h
@@ -44,6 +44,9 @@
     // system, using a named pipe.
     NAMED_PEER,
 #endif  //  !defined(OS_FUCHSIA)
+    // This is the same as child; however, it will never advertise any
+    // capabilities.
+    CHILD_WITHOUT_CAPABILITIES
   };
 
   MultiprocessTestHelper();
diff --git a/mojo/core/test/run_all_unittests.cc b/mojo/core/test/run_all_unittests.cc
index 7e91806..41b6f80 100644
--- a/mojo/core/test/run_all_unittests.cc
+++ b/mojo/core/test/run_all_unittests.cc
@@ -21,6 +21,10 @@
 #include "mojo/public/tests/test_support_private.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace {
+const char kDisableAllCapabilities[] = "disable-all-capabilities";
+}
+
 int main(int argc, char** argv) {
 #if !defined(OS_ANDROID)
   // Silence death test thread warnings on Linux. We can afford to run our death
@@ -48,6 +52,12 @@
           switches::kTestChildProcess)) {
     mojo_config.is_broker_process = true;
   }
+
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          kDisableAllCapabilities)) {
+    mojo_config.dont_advertise_capabilities = true;
+  }
+
   mojo::core::Init(mojo_config);
 
   mojo::test::TestSupport::Init(new mojo::core::test::TestSupportImpl());
diff --git a/mojo/public/interfaces/bindings/tests/sample_service.mojom b/mojo/public/interfaces/bindings/tests/sample_service.mojom
index 682cb3a..fe875a8 100644
--- a/mojo/public/interfaces/bindings/tests/sample_service.mojom
+++ b/mojo/public/interfaces/bindings/tests/sample_service.mojom
@@ -95,6 +95,12 @@
   int32 v3 = 3;
 };
 
+interface DefaultsSender {
+  SendBar(Bar bar);
+  SendFoo(Foo foo);
+  SendDefaultsTest(DefaultsTest defaults);
+};
+
 interface Service {
   enum BazOptions {
     REGULAR = 0,
diff --git a/mojo/public/js/bindings_lite.js b/mojo/public/js/bindings_lite.js
index abac51b..502eff3 100644
--- a/mojo/public/js/bindings_lite.js
+++ b/mojo/public/js/bindings_lite.js
@@ -164,8 +164,11 @@
   let size = structSpec.packedSize;
   let numInterfaceIds = 0;
   for (const field of structSpec.fields) {
-    const fieldValue = value[field.name];
+    let fieldValue = value[field.name];
     if (mojo.internal.isNullOrUndefined(fieldValue)) {
+      fieldValue = field.defaultValue;
+    }
+    if (fieldValue === null) {
       continue;
     }
 
@@ -519,7 +522,7 @@
    */
   encodeMap(mapSpec, offset, value) {
     let keys, values;
-    if (value instanceof Map) {
+    if (value.constructor.name == 'Map') {
       keys = Array.from(value.keys());
       values = Array.from(value.values());
     } else {
@@ -572,8 +575,7 @@
                             field.packedBitOffset, field.nullable);
       };
 
-      if (value && (value instanceof Object) &&
-          !mojo.internal.isNullOrUndefined(value[field.name])) {
+      if (value && !mojo.internal.isNullOrUndefined(value[field.name])) {
         encodeStructField(value[field.name]);
         continue;
       }
@@ -1312,7 +1314,9 @@
     encode: function(value, encoder, byteOffset, bitOffset, nullable) {
       encoder.encodeHandle(byteOffset, value);
     },
-    encodeNull: function(encoder, byteOffset) {},
+    encodeNull: function(encoder, byteOffset) {
+      encoder.encodeUint32(byteOffset, 0xffffffff);
+    },
     decode: function(decoder, byteOffset, bitOffset, nullable) {
       return decoder.decodeHandle(byteOffset);
     },
@@ -1401,10 +1405,12 @@
         return decoder.decodeMap(mapSpec, byteOffset);
       },
       computeDimensions: function(value, nullable) {
-        const keys = (value instanceof Map) ? Array.from(value.keys()) :
-                                              Object.keys(value);
-        const values = (value instanceof Map) ? Array.from(value.values()) :
-                                                keys.map(k => value[k]);
+        const keys =
+            (value.constructor.name == 'Map') ? Array.from(value.keys())
+                                              : Object.keys(value);
+        const values =
+            (value.constructor.name == 'Map') ? Array.from(value.values())
+                                              : keys.map(k => value[k]);
 
         const size = mojo.internal.kMapDataSize +
             mojo.internal.computeTotalArraySize({elementType: keyType}, keys) +
diff --git a/mojo/public/js/interface_support.js b/mojo/public/js/interface_support.js
index b836e10..6e7f2ec 100644
--- a/mojo/public/js/interface_support.js
+++ b/mojo/public/js/interface_support.js
@@ -339,14 +339,20 @@
 /**
  * Creates a new Endpoint wrapping a given pipe handle.
  *
- * @param {!MojoHandle} pipe
+ * @param {!MojoHandle|!mojo.internal.interfaceSupport.Endpoint} pipeOrEndpoint
  * @param {boolean=} setNamespaceBit
  * @return {!mojo.internal.interfaceSupport.Endpoint}
  */
 mojo.internal.interfaceSupport.createEndpoint = function(
-    pipe, setNamespaceBit = false) {
+    pipeOrEndpoint, setNamespaceBit = false) {
+  if (pipeOrEndpoint.constructor.name != 'MojoHandle') {
+    return /** @type {!mojo.internal.interfaceSupport.Endpoint} */(
+        pipeOrEndpoint);
+  }
   return new mojo.internal.interfaceSupport.Endpoint(
-      new mojo.internal.interfaceSupport.Router(pipe, setNamespaceBit), 0);
+      new mojo.internal.interfaceSupport.Router(
+          /** @type {!MojoHandle} */(pipeOrEndpoint), setNamespaceBit),
+      0);
 };
 
 /**
@@ -360,11 +366,7 @@
  * @export
  */
 mojo.internal.interfaceSupport.getEndpointForReceiver = function(handle) {
-  if (handle instanceof MojoHandle) {
-    return mojo.internal.interfaceSupport.createEndpoint(handle);
-  }
-
-  return handle;
+  return mojo.internal.interfaceSupport.createEndpoint(handle);
 };
 
 /**
@@ -633,10 +635,8 @@
    */
   bindHandle(handle) {
     console.assert(!this.endpoint_, 'already bound');
-    if (handle instanceof MojoHandle) {
-      handle = mojo.internal.interfaceSupport.createEndpoint(
-          handle, /* setNamespaceBit */ true);
-    }
+    handle = mojo.internal.interfaceSupport.createEndpoint(
+        handle, /* setNamespaceBit */ true);
     this.endpoint_ = handle;
     this.endpoint_.start(this);
     this.pendingResponses_ = new Map;
@@ -801,6 +801,14 @@
     return this.remote_.associateAndPassReceiver();
   }
 
+  /**
+   * @return {boolean}
+   * @export
+   */
+  isBound() {
+    return this.remote_.endpoint_ !== null;
+  }
+
   /** @export */
   close() {
     this.remote_.close();
@@ -982,9 +990,7 @@
    * @export
    */
   bindHandle(handle) {
-    if (handle instanceof MojoHandle) {
-      handle = mojo.internal.interfaceSupport.createEndpoint(handle);
-    }
+    handle = mojo.internal.interfaceSupport.createEndpoint(handle);
     this.endpoints_.add(handle);
     handle.start(this);
   }
@@ -1055,8 +1061,9 @@
             'Message expects a reply but its handler did not provide one.');
       }
 
-      if (!(result instanceof Promise))
+      if (typeof result != 'object' || result.constructor.name != 'Promise') {
         result = Promise.resolve(result);
+      }
 
       result
           .then(value => {
diff --git a/mojo/public/tools/bindings/generators/mojom_js_generator.py b/mojo/public/tools/bindings/generators/mojom_js_generator.py
index e8e7fbc..c317012 100644
--- a/mojo/public/tools/bindings/generators/mojom_js_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_js_generator.py
@@ -813,6 +813,11 @@
       if mojom.IsStructKind(field.kind):
         assert field.default == "default"
         return "null"
+      if ((field.kind == mojom.INT64 or field.kind == mojom.UINT64)
+          and not isinstance(
+              field.default,
+              (mojom.EnumValue, mojom.NamedValue, mojom.BuiltinValue))):
+        return "BigInt('{}')".format(int(field.default, 0))
       return self._ExpressionToTextLite(field.default, for_module=for_module)
     if field.kind == mojom.INT64 or field.kind == mojom.UINT64:
       return "BigInt(0)"
@@ -1027,7 +1032,7 @@
     assert isinstance(constant, mojom.Constant)
     text = self._ExpressionToTextLite(constant.value, for_module=for_module)
     if constant.kind == mojom.INT64 or constant.kind == mojom.UINT64:
-      return "BigInt('{}')".format(text)
+      return "BigInt('{}')".format(int(text, 0))
     return text
 
   def _GetConstantValueInJsModule(self, constant):
diff --git a/mojo/public/tools/mojom/mojom_parser.py b/mojo/public/tools/mojom/mojom_parser.py
index 75e319d..6c278a0 100755
--- a/mojo/public/tools/mojom/mojom_parser.py
+++ b/mojo/public/tools/mojom/mojom_parser.py
@@ -28,7 +28,8 @@
 
 
 # Disable this for easier debugging.
-ENABLE_MULTIPROCESSING = True
+# In Python 2, subprocesses just hang when exceptions are thrown :(.
+ENABLE_MULTIPROCESSING = sys.version_info[0] > 2
 
 
 def _ResolveRelativeImportPath(path, roots):
diff --git a/net/quic/bidirectional_stream_quic_impl_unittest.cc b/net/quic/bidirectional_stream_quic_impl_unittest.cc
index 8db3585..c519eb4 100644
--- a/net/quic/bidirectional_stream_quic_impl_unittest.cc
+++ b/net/quic/bidirectional_stream_quic_impl_unittest.cc
@@ -134,7 +134,7 @@
         is_ready_(false),
         trailers_expected_(false),
         trailers_received_(false) {
-    loop_.reset(new base::RunLoop);
+    loop_ = std::make_unique<base::RunLoop>();
   }
 
   ~TestDelegateBase() override {}
@@ -239,7 +239,7 @@
     int on_data_sent_count = on_data_sent_count_;
 
     loop_->Run();
-    loop_.reset(new base::RunLoop);
+    loop_ = std::make_unique<base::RunLoop>();
 
     EXPECT_EQ(method == kOnFailed, on_failed_called_);
     EXPECT_EQ(is_ready || (method == kOnStreamReady), is_ready_);
@@ -508,7 +508,7 @@
   void Initialize() {
     crypto_client_stream_factory_.set_handshake_mode(
         MockCryptoClientStream::ZERO_RTT);
-    mock_writes_.reset(new MockWrite[writes_.size()]);
+    mock_writes_ = std::make_unique<MockWrite[]>(writes_.size());
     for (size_t i = 0; i < writes_.size(); i++) {
       if (writes_[i].packet == nullptr) {
         mock_writes_[i] = MockWrite(writes_[i].mode, writes_[i].rv, i);
@@ -518,9 +518,9 @@
       }
     }
 
-    socket_data_.reset(new StaticSocketDataProvider(
+    socket_data_ = std::make_unique<StaticSocketDataProvider>(
         base::span<MockRead>(),
-        base::make_span(mock_writes_.get(), writes_.size())));
+        base::make_span(mock_writes_.get(), writes_.size()));
     socket_data_->set_printer(&printer_);
 
     std::unique_ptr<MockUDPClientSocket> socket(new MockUDPClientSocket(
@@ -529,7 +529,8 @@
     runner_ = new TestTaskRunner(&clock_);
     helper_.reset(
         new QuicChromiumConnectionHelper(&clock_, &random_generator_));
-    alarm_factory_.reset(new QuicChromiumAlarmFactory(runner_.get(), &clock_));
+    alarm_factory_ =
+        std::make_unique<QuicChromiumAlarmFactory>(runner_.get(), &clock_);
     connection_ = new quic::QuicConnection(
         connection_id_, quic::QuicSocketAddress(),
         ToQuicSocketAddress(peer_addr_), helper_.get(), alarm_factory_.get(),
@@ -544,7 +545,7 @@
     base::TimeTicks dns_end = base::TimeTicks::Now();
     base::TimeTicks dns_start = dns_end - base::TimeDelta::FromMilliseconds(1);
 
-    session_.reset(new QuicChromiumClientSession(
+    session_ = std::make_unique<QuicChromiumClientSession>(
         connection_, std::move(socket),
         /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_,
         &transport_security_state_, /*ssl_config_service=*/nullptr,
@@ -574,7 +575,7 @@
         std::make_unique<quic::QuicClientPushPromiseIndex>(), nullptr,
         base::DefaultTickClock::GetInstance(),
         base::ThreadTaskRunnerHandle::Get().get(),
-        /*socket_performance_watcher=*/nullptr, net_log().bound().net_log()));
+        /*socket_performance_watcher=*/nullptr, net_log().bound().net_log());
     session_->Initialize();
 
     // Blackhole QPACK decoder stream instead of constructing mock writes.
diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc
index 4316c1f..6736fff 100644
--- a/net/quic/quic_chromium_client_session_test.cc
+++ b/net/quic/quic_chromium_client_session_test.cc
@@ -187,7 +187,7 @@
         quic::QuicSocketAddress(), ToQuicSocketAddress(kIpEndPoint), &helper_,
         &alarm_factory_, writer, true, quic::Perspective::IS_CLIENT,
         quic::test::SupportedVersions(version_));
-    session_.reset(new TestingQuicChromiumClientSession(
+    session_ = std::make_unique<TestingQuicChromiumClientSession>(
         connection, std::move(socket),
         /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_,
         transport_security_state_.get(), /*ssl_config_service=*/nullptr,
@@ -212,7 +212,7 @@
         std::make_unique<quic::QuicClientPushPromiseIndex>(),
         &test_push_delegate_, base::DefaultTickClock::GetInstance(),
         base::ThreadTaskRunnerHandle::Get().get(),
-        /*socket_performance_watcher=*/nullptr, &net_log_));
+        /*socket_performance_watcher=*/nullptr, &net_log_);
     if (connectivity_monitor_) {
       connectivity_monitor_->SetInitialDefaultNetwork(default_network_);
       session_->AddConnectivityObserver(connectivity_monitor_.get());
@@ -2027,9 +2027,9 @@
   old_reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, 1));
   old_reads.push_back(MockRead(ASYNC, ERR_NETWORK_CHANGED, 2));
 
-  socket_data_.reset(new SequencedSocketData(
+  socket_data_ = std::make_unique<SequencedSocketData>(
       base::span<const MockRead>(old_reads.data(), old_reads.size()),
-      base::span<const MockWrite>(old_writes.data(), old_writes.size())));
+      base::span<const MockWrite>(old_writes.data(), old_writes.size()));
 
   std::unique_ptr<quic::QuicEncryptedPacket> server_ping(
       server_maker_.MakePingPacket(1, /*include_version=*/false));
diff --git a/net/quic/quic_chromium_client_stream_test.cc b/net/quic/quic_chromium_client_stream_test.cc
index fba1f5e..590d3881 100644
--- a/net/quic/quic_chromium_client_stream_test.cc
+++ b/net/quic/quic_chromium_client_stream_test.cc
@@ -147,7 +147,7 @@
                                       push_promise_index,
                                       quic::test::DefaultQuicConfig(),
                                       connection->supported_versions()) {
-  crypto_stream_.reset(new quic::test::MockQuicCryptoStream(this));
+  crypto_stream_ = std::make_unique<quic::test::MockQuicCryptoStream>(this);
   Initialize();
   ON_CALL(*this, WritevData(_, _, _, _, _, _))
       .WillByDefault(testing::Return(quic::QuicConsumedData(0, false)));
diff --git a/net/quic/quic_connectivity_probing_manager_test.cc b/net/quic/quic_connectivity_probing_manager_test.cc
index abce3d51..1cb135c 100644
--- a/net/quic/quic_connectivity_probing_manager_test.cc
+++ b/net/quic/quic_connectivity_probing_manager_test.cc
@@ -124,11 +124,11 @@
     // Create packet writer and reader for probing.
     writer_.reset(
         new QuicChromiumPacketWriter(socket_.get(), test_task_runner_.get()));
-    reader_.reset(new QuicChromiumPacketReader(
+    reader_ = std::make_unique<QuicChromiumPacketReader>(
         socket_.get(), &clock_, &session_, kQuicYieldAfterPacketsRead,
         quic::QuicTime::Delta::FromMilliseconds(
             kQuicYieldAfterDurationMilliseconds),
-        bound_test_net_log_.bound()));
+        bound_test_net_log_.bound());
   }
 
  protected:
diff --git a/net/quic/quic_end_to_end_unittest.cc b/net/quic/quic_end_to_end_unittest.cc
index 1c4532e..756d3cf81 100644
--- a/net/quic/quic_end_to_end_unittest.cc
+++ b/net/quic/quic_end_to_end_unittest.cc
@@ -69,7 +69,7 @@
   // HttpTransactionFactory methods
   int CreateTransaction(RequestPriority priority,
                         std::unique_ptr<HttpTransaction>* trans) override {
-    trans->reset(new HttpNetworkTransaction(priority, session_.get()));
+    *trans = std::make_unique<HttpNetworkTransaction>(priority, session_.get());
     return OK;
   }
 
@@ -155,10 +155,10 @@
         quic::test::kInitialStreamFlowControlWindowForTest);
     server_config_.SetInitialSessionFlowControlWindowToSend(
         quic::test::kInitialSessionFlowControlWindowForTest);
-    server_.reset(new QuicSimpleServer(
+    server_ = std::make_unique<QuicSimpleServer>(
         quic::test::crypto_test_utils::ProofSourceForTesting(), server_config_,
         server_config_options_, quic::AllSupportedVersions(),
-        &memory_cache_backend_));
+        &memory_cache_backend_);
     server_->Listen(server_address_);
     server_address_ = server_->server_address();
     server_->StartReading();
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 280b1e65..1acb4a5 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -329,7 +329,7 @@
 
   // Configures the test fixture to use the list of expected writes.
   void Initialize() {
-    mock_writes_.reset(new MockWrite[writes_.size()]);
+    mock_writes_ = std::make_unique<MockWrite[]>(writes_.size());
     for (size_t i = 0; i < writes_.size(); i++) {
       if (writes_[i].packet == nullptr) {
         mock_writes_[i] = MockWrite(writes_[i].mode, writes_[i].rv, i);
@@ -339,9 +339,9 @@
       }
     }
 
-    socket_data_.reset(new StaticSocketDataProvider(
+    socket_data_ = std::make_unique<StaticSocketDataProvider>(
         base::span<MockRead>(),
-        base::make_span(mock_writes_.get(), writes_.size())));
+        base::make_span(mock_writes_.get(), writes_.size()));
     socket_data_->set_printer(&printer_);
 
     std::unique_ptr<MockUDPClientSocket> socket(new MockUDPClientSocket(
@@ -368,9 +368,10 @@
     EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(AnyNumber());
     EXPECT_CALL(*send_algorithm_, GetCongestionControlType())
         .Times(AnyNumber());
-    helper_.reset(
-        new QuicChromiumConnectionHelper(&clock_, &random_generator_));
-    alarm_factory_.reset(new QuicChromiumAlarmFactory(runner_.get(), &clock_));
+    helper_ = std::make_unique<QuicChromiumConnectionHelper>(
+        &clock_, &random_generator_);
+    alarm_factory_ =
+        std::make_unique<QuicChromiumAlarmFactory>(runner_.get(), &clock_);
 
     connection_ = new TestQuicConnection(
         quic::test::SupportedVersions(version_), connection_id_, peer_addr_,
@@ -391,7 +392,7 @@
 
     base::TimeTicks dns_end = base::TimeTicks::Now();
     base::TimeTicks dns_start = dns_end - base::TimeDelta::FromMilliseconds(1);
-    session_.reset(new QuicChromiumClientSession(
+    session_ = std::make_unique<QuicChromiumClientSession>(
         connection_, std::move(socket),
         /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_,
         &transport_security_state_, /*ssl_config_service=*/nullptr,
@@ -421,7 +422,7 @@
         std::make_unique<quic::QuicClientPushPromiseIndex>(), nullptr,
         base::DefaultTickClock::GetInstance(),
         base::ThreadTaskRunnerHandle::Get().get(),
-        /*socket_performance_watcher=*/nullptr, net_log_.bound().net_log()));
+        /*socket_performance_watcher=*/nullptr, net_log_.bound().net_log());
     session_->Initialize();
 
     // Blackhole QPACK decoder stream instead of constructing mock writes.
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 228c916..ee332bc 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -649,7 +649,8 @@
     session_context_.http_server_properties = http_server_properties_.get();
     session_context_.net_log = net_log_.bound().net_log();
 
-    session_.reset(new HttpNetworkSession(session_params_, session_context_));
+    session_ =
+        std::make_unique<HttpNetworkSession>(session_params_, session_context_);
     session_->quic_stream_factory()
         ->set_is_quic_known_to_work_on_current_network(true);
     SpdySessionPoolPeer spdy_pool_peer(session_->spdy_session_pool());
@@ -816,7 +817,7 @@
 
   void AddHangingNonAlternateProtocolSocketData() {
     std::unique_ptr<StaticSocketDataProvider> hanging_data;
-    hanging_data.reset(new StaticSocketDataProvider());
+    hanging_data = std::make_unique<StaticSocketDataProvider>();
     MockConnect hanging_connect(SYNCHRONOUS, ERR_IO_PENDING);
     hanging_data->set_connect_data(hanging_connect);
     hanging_data_.push_back(std::move(hanging_data));
@@ -827,7 +828,8 @@
     context_.params()->migrate_sessions_on_network_change_v2 = true;
     context_.params()->migrate_sessions_early_v2 = true;
     context_.params()->retry_on_alternate_network_before_handshake = true;
-    scoped_mock_change_notifier_.reset(new ScopedMockNetworkChangeNotifier());
+    scoped_mock_change_notifier_ =
+        std::make_unique<ScopedMockNetworkChangeNotifier>();
     MockNetworkChangeNotifier* mock_ncn =
         scoped_mock_change_notifier_->mock_network_change_notifier();
     mock_ncn->ForceNetworkHandlesSupported();
@@ -2227,11 +2229,11 @@
   MockQuicData mock_quic_data(picked_version);
 
   // Reset QuicTestPacket makers as the version picked may not be |version_|.
-  client_maker_.reset(new QuicTestPacketMaker(
+  client_maker_ = std::make_unique<QuicTestPacketMaker>(
       picked_version,
       quic::QuicUtils::CreateRandomConnectionId(context_.random_generator()),
       context_.clock(), kDefaultServerHostName, quic::Perspective::IS_CLIENT,
-      client_headers_include_h2_stream_dependency_));
+      client_headers_include_h2_stream_dependency_);
   QuicTestPacketMaker server_maker(
       picked_version,
       quic::QuicUtils::CreateRandomConnectionId(context_.random_generator()),
@@ -7103,7 +7105,8 @@
     session_context.http_auth_handler_factory = auth_handler_factory_.get();
     session_context.http_server_properties = &http_server_properties_;
 
-    session_.reset(new HttpNetworkSession(session_params, session_context));
+    session_ =
+        std::make_unique<HttpNetworkSession>(session_params, session_context);
     session_->quic_stream_factory()
         ->set_is_quic_known_to_work_on_current_network(false);
   }
diff --git a/net/quic/quic_proxy_client_socket_unittest.cc b/net/quic/quic_proxy_client_socket_unittest.cc
index 0102c631..08874b2 100644
--- a/net/quic/quic_proxy_client_socket_unittest.cc
+++ b/net/quic/quic_proxy_client_socket_unittest.cc
@@ -223,7 +223,8 @@
         .Times(AnyNumber());
     helper_.reset(
         new QuicChromiumConnectionHelper(&clock_, &random_generator_));
-    alarm_factory_.reset(new QuicChromiumAlarmFactory(runner_.get(), &clock_));
+    alarm_factory_ =
+        std::make_unique<QuicChromiumAlarmFactory>(runner_.get(), &clock_);
 
     QuicChromiumPacketWriter* writer = new QuicChromiumPacketWriter(
         socket.get(), base::ThreadTaskRunnerHandle::Get().get());
@@ -248,7 +249,7 @@
     base::TimeTicks dns_end = base::TimeTicks::Now();
     base::TimeTicks dns_start = dns_end - base::TimeDelta::FromMilliseconds(1);
 
-    session_.reset(new QuicChromiumClientSession(
+    session_ = std::make_unique<QuicChromiumClientSession>(
         connection, std::move(socket),
         /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_,
         &transport_security_state_, /*ssl_config_service=*/nullptr,
@@ -278,7 +279,7 @@
         std::make_unique<quic::QuicClientPushPromiseIndex>(), nullptr,
         base::DefaultTickClock::GetInstance(),
         base::ThreadTaskRunnerHandle::Get().get(),
-        /*socket_performance_watcher=*/nullptr, net_log_.bound().net_log()));
+        /*socket_performance_watcher=*/nullptr, net_log_.bound().net_log());
 
     writer->set_delegate(session_.get());
 
@@ -304,7 +305,7 @@
         session_handle_->ReleaseStream();
     EXPECT_TRUE(stream_handle->IsOpen());
 
-    sock_.reset(new QuicProxyClientSocket(
+    sock_ = std::make_unique<QuicProxyClientSocket>(
         std::move(stream_handle), std::move(session_handle_),
         ProxyServer(ProxyServer::SCHEME_HTTPS, proxy_host_port_), user_agent_,
         endpoint_host_port_, net_log_.bound(),
@@ -313,7 +314,7 @@
                                NetworkIsolationKey(), &http_auth_cache_,
                                http_auth_handler_factory_.get(),
                                host_resolver_.get()),
-        proxy_delegate_.get()));
+        proxy_delegate_.get());
 
     session_->StartReading();
   }
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 643f43b..c682f4f 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -272,8 +272,8 @@
 
   void InitializeConnectionMigrationV2Test(
       NetworkChangeNotifier::NetworkList connected_networks) {
-    scoped_mock_network_change_notifier_.reset(
-        new ScopedMockNetworkChangeNotifier());
+    scoped_mock_network_change_notifier_ =
+        std::make_unique<ScopedMockNetworkChangeNotifier>();
     MockNetworkChangeNotifier* mock_ncn =
         scoped_mock_network_change_notifier_->mock_network_change_notifier();
     mock_ncn->ForceNetworkHandlesSupported();
@@ -281,7 +281,7 @@
     quic_params_->migrate_sessions_on_network_change_v2 = true;
     quic_params_->migrate_sessions_early_v2 = true;
     quic_params_->allow_port_migration = false;
-    socket_factory_.reset(new TestMigrationSocketFactory);
+    socket_factory_ = std::make_unique<TestMigrationSocketFactory>();
     FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator = true;
     FLAGS_quic_reloadable_flag_quic_send_path_response = true;
     FLAGS_quic_reloadable_flag_quic_start_peer_migration_earlier = true;
@@ -4701,7 +4701,7 @@
   FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator = true;
   FLAGS_quic_reloadable_flag_quic_send_path_response = true;
   FLAGS_quic_reloadable_flag_quic_start_peer_migration_earlier = true;
-  socket_factory_.reset(new TestMigrationSocketFactory);
+  socket_factory_ = std::make_unique<TestMigrationSocketFactory>();
   Initialize();
 
   TestSimplePortMigrationOnPathDegrading();
@@ -4725,7 +4725,7 @@
     return;
   }
   quic_params_->allow_port_migration = true;
-  socket_factory_.reset(new TestMigrationSocketFactory);
+  socket_factory_ = std::make_unique<TestMigrationSocketFactory>();
   Initialize();
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
   crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
@@ -4864,7 +4864,7 @@
   FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator = true;
   FLAGS_quic_reloadable_flag_quic_send_path_response = true;
   FLAGS_quic_reloadable_flag_quic_start_peer_migration_earlier = true;
-  socket_factory_.reset(new TestMigrationSocketFactory);
+  socket_factory_ = std::make_unique<TestMigrationSocketFactory>();
   Initialize();
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
   crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
@@ -4982,8 +4982,8 @@
     // Path validator is only supported in IETF QUIC.
     return;
   }
-  scoped_mock_network_change_notifier_.reset(
-      new ScopedMockNetworkChangeNotifier());
+  scoped_mock_network_change_notifier_ =
+      std::make_unique<ScopedMockNetworkChangeNotifier>();
   MockNetworkChangeNotifier* mock_ncn =
       scoped_mock_network_change_notifier_->mock_network_change_notifier();
   mock_ncn->ForceNetworkHandlesSupported();
@@ -4992,7 +4992,7 @@
   FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator = true;
   FLAGS_quic_reloadable_flag_quic_send_path_response = true;
   FLAGS_quic_reloadable_flag_quic_start_peer_migration_earlier = true;
-  socket_factory_.reset(new TestMigrationSocketFactory);
+  socket_factory_ = std::make_unique<TestMigrationSocketFactory>();
   Initialize();
 
   scoped_mock_network_change_notifier_->mock_network_change_notifier()
@@ -5004,14 +5004,14 @@
 // Verifies that port migration can be attempted on the default network and
 // succeed when path degrading is detected. NetworkHandle is supported.
 TEST_P(QuicStreamFactoryTest, MigratePortOnPathDegrading_WithNetworkHandle) {
-  scoped_mock_network_change_notifier_.reset(
-      new ScopedMockNetworkChangeNotifier());
+  scoped_mock_network_change_notifier_ =
+      std::make_unique<ScopedMockNetworkChangeNotifier>();
   MockNetworkChangeNotifier* mock_ncn =
       scoped_mock_network_change_notifier_->mock_network_change_notifier();
   mock_ncn->ForceNetworkHandlesSupported();
   mock_ncn->SetConnectedNetworksList({kDefaultNetworkForTests});
   quic_params_->allow_port_migration = true;
-  socket_factory_.reset(new TestMigrationSocketFactory);
+  socket_factory_ = std::make_unique<TestMigrationSocketFactory>();
   Initialize();
 
   scoped_mock_network_change_notifier_->mock_network_change_notifier()
@@ -5025,8 +5025,8 @@
 // NetworkHandle is supported. Migration on network change is also enabled.
 // No additional network migration is triggered post port migration.
 TEST_P(QuicStreamFactoryTest, MigratePortOnPathDegrading_WithMigration) {
-  scoped_mock_network_change_notifier_.reset(
-      new ScopedMockNetworkChangeNotifier());
+  scoped_mock_network_change_notifier_ =
+      std::make_unique<ScopedMockNetworkChangeNotifier>();
   MockNetworkChangeNotifier* mock_ncn =
       scoped_mock_network_change_notifier_->mock_network_change_notifier();
   mock_ncn->ForceNetworkHandlesSupported();
@@ -5034,7 +5034,7 @@
   // Enable migration on network change.
   quic_params_->migrate_sessions_on_network_change_v2 = true;
   quic_params_->allow_port_migration = true;
-  socket_factory_.reset(new TestMigrationSocketFactory);
+  socket_factory_ = std::make_unique<TestMigrationSocketFactory>();
   Initialize();
 
   scoped_mock_network_change_notifier_->mock_network_change_notifier()
@@ -5049,8 +5049,8 @@
     // Path validator is only supported in IETF QUIC.
     return;
   }
-  scoped_mock_network_change_notifier_.reset(
-      new ScopedMockNetworkChangeNotifier());
+  scoped_mock_network_change_notifier_ =
+      std::make_unique<ScopedMockNetworkChangeNotifier>();
   MockNetworkChangeNotifier* mock_ncn =
       scoped_mock_network_change_notifier_->mock_network_change_notifier();
   mock_ncn->ForceNetworkHandlesSupported();
@@ -5061,7 +5061,7 @@
   FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator = true;
   FLAGS_quic_reloadable_flag_quic_send_path_response = true;
   FLAGS_quic_reloadable_flag_quic_start_peer_migration_earlier = true;
-  socket_factory_.reset(new TestMigrationSocketFactory);
+  socket_factory_ = std::make_unique<TestMigrationSocketFactory>();
   Initialize();
 
   scoped_mock_network_change_notifier_->mock_network_change_notifier()
@@ -5255,7 +5255,7 @@
 // Regression test for https://crbug.com/1014092.
 TEST_P(QuicStreamFactoryTest, MultiplePortMigrationsExceedsMaxLimit) {
   quic_params_->allow_port_migration = true;
-  socket_factory_.reset(new TestMigrationSocketFactory);
+  socket_factory_ = std::make_unique<TestMigrationSocketFactory>();
   Initialize();
 
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
@@ -14206,9 +14206,9 @@
 // Test that QuicStreamRequests with similar and different tags results in
 // reused and unique QUIC streams using appropriately tagged sockets.
 TEST_P(QuicStreamFactoryTest, Tag) {
-  MockTaggingClientSocketFactory* socket_factory =
-      new MockTaggingClientSocketFactory();
-  socket_factory_.reset(socket_factory);
+  socket_factory_ = std::make_unique<MockTaggingClientSocketFactory>();
+  auto* socket_factory =
+      static_cast<MockTaggingClientSocketFactory*>(socket_factory_.get());
   Initialize();
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
   crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index f40e3c28..956a8470 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -1141,78 +1141,6 @@
   }
 }
 
-void OutOfProcessInstance::DoPaint(const std::vector<gfx::Rect>& paint_rects,
-                                   std::vector<PaintReadyRect>* ready,
-                                   std::vector<gfx::Rect>* pending) {
-  if (image_data().drawsNothing()) {
-    DCHECK(plugin_size().IsEmpty());
-    return;
-  }
-  if (first_paint()) {
-    set_first_paint(false);
-    mutable_image_data().eraseColor(GetBackgroundColor());
-    gfx::Rect rect(gfx::SkISizeToSize(image_data().dimensions()));
-    ready->push_back(
-        PaintReadyRect(rect, GetPluginImageData(), /*flush_now=*/true));
-  }
-
-  if (!received_viewport_message() || !needs_reraster())
-    return;
-
-  engine()->PrePaint();
-
-  for (const auto& paint_rect : paint_rects) {
-    // Intersect with plugin area since there could be pending invalidates from
-    // when the plugin area was larger.
-    gfx::Rect rect = gfx::IntersectRects(paint_rect, gfx::Rect(plugin_size()));
-    if (rect.IsEmpty())
-      continue;
-
-    gfx::Rect pdf_rect = gfx::IntersectRects(rect, available_area());
-    if (!pdf_rect.IsEmpty()) {
-      pdf_rect.Offset(available_area().x() * -1, 0);
-
-      std::vector<gfx::Rect> pdf_ready;
-      std::vector<gfx::Rect> pdf_pending;
-      engine()->Paint(pdf_rect, mutable_image_data(), pdf_ready, pdf_pending);
-      for (auto& ready_rect : pdf_ready) {
-        ready_rect.Offset(available_area().OffsetFromOrigin());
-        ready->push_back(PaintReadyRect(ready_rect, GetPluginImageData()));
-      }
-      for (auto& pending_rect : pdf_pending) {
-        pending_rect.Offset(available_area().OffsetFromOrigin());
-        pending->push_back(pending_rect);
-      }
-    }
-
-    // Ensure the region above the first page (if any) is filled;
-    int32_t first_page_ypos = engine()->GetNumberOfPages() == 0
-                                  ? 0
-                                  : engine()->GetPageScreenRect(0).y();
-    if (rect.y() < first_page_ypos) {
-      gfx::Rect region = gfx::IntersectRects(
-          rect, gfx::Rect(gfx::Size(plugin_size().width(), first_page_ypos)));
-      ready->push_back(PaintReadyRect(region, GetPluginImageData()));
-      mutable_image_data().erase(GetBackgroundColor(),
-                                 gfx::RectToSkIRect(region));
-    }
-
-    for (const auto& background_part : background_parts()) {
-      gfx::Rect intersection =
-          gfx::IntersectRects(background_part.location, rect);
-      if (!intersection.IsEmpty()) {
-        mutable_image_data().erase(background_part.color,
-                                   gfx::RectToSkIRect(intersection));
-        ready->push_back(PaintReadyRect(intersection, GetPluginImageData()));
-      }
-    }
-  }
-
-  engine()->PostPaint();
-
-  InvalidateAfterPaintDone();
-}
-
 pp::VarArray OutOfProcessInstance::GetDocumentAttachments() {
   const std::vector<DocumentAttachmentInfo>& list =
       engine()->GetDocumentAttachmentInfoList();
diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h
index 1969d01..cdc8430 100644
--- a/pdf/out_of_process_instance.h
+++ b/pdf/out_of_process_instance.h
@@ -45,7 +45,6 @@
 namespace chrome_pdf {
 
 class Graphics;
-class PaintReadyRect;
 class PDFiumEngine;
 class Thumbnail;
 class UrlLoader;
@@ -185,9 +184,6 @@
   void DidOpen(std::unique_ptr<UrlLoader> loader, int32_t result) override;
   void DidOpenPreview(std::unique_ptr<UrlLoader> loader,
                       int32_t result) override;
-  void DoPaint(const std::vector<gfx::Rect>& paint_rects,
-               std::vector<PaintReadyRect>* ready,
-               std::vector<gfx::Rect>* pending) override;
   void OnGeometryChanged(double old_zoom, float old_device_scale) override;
   Image GetPluginImageData() const override;
 
diff --git a/pdf/pdf_view_plugin_base.cc b/pdf/pdf_view_plugin_base.cc
index 505d3b6..e5b90f3 100644
--- a/pdf/pdf_view_plugin_base.cc
+++ b/pdf/pdf_view_plugin_base.cc
@@ -21,12 +21,15 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/optional.h"
 #include "base/values.h"
+#include "pdf/paint_ready_rect.h"
 #include "pdf/pdf_features.h"
 #include "pdf/pdfium/pdfium_engine.h"
 #include "pdf/ppapi_migration/image.h"
 #include "pdf/ppapi_migration/url_loader.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/skia_util.h"
 
 namespace chrome_pdf {
 
@@ -236,6 +239,87 @@
   engine()->SetTwoUpView(message.FindBoolKey("enableTwoUpView").value());
 }
 
+void PdfViewPluginBase::DoPaint(const std::vector<gfx::Rect>& paint_rects,
+                                std::vector<PaintReadyRect>* ready,
+                                std::vector<gfx::Rect>* pending) {
+  if (image_data_.drawsNothing()) {
+    DCHECK(plugin_size_.IsEmpty());
+    return;
+  }
+
+  PrepareForFirstPaint(ready);
+
+  if (!received_viewport_message_ || !needs_reraster_)
+    return;
+
+  engine()->PrePaint();
+
+  for (const gfx::Rect& paint_rect : paint_rects) {
+    // Intersect with plugin area since there could be pending invalidates from
+    // when the plugin area was larger.
+    gfx::Rect rect = gfx::IntersectRects(paint_rect, gfx::Rect(plugin_size_));
+    if (rect.IsEmpty())
+      continue;
+
+    // Paint the rendering of the PDF document.
+    gfx::Rect pdf_rect = gfx::IntersectRects(rect, available_area_);
+    if (!pdf_rect.IsEmpty()) {
+      pdf_rect.Offset(-available_area_.x(), 0);
+
+      std::vector<gfx::Rect> pdf_ready;
+      std::vector<gfx::Rect> pdf_pending;
+      engine()->Paint(pdf_rect, image_data_, pdf_ready, pdf_pending);
+      for (gfx::Rect& ready_rect : pdf_ready) {
+        ready_rect.Offset(available_area_.OffsetFromOrigin());
+        ready->push_back(PaintReadyRect(ready_rect, GetPluginImageData()));
+      }
+      for (gfx::Rect& pending_rect : pdf_pending) {
+        pending_rect.Offset(available_area_.OffsetFromOrigin());
+        pending->push_back(pending_rect);
+      }
+    }
+
+    // Ensure the region above the first page (if any) is filled;
+    const int32_t first_page_ypos = 0 == engine()->GetNumberOfPages()
+                                        ? 0
+                                        : engine()->GetPageScreenRect(0).y();
+    if (rect.y() < first_page_ypos) {
+      gfx::Rect region = gfx::IntersectRects(
+          rect, gfx::Rect(gfx::Size(plugin_size_.width(), first_page_ypos)));
+      ready->push_back(PaintReadyRect(region, GetPluginImageData()));
+      image_data_.erase(background_color_, gfx::RectToSkIRect(region));
+    }
+
+    // Ensure the background parts are filled.
+    for (const BackgroundPart& background_part : background_parts_) {
+      gfx::Rect intersection =
+          gfx::IntersectRects(background_part.location, rect);
+      if (!intersection.IsEmpty()) {
+        image_data_.erase(background_part.color,
+                          gfx::RectToSkIRect(intersection));
+        ready->push_back(PaintReadyRect(intersection, GetPluginImageData()));
+      }
+    }
+  }
+
+  engine()->PostPaint();
+
+  InvalidateAfterPaintDone();
+}
+
+void PdfViewPluginBase::PrepareForFirstPaint(
+    std::vector<PaintReadyRect>* ready) {
+  if (!first_paint_)
+    return;
+
+  // Fill the image data buffer with the background color.
+  first_paint_ = false;
+  image_data_.eraseColor(background_color_);
+  gfx::Rect rect(gfx::SkISizeToSize(image_data_.dimensions()));
+  ready->push_back(
+      PaintReadyRect(rect, GetPluginImageData(), /*flush_now=*/true));
+}
+
 void PdfViewPluginBase::ClearDeferredInvalidates(
     int32_t /*unused_but_required*/) {
   DCHECK(!in_paint_);
diff --git a/pdf/pdf_view_plugin_base.h b/pdf/pdf_view_plugin_base.h
index 960b183..ffaf6d6 100644
--- a/pdf/pdf_view_plugin_base.h
+++ b/pdf/pdf_view_plugin_base.h
@@ -92,12 +92,6 @@
   // Handles `postMessage()` calls from the embedder.
   void HandleMessage(const base::Value& message);
 
-  // Paints the given invalid area of the plugin to the given graphics device.
-  // PaintManager::Client::OnPaint() should be its only caller.
-  virtual void DoPaint(const std::vector<gfx::Rect>& paint_rects,
-                       std::vector<PaintReadyRect>* ready,
-                       std::vector<gfx::Rect>* pending) = 0;
-
   // Schedules invalidation tasks after painting finishes.
   void InvalidateAfterPaintDone();
 
@@ -121,10 +115,6 @@
   int GetDocumentPixelWidth() const;
   int GetDocumentPixelHeight() const;
 
-  const std::vector<BackgroundPart>& background_parts() const {
-    return background_parts_;
-  }
-
   const SkBitmap& image_data() const { return image_data_; }
   SkBitmap& mutable_image_data() { return image_data_; }
 
@@ -162,15 +152,12 @@
   float device_scale() const { return device_scale_; }
   void set_device_scale(float device_scale) { device_scale_ = device_scale; }
 
-  bool first_paint() const { return first_paint_; }
   void set_first_paint(bool first_paint) { first_paint_ = first_paint; }
 
-  bool needs_reraster() const { return needs_reraster_; }
   void set_needs_reraster(bool needs_reraster) {
     needs_reraster_ = needs_reraster;
   }
 
-  bool received_viewport_message() const { return received_viewport_message_; }
   void set_received_viewport_message(bool received) {
     received_viewport_message_ = received;
   }
@@ -185,6 +172,16 @@
   void HandleSetReadOnlyMessage(const base::Value& message);
   void HandleSetTwoUpViewMessage(const base::Value& message);
 
+  // Paints the given invalid area of the plugin to the given graphics device.
+  // PaintManager::Client::OnPaint() should be its only caller.
+  void DoPaint(const std::vector<gfx::Rect>& paint_rects,
+               std::vector<PaintReadyRect>* ready,
+               std::vector<gfx::Rect>* pending);
+
+  // The preparation when painting on the image data buffer for the first
+  // time.
+  void PrepareForFirstPaint(std::vector<PaintReadyRect>* ready);
+
   // Callback to clear deferred invalidates after painting finishes.
   void ClearDeferredInvalidates(int32_t /*unused_but_required*/);
 
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc
index d3af46d6..ca00729 100644
--- a/pdf/pdf_view_web_plugin.cc
+++ b/pdf/pdf_view_web_plugin.cc
@@ -407,14 +407,6 @@
   NOTIMPLEMENTED();
 }
 
-// TODO(https://crbug.com/1099020): To be implemented as a Pepper-free version
-// of `OutOfProcessInstance::DoPaint()`
-void PdfViewWebPlugin::DoPaint(const std::vector<gfx::Rect>& paint_rects,
-                               std::vector<PaintReadyRect>* ready,
-                               std::vector<gfx::Rect>* pending) {
-  NOTIMPLEMENTED_LOG_ONCE();
-}
-
 void PdfViewWebPlugin::OnGeometryChanged(double old_zoom,
                                          float old_device_scale) {
   RecalculateAreas(old_zoom, old_device_scale);
diff --git a/pdf/pdf_view_web_plugin.h b/pdf/pdf_view_web_plugin.h
index 361b64b..a8bdef5 100644
--- a/pdf/pdf_view_web_plugin.h
+++ b/pdf/pdf_view_web_plugin.h
@@ -137,9 +137,6 @@
   void DidOpen(std::unique_ptr<UrlLoader> loader, int32_t result) override;
   void DidOpenPreview(std::unique_ptr<UrlLoader> loader,
                       int32_t result) override;
-  void DoPaint(const std::vector<gfx::Rect>& paint_rects,
-               std::vector<PaintReadyRect>* ready,
-               std::vector<gfx::Rect>* pending) override;
   void OnGeometryChanged(double old_zoom, float old_device_scale) override;
 
  private:
diff --git a/remoting/host/installer/linux/BUILD.gn b/remoting/host/installer/linux/BUILD.gn
index 4db0701..397b4d4 100644
--- a/remoting/host/installer/linux/BUILD.gn
+++ b/remoting/host/installer/linux/BUILD.gn
@@ -55,6 +55,7 @@
     "debian/postinst",
     "debian/preinst",
     "debian/rules",
+    "debian/triggers",
   ]
   outputs = packaging_outputs
   sources = [ "build-deb.sh" ]
diff --git a/remoting/host/installer/linux/debian/postinst b/remoting/host/installer/linux/debian/postinst
index 5b5aac3..1da5c3c 100755
--- a/remoting/host/installer/linux/debian/postinst
+++ b/remoting/host/installer/linux/debian/postinst
@@ -23,6 +23,15 @@
 HOST_PATH="$INSTALL_DIR/chrome-remote-desktop-host"
 CRD_GROUP="chrome-remote-desktop"
 
+restart_hosts() {
+  # Kill host processes. SIGKILL is used because the wrapper script will
+  # restart the host immediately (so any cleanup that might otherwise happen
+  # is not useful), and this ensures that hosts restart even if they are
+  # deadlocked.
+  echo "Shutting down Chrome Remote Desktop hosts (they will restart automatically)..."
+  pkill -KILL -f "^$HOST_PATH" || true
+}
+
 case "$1" in
   "configure")
     # Create CRD group if it doesn't already exist
@@ -37,12 +46,9 @@
       chown root:"$CRD_GROUP" "$USER_SESSION_PATH"
       chmod u=srwx,g=rx,o=r "$USER_SESSION_PATH"
     fi
-    # Kill host processes. SIGKILL is used because the wrapper script will
-    # restart the host immediately (so any cleanup that might otherwise happen
-    # is not useful), and this ensures that hosts restart even if they are
-    # deadlocked.
-    echo "Shutting down Chrome Remote Desktop hosts (they will restart automatically)..."
-    pkill -KILL -f "^$HOST_PATH" || true
+
+    restart_hosts
+
     # If any files have changed that require the user to restart their virtual
     # desktops (eg, the wrapper script itself) then notify them but don't do
     # anything that would result in them losing state.
@@ -57,6 +63,11 @@
       rmdir --ignore-fail-on-non-empty "$VAR_DIR"
     fi
     ;;
+
+  "triggered")
+    echo "Responding to dpkg trigger."
+    restart_hosts
+    ;;
 esac
 
 # Create defaults file.
diff --git a/remoting/host/installer/linux/debian/triggers b/remoting/host/installer/linux/debian/triggers
new file mode 100644
index 0000000..30ad371
--- /dev/null
+++ b/remoting/host/installer/linux/debian/triggers
@@ -0,0 +1,2 @@
+interest-noawait /lib/x86_64-linux-gnu/libpam.so.0
+interest-noawait /lib/x86_64-linux-gnu/security
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
index e00e3125..5c70e1f 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
@@ -40,9 +40,11 @@
 namespace {
 
 bool IsBaselinePolicyAllowed(int sysno) {
+  // clang-format off
   return SyscallSets::IsAllowedAddressSpaceAccess(sysno) ||
          SyscallSets::IsAllowedBasicScheduler(sysno) ||
          SyscallSets::IsAllowedEpoll(sysno) ||
+         SyscallSets::IsEventFd(sysno) ||
          SyscallSets::IsAllowedFileSystemAccessViaFd(sysno) ||
          SyscallSets::IsAllowedFutex(sysno) ||
          SyscallSets::IsAllowedGeneralIo(sysno) ||
@@ -59,6 +61,7 @@
          SyscallSets::IsMipsPrivate(sysno) ||
 #endif
          SyscallSets::IsAllowedOperationOnFd(sysno);
+  // clang-format on
 }
 
 // System calls that will trigger the crashing SIGSYS handler.
@@ -68,7 +71,6 @@
          SyscallSets::IsAdvancedTimer(sysno) ||
          SyscallSets::IsAsyncIo(sysno) ||
          SyscallSets::IsDebug(sysno) ||
-         SyscallSets::IsEventFd(sysno) ||
          SyscallSets::IsExtendedAttributes(sysno) ||
          SyscallSets::IsFaNotify(sysno) ||
          SyscallSets::IsFsControl(sysno) ||
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.cc
index 35ab90e..c9d598c 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.cc
@@ -151,11 +151,6 @@
       break;
   }
 
-  // https://crbug.com/772441 and https://crbug.com/760020.
-  if (SyscallSets::IsEventFd(sysno)) {
-    return Allow();
-  }
-
   // Ptrace is allowed so the crash reporter can fork in a renderer
   // and then ptrace the parent. https://crbug.com/933418
   if (sysno == __NR_ptrace) {
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
index 01c046d..68c29b5 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
@@ -303,7 +303,6 @@
 TEST_BASELINE_SIGSYS(__NR_timer_create)
 
 #if !defined(__aarch64__)
-TEST_BASELINE_SIGSYS(__NR_eventfd)
 TEST_BASELINE_SIGSYS(__NR_inotify_init)
 TEST_BASELINE_SIGSYS(__NR_vserver)
 #endif
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
index 2a97d39..8fa54f5 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -215,7 +215,7 @@
   // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries.
   const uint64_t kAllowedMask = MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS |
                                 MAP_STACK | MAP_NORESERVE | MAP_FIXED |
-                                MAP_DENYWRITE;
+                                MAP_DENYWRITE | MAP_LOCKED;
   const Arg<int> flags(3);
   return If((flags & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS());
 }
@@ -245,9 +245,12 @@
 
   const uint64_t kAllowedMask = O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC |
                                 kOLargeFileFlag | O_CLOEXEC | O_NOATIME;
+  const uint64_t kAllowedSeals = F_SEAL_SEAL | F_SEAL_GROW | F_SEAL_SHRINK;
+  // clang-format off
   return Switch(cmd)
       .CASES((F_GETFL,
               F_GETFD,
+              F_GET_SEALS,
               F_SETFD,
               F_SETLK,
               F_SETLKW,
@@ -257,7 +260,10 @@
              Allow())
       .Case(F_SETFL,
             If((long_arg & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS()))
+      .Case(F_ADD_SEALS,
+            If((long_arg & ~kAllowedSeals) == 0, Allow()).Else(CrashSIGSYS()))
       .Default(CrashSIGSYS());
+  // clang-format on
 }
 
 #if defined(__i386__) || defined(__mips__)
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
index d9d18822..f40d436 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
@@ -168,9 +168,11 @@
 bool SyscallSets::IsAllowedFileSystemAccessViaFd(int sysno) {
   switch (sysno) {
     case __NR_fstat:
+    case __NR_ftruncate:
 #if defined(__i386__) || defined(__arm__) || \
     (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS))
     case __NR_fstat64:
+    case __NR_ftruncate64:
 #endif
       return true;
 // TODO(jln): these should be denied gracefully as well (moved below).
@@ -211,14 +213,9 @@
     case __NR_fallocate:
     case __NR_fchmod:
     case __NR_fchown:
-    case __NR_ftruncate:
 #if defined(__i386__) || defined(__arm__)
     case __NR_fchown32:
 #endif
-#if defined(__i386__) || defined(__arm__) || \
-    (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS))
-    case __NR_ftruncate64:
-#endif
 #if !defined(__aarch64__)
     case __NR_getdents:    // EPERM not a valid errno.
 #endif
diff --git a/sandbox/policy/BUILD.gn b/sandbox/policy/BUILD.gn
index 5b94f20..50073ae 100644
--- a/sandbox/policy/BUILD.gn
+++ b/sandbox/policy/BUILD.gn
@@ -128,6 +128,7 @@
       "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.intl",
       "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.logger",
       "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.mediacodec",
+      "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.memorypressure",
       "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.net",
       "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.net.interfaces",
       "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.sysmem",
diff --git a/sandbox/policy/fuchsia/sandbox_policy_fuchsia.cc b/sandbox/policy/fuchsia/sandbox_policy_fuchsia.cc
index 1ea75f7..42b6af2 100644
--- a/sandbox/policy/fuchsia/sandbox_policy_fuchsia.cc
+++ b/sandbox/policy/fuchsia/sandbox_policy_fuchsia.cc
@@ -14,6 +14,7 @@
 #include <fuchsia/intl/cpp/fidl.h>
 #include <fuchsia/logger/cpp/fidl.h>
 #include <fuchsia/mediacodec/cpp/fidl.h>
+#include <fuchsia/memorypressure/cpp/fidl.h>
 #include <fuchsia/net/cpp/fidl.h>
 #include <fuchsia/net/interfaces/cpp/fidl.h>
 #include <fuchsia/sysmem/cpp/fidl.h>
@@ -100,6 +101,7 @@
     base::make_span((const char* const[]){
         fuchsia::fonts::Provider::Name_,
         fuchsia::mediacodec::CodecFactory::Name_,
+        fuchsia::memorypressure::Provider::Name_,
         fuchsia::sysmem::Allocator::Name_,
     }),
     kAmbientMarkVmoAsExecutable,
diff --git a/sandbox/policy/linux/bpf_base_policy_linux.cc b/sandbox/policy/linux/bpf_base_policy_linux.cc
index 90164ea..04bd9c84 100644
--- a/sandbox/policy/linux/bpf_base_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_base_policy_linux.cc
@@ -31,6 +31,11 @@
 ResultExpr BPFBasePolicy::EvaluateSyscall(int system_call_number) const {
   DCHECK(baseline_policy_);
 
+  // Used for shared memory Mojo channels on Linux.
+  if (system_call_number == __NR_memfd_create) {
+    return Allow();
+  }
+
   // set_robust_list(2) is part of the futex(2) infrastructure.
   // Chrome on Linux/Chrome OS will call set_robust_list(2) frequently.
   // The baseline policy will EPERM set_robust_list(2), but on systems with
diff --git a/sandbox/policy/linux/bpf_gpu_policy_linux.cc b/sandbox/policy/linux/bpf_gpu_policy_linux.cc
index 829efee8b..dd4c3116 100644
--- a/sandbox/policy/linux/bpf_gpu_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_gpu_policy_linux.cc
@@ -93,8 +93,6 @@
     default:
       break;
   }
-  if (SyscallSets::IsEventFd(sysno))
-    return Allow();
 
 #if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && defined(USE_X11)
   if (SyscallSets::IsSystemVSharedMemory(sysno))
diff --git a/sandbox/policy/sandbox_delegate.h b/sandbox/policy/sandbox_delegate.h
index d827c94..ecca1e1 100644
--- a/sandbox/policy/sandbox_delegate.h
+++ b/sandbox/policy/sandbox_delegate.h
@@ -38,6 +38,9 @@
 
   // Called right after the process is launched, but before its thread is run.
   virtual void PostSpawnTarget(base::ProcessHandle process) = 0;
+
+  // Whether this process should run inside a Job if running unsandboxed.
+  virtual bool ShouldUnsandboxedRunInJob() = 0;
 #endif  // defined(OS_WIN)
 };
 
diff --git a/sandbox/policy/win/sandbox_win.cc b/sandbox/policy/win/sandbox_win.cc
index 9793ece..2af92ac6 100644
--- a/sandbox/policy/win/sandbox_win.cc
+++ b/sandbox/policy/win/sandbox_win.cc
@@ -58,8 +58,6 @@
 
 BrokerServices* g_broker_services = NULL;
 
-HANDLE g_job_object_handle = NULL;
-
 // The DLLs listed here are known (or under strong suspicion) of causing crashes
 // when they are loaded in the renderer. Note: at runtime we generate short
 // versions of the dll name only if the dll has an extension.
@@ -933,24 +931,26 @@
       launcher_process_command_line.HasSwitch(switches::kNoSandbox)) {
     base::LaunchOptions options;
     options.handles_to_inherit = handles_to_inherit;
-    BOOL in_job = true;
-    // Prior to Windows 8 nested jobs aren't possible.
-    if (sandbox_type == SandboxType::kNetwork &&
-        (base::win::GetVersion() >= base::win::Version::WIN8 ||
-         (::IsProcessInJob(::GetCurrentProcess(), nullptr, &in_job) &&
-          !in_job))) {
-      // Launch the process in a job to ensure that the network process doesn't
-      // outlive the browser. This could happen if there is a lot of I/O on
-      // process shutdown, in which case TerminateProcess would fail.
-      // https://crbug.com/820996
-      if (!g_job_object_handle) {
-        Job job_obj;
-        DWORD result = job_obj.Init(JOB_UNPROTECTED, nullptr, 0, 0);
-        if (result != ERROR_SUCCESS)
-          return SBOX_ERROR_CANNOT_INIT_JOB;
-        g_job_object_handle = job_obj.Take().Take();
+    // Network process runs in a job even when unsandboxed. This is to ensure it
+    // does not outlive the browser, which could happen if there is a lot of I/O
+    // on process shutdown, in which case TerminateProcess can fail. See
+    // https://crbug.com/820996.
+    if (delegate->ShouldUnsandboxedRunInJob()) {
+      BOOL in_job = true;
+      // Prior to Windows 8 nested jobs aren't possible.
+      if (base::win::GetVersion() >= base::win::Version::WIN8 ||
+          (::IsProcessInJob(::GetCurrentProcess(), nullptr, &in_job) &&
+           !in_job)) {
+        static HANDLE job_object_handle = nullptr;
+        if (!job_object_handle) {
+          Job job_obj;
+          DWORD result = job_obj.Init(JOB_UNPROTECTED, nullptr, 0, 0);
+          if (result != ERROR_SUCCESS)
+            return SBOX_ERROR_CANNOT_INIT_JOB;
+          job_object_handle = job_obj.Take().Take();
+        }
+        options.job_handle = job_object_handle;
       }
-      options.job_handle = g_job_object_handle;
     }
     *process = base::LaunchProcess(*cmd_line, options);
     return SBOX_ALL_OK;
@@ -1002,10 +1002,6 @@
       sandbox_type == SandboxType::kIconReader) {
     mitigations |= MITIGATION_DYNAMIC_CODE_DISABLE;
   }
-  // TODO(wfh): Relax strict handle checks for network process until root cause
-  // for this crash can be resolved. See https://crbug.com/939590.
-  if (sandbox_type != SandboxType::kNetwork)
-    mitigations |= MITIGATION_STRICT_HANDLE_CHECKS;
 
   result = policy->SetDelayedProcessMitigations(mitigations);
   if (result != SBOX_ALL_OK)
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn
index 1144223..7ad5b7b 100644
--- a/sandbox/win/BUILD.gn
+++ b/sandbox/win/BUILD.gn
@@ -238,6 +238,8 @@
     ":sbox_integration_test_hooking_dll",
     ":sbox_integration_test_win_proc",
   ]
+
+  libs = [ "ktmw32.lib" ]
 }
 
 shared_library("sbox_integration_test_hijack_dll") {
diff --git a/sandbox/win/src/process_mitigations.cc b/sandbox/win/src/process_mitigations.cc
index d6a420a9..69dc925 100644
--- a/sandbox/win/src/process_mitigations.cc
+++ b/sandbox/win/src/process_mitigations.cc
@@ -528,6 +528,14 @@
   return;
 }
 
+void ConvertProcessMitigationsToComponentFilter(MitigationFlags flags,
+                                                COMPONENT_FILTER* filter) {
+  filter->ComponentFlags = 0;
+  if (flags & MITIGATION_KTM_COMPONENT) {
+    filter->ComponentFlags = COMPONENT_KTM;
+  }
+}
+
 MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags) {
   base::win::Version version = base::win::GetVersion();
 
diff --git a/sandbox/win/src/process_mitigations.h b/sandbox/win/src/process_mitigations.h
index 26dc42e..3b511fe 100644
--- a/sandbox/win/src/process_mitigations.h
+++ b/sandbox/win/src/process_mitigations.h
@@ -11,6 +11,23 @@
 
 #include "sandbox/win/src/security_level.h"
 
+// This will be defined in an upcoming Windows SDK release
+#ifndef COMPONENT_KTM
+
+#define COMPONENT_KTM 0x01
+#define COMPONENT_VALID_FLAGS (COMPONENT_KTM)
+#define ProcThreadAttributeComponentFilter 26
+
+typedef struct _COMPONENT_FILTER {
+  ULONG ComponentFlags;
+} COMPONENT_FILTER, *PCOMPONENT_FILTER;
+
+#define PROC_THREAD_ATTRIBUTE_COMPONENT_FILTER                              \
+  ProcThreadAttributeValue(ProcThreadAttributeComponentFilter, FALSE, TRUE, \
+                           FALSE)
+
+#endif  // COMPONENT_KTM
+
 namespace sandbox {
 
 // Sets the mitigation policy for the current process, ignoring any settings
@@ -34,6 +51,11 @@
                                        DWORD64* policy_flags,
                                        size_t* size);
 
+// Converts sandbox flags to COMPONENT_FILTER so that it can be passed directly
+// to UpdateProcThreadAttribute().
+void ConvertProcessMitigationsToComponentFilter(MitigationFlags flags,
+                                                COMPONENT_FILTER* filter);
+
 // Adds mitigations that need to be performed on the suspended target process
 // before execution begins.
 bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process,
diff --git a/sandbox/win/src/process_mitigations_unittest.cc b/sandbox/win/src/process_mitigations_unittest.cc
index 88c67ca2..3fc6d146 100644
--- a/sandbox/win/src/process_mitigations_unittest.cc
+++ b/sandbox/win/src/process_mitigations_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "sandbox/win/src/process_mitigations.h"
 
+#include <ktmw32.h>
 #include <windows.h>
 
 #include "base/files/file_util.h"
@@ -12,6 +13,7 @@
 #include "base/process/kill.h"
 #include "base/scoped_native_library.h"
 #include "base/test/test_timeouts.h"
+#include "base/win/scoped_handle.h"
 #include "base/win/windows_version.h"
 #include "sandbox/win/src/nt_internals.h"
 #include "sandbox/win/src/target_services.h"
@@ -384,6 +386,25 @@
 
       break;
     }
+    //--------------------------------------------------
+    // MITIGATION_KTM_COMPONENT_FILTER
+    //--------------------------------------------------
+    case (TESTPOLICY_KTMCOMPONENTFILTER): {
+      // If the mitigation is enabled, creating a KTM should fail.
+      SECURITY_ATTRIBUTES tm_attributes = {0};
+      tm_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+      tm_attributes.lpSecurityDescriptor = nullptr;
+      tm_attributes.bInheritHandle = false;
+      base::win::ScopedHandle ktm;
+      ktm.Set(CreateTransactionManager(&tm_attributes, nullptr,
+                                       TRANSACTION_MANAGER_VOLATILE,
+                                       TRANSACTION_MANAGER_COMMIT_DEFAULT));
+      if (ktm.IsValid() || ::GetLastError() != ERROR_ACCESS_DENIED)
+        return SBOX_TEST_FAILED;
+
+      break;
+    }
+
     default:
       return SBOX_TEST_INVALID_PARAMETER;
   }
@@ -1122,4 +1143,16 @@
   //---------------------------------
 }
 
+TEST(ProcessMitigationsTest, CheckWin10KernelTransactionManagerMitigation) {
+  if (base::win::GetVersion() < base::win::Version::WIN10_21H1)
+    return;
+  std::wstring test_policy_command = L"CheckPolicy ";
+  test_policy_command += std::to_wstring(TESTPOLICY_KTMCOMPONENTFILTER);
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_KTM_COMPONENT),
+            SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_policy_command.c_str()));
+}
+
 }  // namespace sandbox
diff --git a/sandbox/win/src/security_level.h b/sandbox/win/src/security_level.h
index 182a7dd..bdeac002 100644
--- a/sandbox/win/src/security_level.h
+++ b/sandbox/win/src/security_level.h
@@ -293,6 +293,10 @@
 // PROCESS_CREATION_MITIGATION_POLICY2_CET_USER_SHADOW_STACKS_ALWAYS_OFF.
 const MitigationFlags MITIGATION_CET_DISABLED = 0x00400000;
 
+// Enable KTM component mitigation. When enabled, it locks down all function
+// calls to consume the kernel transaction manager.
+const MitigationFlags MITIGATION_KTM_COMPONENT = 0x00800000;
+
 }  // namespace sandbox
 
 #endif  // SANDBOX_SRC_SECURITY_LEVEL_H_
diff --git a/sandbox/win/src/startup_information_helper.cc b/sandbox/win/src/startup_information_helper.cc
index eaa3aa1..d25d46d3 100644
--- a/sandbox/win/src/startup_information_helper.cc
+++ b/sandbox/win/src/startup_information_helper.cc
@@ -14,7 +14,9 @@
 #include "base/win/startup_information.h"
 #include "base/win/windows_version.h"
 #include "sandbox/win/src/app_container_profile.h"
+#include "sandbox/win/src/nt_internals.h"
 #include "sandbox/win/src/security_capabilities.h"
+#include "sandbox/win/src/win_utils.h"
 
 namespace sandbox {
 using base::win::StartupInformation;
@@ -39,6 +41,7 @@
 void StartupInformationHelper::SetMitigations(MitigationFlags flags) {
   ConvertProcessMitigationsToPolicy(flags, &mitigations_[0],
                                     &mitigations_size_);
+  ConvertProcessMitigationsToComponentFilter(flags, &component_filter_);
 }
 
 void StartupInformationHelper::SetRestrictChildProcessCreation(bool restrict) {
@@ -85,6 +88,9 @@
   if (mitigations_[0] || mitigations_[1])
     ++attribute_count;
 
+  if (component_filter_.ComponentFlags)
+    ++attribute_count;
+
   if (restrict_child_process_creation_)
     ++attribute_count;
 
@@ -120,6 +126,16 @@
     expected_attributes--;
   }
 
+  if (component_filter_.ComponentFlags) {
+    if (!startup_info_.UpdateProcThreadAttribute(
+            PROC_THREAD_ATTRIBUTE_COMPONENT_FILTER, &component_filter_,
+            sizeof(component_filter_)) &&
+        ::GetLastError() != ERROR_NOT_SUPPORTED) {
+      return false;
+    }
+    expected_attributes--;
+  }
+
   if (restrict_child_process_creation_) {
     child_process_creation_ = PROCESS_CREATION_CHILD_PROCESS_RESTRICTED;
     if (!startup_info_.UpdateProcThreadAttribute(
diff --git a/sandbox/win/src/startup_information_helper.h b/sandbox/win/src/startup_information_helper.h
index 0f1411ef..5327195 100644
--- a/sandbox/win/src/startup_information_helper.h
+++ b/sandbox/win/src/startup_information_helper.h
@@ -81,9 +81,10 @@
 
   // These need to have the same lifetime as startup_info_.startup_info();
   std::wstring desktop_;
-  DWORD64 mitigations_[2];
-  DWORD child_process_creation_;
-  DWORD all_applications_package_policy_;
+  DWORD64 mitigations_[2]{};
+  COMPONENT_FILTER component_filter_{};
+  DWORD child_process_creation_ = 0;
+  DWORD all_applications_package_policy_ = 0;
   std::vector<HANDLE> inherited_handle_list_;
   std::vector<HANDLE> job_handle_list_;
   std::unique_ptr<SecurityCapabilities> security_capabilities_ = nullptr;
diff --git a/sandbox/win/tests/integration_tests/integration_tests_common.h b/sandbox/win/tests/integration_tests/integration_tests_common.h
index 9c9a083..d4e0fb7 100644
--- a/sandbox/win/tests/integration_tests/integration_tests_common.h
+++ b/sandbox/win/tests/integration_tests/integration_tests_common.h
@@ -29,7 +29,8 @@
   TESTPOLICY_DYNAMICCODEOPTOUT,
   TESTPOLICY_LOADPREFERSYS32,
   TESTPOLICY_RESTRICTINDIRECTBRANCHPREDICTION,
-  TESTPOLICY_CETDISABLED
+  TESTPOLICY_CETDISABLED,
+  TESTPOLICY_KTMCOMPONENTFILTER,
 };
 
 // Timeout for ::WaitForSingleObject synchronization.
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 1308bdf..a651848 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -2895,6 +2895,32 @@
       }
     ]
   },
+  "linux-chromeos-js-code-coverage": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--gtest_filter=*FilesApp*"
+        ],
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "js_code_coverage_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-16.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "browser_tests",
+        "test_id_prefix": "ninja://chrome/test:browser_tests/"
+      }
+    ]
+  },
   "linux-chromeos-rel": {
     "additional_compile_targets": [
       "gn_all"
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index 6ec2781..619bdbe 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -233,20 +233,20 @@
     "isolated_scripts": [
       {
         "args": [
+          "hardware_accelerated_feature",
+          "--show-stdout",
+          "--browser=web-engine-shell",
+          "--passthrough",
           "-v",
-          "--browser=release",
-          "--upload-results",
-          "--test-shard-map-filename=fuchsia-perf-fyi_map.json",
-          "--output-format=histograms",
-          "--experimental-tbmv3-metrics"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
         ],
-        "isolate_name": "performance_test_suite",
+        "isolate_name": "fuchsia_telemetry_gpu_integration_test",
         "merge": {
           "script": "//tools/perf/process_perf_results.py"
         },
-        "name": "performance_test_suite",
+        "name": "fuchsia_telemetry_gpu_integration_test",
         "override_compile_targets": [
-          "performance_test_suite"
+          "fuchsia_telemetry_gpu_integration_test"
         ],
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -261,8 +261,7 @@
           "hard_timeout": 21600,
           "ignore_task_failure": false,
           "io_timeout": 21600,
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 1
+          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "trigger_script": {
           "args": [
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 5ddd286..bc33faf 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1649,6 +1649,15 @@
           'gtest_tests': 'linux_chromeos_gtests',
         },
       },
+      'linux-chromeos-js-code-coverage': {
+        'mixins': [
+          'isolate_profile_data',
+          'linux-xenial',
+        ],
+        'test_suites': {
+          'gtest_tests': 'js_code_coverage_browser_tests'
+        },
+      },
       'linux-chromeos-rel': {
         'mixins': [
           'isolate_profile_data',
diff --git a/testing/gmock/BUILD.gn b/testing/gmock/BUILD.gn
index 0e7cc53..0248d146 100644
--- a/testing/gmock/BUILD.gn
+++ b/testing/gmock/BUILD.gn
@@ -13,7 +13,7 @@
     "include/gmock/gmock-matchers.h",
     "include/gmock/gmock.h",
   ]
-  deps = [ "//third_party/googletest:gmock" ]
+  public_deps = [ "//third_party/googletest:gmock" ]
 
   public_configs = [
     "//third_party/googletest:gmock_config",
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index a0be697..b2607a3 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2164,6 +2164,27 @@
             ]
         }
     ],
+    "DeclarativeShadowDOM": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "chromeos",
+                "chromeos_lacros",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "DeclarativeShadowDOM"
+                    ]
+                }
+            ]
+        }
+    ],
     "DecoupleSyncFromAndroidMasterSync": [
         {
             "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index ad44389..0d12442 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -843,6 +843,10 @@
     "SendCnameAliasesToSubresourceFilterFromRenderer",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables the declarative Shadow DOM feature.
+const base::Feature kDeclarativeShadowDOM{"DeclarativeShadowDOM",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Kill switch for the InterestCohort API origin trial, i.e. if disabled, the
 // API exposure will be disabled regardless of the OT config.
 // (See https://github.com/WICG/floc.)
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 4db1e5b3..6b5278e 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -350,6 +350,8 @@
 BLINK_COMMON_EXPORT extern const base::Feature
     kSendCnameAliasesToSubresourceFilterFromRenderer;
 
+BLINK_COMMON_EXPORT extern const base::Feature kDeclarativeShadowDOM;
+
 BLINK_COMMON_EXPORT extern const base::Feature kInterestCohortAPIOriginTrial;
 
 BLINK_COMMON_EXPORT extern const base::Feature kInterestCohortFeaturePolicy;
diff --git a/third_party/blink/renderer/core/css/counter_style.cc b/third_party/blink/renderer/core/css/counter_style.cc
index d965727..7ced2ae 100644
--- a/third_party/blink/renderer/core/css/counter_style.cc
+++ b/third_party/blink/renderer/core/css/counter_style.cc
@@ -54,6 +54,8 @@
       return CounterStyleSystem::kNumeric;
     case CSSValueID::kAdditive:
       return CounterStyleSystem::kAdditive;
+    case CSSValueID::kInternalHebrew:
+      return CounterStyleSystem::kHebrew;
     case CSSValueID::kInternalSimpChineseInformal:
       return CounterStyleSystem::kSimpChineseInformal;
     case CSSValueID::kInternalSimpChineseFormal:
@@ -62,6 +64,16 @@
       return CounterStyleSystem::kTradChineseInformal;
     case CSSValueID::kInternalTradChineseFormal:
       return CounterStyleSystem::kTradChineseFormal;
+    case CSSValueID::kInternalKoreanHangulFormal:
+      return CounterStyleSystem::kKoreanHangulFormal;
+    case CSSValueID::kInternalKoreanHanjaInformal:
+      return CounterStyleSystem::kKoreanHanjaInformal;
+    case CSSValueID::kInternalKoreanHanjaFormal:
+      return CounterStyleSystem::kKoreanHanjaFormal;
+    case CSSValueID::kInternalLowerArmenian:
+      return CounterStyleSystem::kLowerArmenian;
+    case CSSValueID::kInternalUpperArmenian:
+      return CounterStyleSystem::kUpperArmenian;
     case CSSValueID::kExtends:
       return CounterStyleSystem::kUnresolvedExtends;
     default:
@@ -80,10 +92,16 @@
     case CounterStyleSystem::kAdditive:
       return true;
     case CounterStyleSystem::kUnresolvedExtends:
+    case CounterStyleSystem::kHebrew:
     case CounterStyleSystem::kSimpChineseInformal:
     case CounterStyleSystem::kSimpChineseFormal:
     case CounterStyleSystem::kTradChineseInformal:
     case CounterStyleSystem::kTradChineseFormal:
+    case CounterStyleSystem::kKoreanHangulFormal:
+    case CounterStyleSystem::kKoreanHanjaInformal:
+    case CounterStyleSystem::kKoreanHanjaFormal:
+    case CounterStyleSystem::kLowerArmenian:
+    case CounterStyleSystem::kUpperArmenian:
       return false;
   }
 }
@@ -105,10 +123,16 @@
       return additive_symbols && additive_symbols->length();
     case CounterStyleSystem::kUnresolvedExtends:
       return !symbols && !additive_symbols;
+    case CounterStyleSystem::kHebrew:
     case CounterStyleSystem::kSimpChineseInformal:
     case CounterStyleSystem::kSimpChineseFormal:
     case CounterStyleSystem::kTradChineseInformal:
     case CounterStyleSystem::kTradChineseFormal:
+    case CounterStyleSystem::kKoreanHangulFormal:
+    case CounterStyleSystem::kKoreanHanjaInformal:
+    case CounterStyleSystem::kKoreanHanjaFormal:
+    case CounterStyleSystem::kLowerArmenian:
+    case CounterStyleSystem::kUpperArmenian:
       return true;
   }
 }
@@ -238,6 +262,12 @@
 // code paths are removed, remove everything else of list_marker_text and move
 // the implementation of the special algorithms here.
 
+String HebrewAlgorithm(unsigned value) {
+  if (value > 999999)
+    return String();
+  return list_marker_text::GetText(EListStyleType::kHebrew, value);
+}
+
 String SimpChineseInformalAlgorithm(unsigned value) {
   // @counter-style algorithm works on absolute value, but the legacy
   // implementation works on the original value (and handles negative sign on
@@ -274,6 +304,45 @@
   return list_marker_text::GetText(EListStyleType::kTradChineseFormal, value);
 }
 
+String KoreanHangulFormalAlgorithm(unsigned value) {
+  // @counter-style algorithm works on absolute value, but the legacy
+  // implementation works on the original value (and handles negative sign on
+  // its own). Range check before proceeding.
+  if (value > std::numeric_limits<int>::max())
+    return String();
+  return list_marker_text::GetText(EListStyleType::kKoreanHangulFormal, value);
+}
+
+String KoreanHanjaInformalAlgorithm(unsigned value) {
+  // @counter-style algorithm works on absolute value, but the legacy
+  // implementation works on the original value (and handles negative sign on
+  // its own). Range check before proceeding.
+  if (value > std::numeric_limits<int>::max())
+    return String();
+  return list_marker_text::GetText(EListStyleType::kKoreanHanjaInformal, value);
+}
+
+String KoreanHanjaFormalAlgorithm(unsigned value) {
+  // @counter-style algorithm works on absolute value, but the legacy
+  // implementation works on the original value (and handles negative sign on
+  // its own). Range check before proceeding.
+  if (value > std::numeric_limits<int>::max())
+    return String();
+  return list_marker_text::GetText(EListStyleType::kKoreanHanjaFormal, value);
+}
+
+String LowerArmenianAlgorithm(unsigned value) {
+  if (value > 99999999)
+    return String();
+  return list_marker_text::GetText(EListStyleType::kLowerArmenian, value);
+}
+
+String UpperArmenianAlgorithm(unsigned value) {
+  if (value > 99999999)
+    return String();
+  return list_marker_text::GetText(EListStyleType::kUpperArmenian, value);
+}
+
 }  // namespace
 
 // static
@@ -423,12 +492,20 @@
     case CounterStyleSystem::kSimpChineseFormal:
     case CounterStyleSystem::kTradChineseInformal:
     case CounterStyleSystem::kTradChineseFormal:
+    case CounterStyleSystem::kKoreanHangulFormal:
+    case CounterStyleSystem::kKoreanHanjaInformal:
+    case CounterStyleSystem::kKoreanHanjaFormal:
       return true;
     case CounterStyleSystem::kSymbolic:
     case CounterStyleSystem::kAlphabetic:
       return value >= 1;
     case CounterStyleSystem::kAdditive:
       return value >= 0;
+    case CounterStyleSystem::kHebrew:
+      return value >= 0 && value <= 999999;
+    case CounterStyleSystem::kLowerArmenian:
+    case CounterStyleSystem::kUpperArmenian:
+      return value >= 0 && value <= 99999999;
     case CounterStyleSystem::kUnresolvedExtends:
       NOTREACHED();
       return false;
@@ -443,10 +520,16 @@
     case CounterStyleSystem::kAlphabetic:
     case CounterStyleSystem::kNumeric:
     case CounterStyleSystem::kAdditive:
+    case CounterStyleSystem::kHebrew:
     case CounterStyleSystem::kSimpChineseInformal:
     case CounterStyleSystem::kSimpChineseFormal:
     case CounterStyleSystem::kTradChineseInformal:
     case CounterStyleSystem::kTradChineseFormal:
+    case CounterStyleSystem::kKoreanHangulFormal:
+    case CounterStyleSystem::kKoreanHanjaInformal:
+    case CounterStyleSystem::kKoreanHanjaFormal:
+    case CounterStyleSystem::kLowerArmenian:
+    case CounterStyleSystem::kUpperArmenian:
       return true;
     case CounterStyleSystem::kCyclic:
     case CounterStyleSystem::kFixed:
@@ -523,6 +606,8 @@
       return IndexesToString(AlphabeticAlgorithm(abs_value, symbols_.size()));
     case CounterStyleSystem::kAdditive:
       return IndexesToString(AdditiveAlgorithm(abs_value, additive_weights_));
+    case CounterStyleSystem::kHebrew:
+      return HebrewAlgorithm(abs_value);
     case CounterStyleSystem::kSimpChineseInformal:
       return SimpChineseInformalAlgorithm(abs_value);
     case CounterStyleSystem::kSimpChineseFormal:
@@ -531,6 +616,16 @@
       return TradChineseInformalAlgorithm(abs_value);
     case CounterStyleSystem::kTradChineseFormal:
       return TradChineseFormalAlgorithm(abs_value);
+    case CounterStyleSystem::kKoreanHangulFormal:
+      return KoreanHangulFormalAlgorithm(abs_value);
+    case CounterStyleSystem::kKoreanHanjaInformal:
+      return KoreanHanjaInformalAlgorithm(abs_value);
+    case CounterStyleSystem::kKoreanHanjaFormal:
+      return KoreanHanjaFormalAlgorithm(abs_value);
+    case CounterStyleSystem::kLowerArmenian:
+      return LowerArmenianAlgorithm(abs_value);
+    case CounterStyleSystem::kUpperArmenian:
+      return UpperArmenianAlgorithm(abs_value);
     case CounterStyleSystem::kUnresolvedExtends:
       NOTREACHED();
       return String();
diff --git a/third_party/blink/renderer/core/css/counter_style.h b/third_party/blink/renderer/core/css/counter_style.h
index 81b2556..0f7cdf36 100644
--- a/third_party/blink/renderer/core/css/counter_style.h
+++ b/third_party/blink/renderer/core/css/counter_style.h
@@ -20,10 +20,16 @@
   kAlphabetic,
   kNumeric,
   kAdditive,
+  kHebrew,
   kSimpChineseInformal,
   kSimpChineseFormal,
   kTradChineseInformal,
   kTradChineseFormal,
+  kKoreanHangulFormal,
+  kKoreanHanjaInformal,
+  kKoreanHanjaFormal,
+  kLowerArmenian,
+  kUpperArmenian,
   kUnresolvedExtends,
 };
 
diff --git a/third_party/blink/renderer/core/css/counter_style_test.cc b/third_party/blink/renderer/core/css/counter_style_test.cc
index 1bf0a8f0..ddc7a26 100644
--- a/third_party/blink/renderer/core/css/counter_style_test.cc
+++ b/third_party/blink/renderer/core/css/counter_style_test.cc
@@ -453,4 +453,126 @@
   EXPECT_EQ("Y", extended.GetSuffix());
 }
 
+TEST_F(CounterStyleTest, Hebrew) {
+  // Verifies that our 'hebrew' implementation matches the spec in the
+  // officially specified range 1-10999.
+  // https://drafts.csswg.org/css-counter-styles-3/#hebrew
+  const CounterStyle& hebrew_as_specced =
+      AddCounterStyle("hebrew-as-specced", R"CSS(
+    system: additive;
+    range: 1 10999;
+    additive-symbols: 10000 \5D9\5F3, 9000 \5D8\5F3, 8000 \5D7\5F3, 7000 \5D6\5F3, 6000 \5D5\5F3, 5000 \5D4\5F3, 4000 \5D3\5F3, 3000 \5D2\5F3, 2000 \5D1\5F3, 1000 \5D0\5F3, 400 \5EA, 300 \5E9, 200 \5E8, 100 \5E7, 90 \5E6, 80 \5E4, 70 \5E2, 60 \5E1, 50 \5E0, 40 \5DE, 30 \5DC, 20 \5DB, 19 \5D9\5D8, 18 \5D9\5D7, 17 \5D9\5D6, 16 \5D8\5D6, 15 \5D8\5D5, 10 \5D9, 9 \5D8, 8 \5D7, 7 \5D6, 6 \5D5, 5 \5D4, 4 \5D3, 3 \5D2, 2 \5D1, 1 \5D0;
+  )CSS");
+  const CounterStyle& hebrew_as_implemented = GetCounterStyle("hebrew");
+  for (int value = 1; value <= 10999; ++value) {
+    String expected = hebrew_as_specced.GenerateRepresentation(value);
+    String actual = hebrew_as_implemented.GenerateRepresentation(value);
+    EXPECT_EQ(expected, actual);
+  }
+}
+
+TEST_F(CounterStyleTest, LowerArmenian) {
+  // Verifies that our 'lower-armenian' implementation matches the spec in the
+  // officially specified range 1-9999.
+  // https://drafts.csswg.org/css-counter-styles-3/#valdef-counter-style-name-lower-armenian
+  const CounterStyle& lower_armenian_as_specced =
+      AddCounterStyle("lower-armenian-as-specced", R"CSS(
+    system: additive;
+    range: 1 9999;
+    additive-symbols: 9000 "\584", 8000 "\583", 7000 "\582", 6000 "\581", 5000 "\580", 4000 "\57F", 3000 "\57E", 2000 "\57D", 1000 "\57C", 900 "\57B", 800 "\57A", 700 "\579", 600 "\578", 500 "\577", 400 "\576", 300 "\575", 200 "\574", 100 "\573", 90 "\572", 80 "\571", 70 "\570", 60 "\56F", 50 "\56E", 40 "\56D", 30 "\56C", 20 "\56B", 10 "\56A", 9 "\569", 8 "\568", 7 "\567", 6 "\566", 5 "\565", 4 "\564", 3 "\563", 2 "\562", 1 "\561";
+  )CSS");
+  const CounterStyle& lower_armenian_as_implemented =
+      GetCounterStyle("lower-armenian");
+  for (int value = 1; value <= 9999; ++value) {
+    String expected = lower_armenian_as_specced.GenerateRepresentation(value);
+    String actual = lower_armenian_as_implemented.GenerateRepresentation(value);
+    EXPECT_EQ(expected, actual);
+  }
+}
+
+TEST_F(CounterStyleTest, UpperArmenian) {
+  // Verifies that our 'upper-armenian' implementation matches the spec in the
+  // officially specified range 1-9999.
+  // https://drafts.csswg.org/css-counter-styles-3/#valdef-counter-style-name-upper-armenian
+  const CounterStyle& upper_armenian_as_specced =
+      AddCounterStyle("upper-armenian-as-specced", R"CSS(
+    system: additive;
+    range: 1 9999;
+    additive-symbols: 9000 \554, 8000 \553, 7000 \552, 6000 \551, 5000 \550, 4000 \54F, 3000 \54E, 2000 \54D, 1000 \54C, 900 \54B, 800 \54A, 700 \549, 600 \548, 500 \547, 400 \546, 300 \545, 200 \544, 100 \543, 90 \542, 80 \541, 70 \540, 60 \53F, 50 \53E, 40 \53D, 30 \53C, 20 \53B, 10 \53A, 9 \539, 8 \538, 7 \537, 6 \536, 5 \535, 4 \534, 3 \533, 2 \532, 1 \531;
+  )CSS");
+  const CounterStyle& upper_armenian_as_implemented =
+      GetCounterStyle("upper-armenian");
+  for (int value = 1; value <= 9999; ++value) {
+    String expected = upper_armenian_as_specced.GenerateRepresentation(value);
+    String actual = upper_armenian_as_implemented.GenerateRepresentation(value);
+    EXPECT_EQ(expected, actual);
+  }
+}
+
+TEST_F(CounterStyleTest, KoreanHangulFormal) {
+  // Verifies that our 'korean-hangul-formal' implementation matches the spec in
+  // the officially specified range 1-9999.
+  // https://drafts.csswg.org/css-counter-styles-3/#korean-hangul-formal
+  const CounterStyle& korean_hangul_formal_as_specced =
+      AddCounterStyle("korean-hangul-formal-as-specced", R"CSS(
+    system: additive;
+    range: -9999 9999;
+    additive-symbols: 9000 \AD6C\CC9C, 8000 \D314\CC9C, 7000 \CE60\CC9C, 6000 \C721\CC9C, 5000 \C624\CC9C, 4000 \C0AC\CC9C, 3000 \C0BC\CC9C, 2000 \C774\CC9C, 1000 \C77C\CC9C, 900 \AD6C\BC31, 800 \D314\BC31, 700 \CE60\BC31, 600 \C721\BC31, 500 \C624\BC31, 400 \C0AC\BC31, 300 \C0BC\BC31, 200 \C774\BC31, 100 \C77C\BC31, 90 \AD6C\C2ED, 80 \D314\C2ED, 70 \CE60\C2ED, 60 \C721\C2ED, 50 \C624\C2ED, 40 \C0AC\C2ED, 30 \C0BC\C2ED, 20 \C774\C2ED, 10 \C77C\C2ED, 9 \AD6C, 8 \D314, 7 \CE60, 6 \C721, 5 \C624, 4 \C0AC, 3 \C0BC, 2 \C774, 1 \C77C, 0 \C601;
+    negative: "\B9C8\C774\B108\C2A4  ";
+  )CSS");
+  const CounterStyle& korean_hangul_formal_as_implemented =
+      GetCounterStyle("korean-hangul-formal");
+  for (int value = -9999; value <= 9999; ++value) {
+    String expected =
+        korean_hangul_formal_as_specced.GenerateRepresentation(value);
+    String actual =
+        korean_hangul_formal_as_implemented.GenerateRepresentation(value);
+    EXPECT_EQ(expected, actual);
+  }
+}
+
+TEST_F(CounterStyleTest, KoreanHanjaFormal) {
+  // Verifies that our 'korean-hanja-formal' implementation matches the spec in
+  // the officially specified range 1-9999.
+  // https://drafts.csswg.org/css-counter-styles-3/#korean-hanja-formal
+  const CounterStyle& korean_hanja_formal_as_specced =
+      AddCounterStyle("korean-hanja-formal-as-specced", R"CSS(
+    system: additive;
+    range: -9999 9999;
+    additive-symbols: 9000 \4E5D\4EDF, 8000 \516B\4EDF, 7000 \4E03\4EDF, 6000 \516D\4EDF, 5000 \4E94\4EDF, 4000 \56DB\4EDF, 3000 \53C3\4EDF, 2000 \8CB3\4EDF, 1000 \58F9\4EDF, 900 \4E5D\767E, 800 \516B\767E, 700 \4E03\767E, 600 \516D\767E, 500 \4E94\767E, 400 \56DB\767E, 300 \53C3\767E, 200 \8CB3\767E, 100 \58F9\767E, 90 \4E5D\62FE, 80 \516B\62FE, 70 \4E03\62FE, 60 \516D\62FE, 50 \4E94\62FE, 40 \56DB\62FE, 30 \53C3\62FE, 20 \8CB3\62FE, 10 \58F9\62FE, 9 \4E5D, 8 \516B, 7 \4E03, 6 \516D, 5 \4E94, 4 \56DB, 3 \53C3, 2 \8CB3, 1 \58F9, 0 \96F6;
+    negative: "\B9C8\C774\B108\C2A4  ";
+  )CSS");
+  const CounterStyle& korean_hanja_formal_as_implemented =
+      GetCounterStyle("korean-hanja-formal");
+  for (int value = -9999; value <= 9999; ++value) {
+    String expected =
+        korean_hanja_formal_as_specced.GenerateRepresentation(value);
+    String actual =
+        korean_hanja_formal_as_implemented.GenerateRepresentation(value);
+    EXPECT_EQ(expected, actual);
+  }
+}
+
+TEST_F(CounterStyleTest, KoreanHanjaInformal) {
+  // Verifies that our 'korean-hanja-informal' implementation matches the spec
+  // in the officially specified range 1-9999.
+  // https://drafts.csswg.org/css-counter-styles-3/#korean-hanja-informal
+  const CounterStyle& korean_hanja_informal_as_specced =
+      AddCounterStyle("korean-hanja-informal-as-specced", R"CSS(
+    system: additive;
+    range: -9999 9999;
+    additive-symbols: 9000 \4E5D\5343, 8000 \516B\5343, 7000 \4E03\5343, 6000 \516D\5343, 5000 \4E94\5343, 4000 \56DB\5343, 3000 \4E09\5343, 2000 \4E8C\5343, 1000 \5343, 900 \4E5D\767E, 800 \516B\767E, 700 \4E03\767E, 600 \516D\767E, 500 \4E94\767E, 400 \56DB\767E, 300 \4E09\767E, 200 \4E8C\767E, 100 \767E, 90 \4E5D\5341, 80 \516B\5341, 70 \4E03\5341, 60 \516D\5341, 50 \4E94\5341, 40 \56DB\5341, 30 \4E09\5341, 20 \4E8C\5341, 10 \5341, 9 \4E5D, 8 \516B, 7 \4E03, 6 \516D, 5 \4E94, 4 \56DB, 3 \4E09, 2 \4E8C, 1 \4E00, 0 \96F6;
+    negative: "\B9C8\C774\B108\C2A4  ";
+  )CSS");
+  const CounterStyle& korean_hanja_informal_as_implemented =
+      GetCounterStyle("korean-hanja-informal");
+  for (int value = -9999; value <= 9999; ++value) {
+    String expected =
+        korean_hanja_informal_as_specced.GenerateRepresentation(value);
+    String actual =
+        korean_hanja_informal_as_implemented.GenerateRepresentation(value);
+    EXPECT_EQ(expected, actual);
+  }
+}
+
 }  // namespace blink
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 745d3cd4..c81dcfe2 100644
--- a/third_party/blink/renderer/core/css/css_value_keywords.json5
+++ b/third_party/blink/renderer/core/css/css_value_keywords.json5
@@ -1479,6 +1479,12 @@
     "-internal-simp-chinese-formal",
     "-internal-trad-chinese-informal",
     "-internal-trad-chinese-formal",
+    "-internal-korean-hangul-formal",
+    "-internal-korean-hanja-informal",
+    "-internal-korean-hanja-formal",
+    "-internal-hebrew",
+    "-internal-lower-armenian",
+    "-internal-upper-armenian",
 
     // @counter-style range
     // infinite,
diff --git a/third_party/blink/renderer/core/css/parser/at_rule_counter_style_descriptor_parser.cc b/third_party/blink/renderer/core/css/parser/at_rule_counter_style_descriptor_parser.cc
index 756ba141..3f771ad 100644
--- a/third_party/blink/renderer/core/css/parser/at_rule_counter_style_descriptor_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/at_rule_counter_style_descriptor_parser.cc
@@ -66,10 +66,16 @@
   // algorithms. For example, 'simp-chinese-informal'.
   if (context.Mode() == kUASheetMode) {
     if (CSSValue* ident = css_parsing_utils::ConsumeIdent<
+            CSSValueID::kInternalHebrew,
             CSSValueID::kInternalSimpChineseInformal,
             CSSValueID::kInternalSimpChineseFormal,
             CSSValueID::kInternalTradChineseInformal,
-            CSSValueID::kInternalTradChineseFormal>(range))
+            CSSValueID::kInternalTradChineseFormal,
+            CSSValueID::kInternalKoreanHangulFormal,
+            CSSValueID::kInternalKoreanHanjaInformal,
+            CSSValueID::kInternalKoreanHanjaFormal,
+            CSSValueID::kInternalLowerArmenian,
+            CSSValueID::kInternalUpperArmenian>(range))
       return ident;
   }
 
diff --git a/third_party/blink/renderer/core/css/predefined_counter_styles.css b/third_party/blink/renderer/core/css/predefined_counter_styles.css
index 6a984ee6..3dccd1f 100644
--- a/third_party/blink/renderer/core/css/predefined_counter_styles.css
+++ b/third_party/blink/renderer/core/css/predefined_counter_styles.css
@@ -23,10 +23,11 @@
 }
 
 @counter-style armenian {
-  system: additive;
-  range: 1 9999;
-  additive-symbols: 9000 \554, 8000 \553, 7000 \552, 6000 \551, 5000 \550, 4000 \54F, 3000 \54E, 2000 \54D, 1000 \54C, 900 \54B, 800 \54A, 700 \549, 600 \548, 500 \547, 400 \546, 300 \545, 200 \544, 100 \543, 90 \542, 80 \541, 70 \540, 60 \53F, 50 \53E, 40 \53D, 30 \53C, 20 \53B, 10 \53A, 9 \539, 8 \538, 7 \537, 6 \536, 5 \535, 4 \534, 3 \533, 2 \532, 1 \531;
-  /* 9000 Ք, 8000 Փ, 7000 Ւ, 6000 Ց, 5000 Ր, 4000 Տ, 3000 Վ, 2000 Ս, 1000 Ռ, 900 Ջ, 800 Պ, 700 Չ, 600 Ո, 500 Շ, 400 Ն, 300 Յ, 200 Մ, 100 Ճ, 90 Ղ, 80 Ձ, 70 Հ, 60 Կ, 50 Ծ, 40 Խ, 30 Լ, 20 Ի, 10 Ժ, 9 Թ, 8 Ը, 7 Է, 6 Զ, 5 Ե, 4 Դ, 3 Գ, 2 Բ, 1 Ա */
+  system: -internal-upper-armenian;
+  /* Officially, 'armenian' is specified as an additive counter style supporting
+   * 1-9999. We extend the range to 99999999 using a special algorithm.
+   */
+  range: 1 99999999;
 }
 
 @counter-style upper-armenian {
@@ -34,10 +35,12 @@
 }
 
 @counter-style lower-armenian {
-  system: additive;
-  range: 1 9999;
-  additive-symbols: 9000 "\584", 8000 "\583", 7000 "\582", 6000 "\581", 5000 "\580", 4000 "\57F", 3000 "\57E", 2000 "\57D", 1000 "\57C", 900 "\57B", 800 "\57A", 700 "\579", 600 "\578", 500 "\577", 400 "\576", 300 "\575", 200 "\574", 100 "\573", 90 "\572", 80 "\571", 70 "\570", 60 "\56F", 50 "\56E", 40 "\56D", 30 "\56C", 20 "\56B", 10 "\56A", 9 "\569", 8 "\568", 7 "\567", 6 "\566", 5 "\565", 4 "\564", 3 "\563", 2 "\562", 1 "\561";
-  /* 9000 ք, 8000 փ, 7000 ւ, 6000 ց, 5000 ր, 4000 տ, 3000 վ, 2000 ս, 1000 ռ, 900 ջ, 800 պ, 700 չ, 600 ո, 500 շ, 400 ն, 300 յ, 200 մ, 100 ճ, 90 ղ, 80 ձ, 70 հ, 60 կ, 50 ծ, 40 խ, 30 լ, 20 ի, 10 ժ, 9 թ, 8 ը, 7 է, 6 զ, 5 ե, 4 դ, 3 գ, 2 բ, 1 ա */
+  system: -internal-lower-armenian;
+  /* Officially, 'lower-armenian' is specified as an additive counter style
+   * supporting 1-9999. We extend the range to 99999999 using a special
+   * algorithm.
+   */
+  range: 1 99999999;
 }
 
 @counter-style bengali {
@@ -91,12 +94,10 @@
 }
 
 @counter-style hebrew {
-  system: additive;
-  range: 1 10999;
-  additive-symbols: 10000 \5D9\5F3, 9000 \5D8\5F3, 8000 \5D7\5F3, 7000 \5D6\5F3, 6000 \5D5\5F3, 5000 \5D4\5F3, 4000 \5D3\5F3, 3000 \5D2\5F3, 2000 \5D1\5F3, 1000 \5D0\5F3, 400 \5EA, 300 \5E9, 200 \5E8, 100 \5E7, 90 \5E6, 80 \5E4, 70 \5E2, 60 \5E1, 50 \5E0, 40 \5DE, 30 \5DC, 20 \5DB, 19 \5D9\5D8, 18 \5D9\5D7, 17 \5D9\5D6, 16 \5D8\5D6, 15 \5D8\5D5, 10 \5D9, 9 \5D8, 8 \5D7, 7 \5D6, 6 \5D5, 5 \5D4, 4 \5D3, 3 \5D2, 2 \5D1, 1 \5D0;
-  /* 10000 י׳, 9000 ט׳, 8000 ח׳, 7000 ז׳, 6000 ו׳, 5000 ה׳, 4000 ד׳, 3000 ג׳, 2000 ב׳, 1000 א׳, 400 ת, 300 ש, 200 ר, 100 ק, 90 צ, 80 פ, 70 ע, 60 ס, 50 נ, 40 מ, 30 ל, 20 כ, 19 יט, 18 יח, 17 יז, 16 טז, 15 טו, 10 י, 9 ט, 8 ח, 7 ז, 6 ו, 5 ה, 4 ד, 3 ג, 2 ב, 1 א */
-  /* This system manually specifies the values for 19-15 to force the correct display of 15 and 16, which are commonly rewritten to avoid a close resemblance to the Tetragrammaton. */
-  /* Implementations MAY choose to implement this manually to a higher range; see note below. */
+  system: -internal-hebrew;
+  /* Officially, 'hebrew' is specified as an additive counter style supporting
+   * 1-10999. We extend the range to 0-999999 using a special algorithm.  */
+  range: 0 999999;
 }
 
 @counter-style kannada {
@@ -310,34 +311,32 @@
 
 /* https://drafts.csswg.org/css-counter-styles-3/#limited-korean */
 
+/* Note: While the officially specified range is -9999 to 9999 for these counter
+ * styles, implementations are allowed to support a larger range for
+ * investigative purposes. Therefore, we support the full int range. */
+
 @counter-style korean-hangul-formal {
-  system: additive;
-  range: -9999 9999;
-  additive-symbols: 9000 \AD6C\CC9C, 8000 \D314\CC9C, 7000 \CE60\CC9C, 6000 \C721\CC9C, 5000 \C624\CC9C, 4000 \C0AC\CC9C, 3000 \C0BC\CC9C, 2000 \C774\CC9C, 1000 \C77C\CC9C, 900 \AD6C\BC31, 800 \D314\BC31, 700 \CE60\BC31, 600 \C721\BC31, 500 \C624\BC31, 400 \C0AC\BC31, 300 \C0BC\BC31, 200 \C774\BC31, 100 \C77C\BC31, 90 \AD6C\C2ED, 80 \D314\C2ED, 70 \CE60\C2ED, 60 \C721\C2ED, 50 \C624\C2ED, 40 \C0AC\C2ED, 30 \C0BC\C2ED, 20 \C774\C2ED, 10 \C77C\C2ED, 9 \AD6C, 8 \D314, 7 \CE60, 6 \C721, 5 \C624, 4 \C0AC, 3 \C0BC, 2 \C774, 1 \C77C, 0 \C601;
-  /* 9000 구천, 8000 팔천, 7000 칠천, 6000 육천, 5000 오천, 4000 사천, 3000 삼천, 2000 이천, 1000 일천, 900 구백, 800 팔백, 700 칠백, 600 육백, 500 오백, 400 사백, 300 삼백, 200 이백, 100 일백, 90 구십, 80 팔십, 70 칠십, 60 육십, 50 오십, 40 사십, 30 삼십, 20 이십, 10 일십, 9 구, 8 팔, 7 칠, 6 육, 5 오, 4 사, 3 삼, 2 이, 1 일, 0 영 */
+  system: -internal-korean-hangul-formal;
   suffix: ', ';
   negative: "\B9C8\C774\B108\C2A4  ";
   /* 마이너스 (followed by a space) */
+  fallback: cjk-decimal;
 }
 
 @counter-style korean-hanja-informal {
-  system: additive;
-  range: -9999 9999;
-  additive-symbols: 9000 \4E5D\5343, 8000 \516B\5343, 7000 \4E03\5343, 6000 \516D\5343, 5000 \4E94\5343, 4000 \56DB\5343, 3000 \4E09\5343, 2000 \4E8C\5343, 1000 \5343, 900 \4E5D\767E, 800 \516B\767E, 700 \4E03\767E, 600 \516D\767E, 500 \4E94\767E, 400 \56DB\767E, 300 \4E09\767E, 200 \4E8C\767E, 100 \767E, 90 \4E5D\5341, 80 \516B\5341, 70 \4E03\5341, 60 \516D\5341, 50 \4E94\5341, 40 \56DB\5341, 30 \4E09\5341, 20 \4E8C\5341, 10 \5341, 9 \4E5D, 8 \516B, 7 \4E03, 6 \516D, 5 \4E94, 4 \56DB, 3 \4E09, 2 \4E8C, 1 \4E00, 0 \96F6;
-  /* 9000 九千, 8000 八千, 7000 七千, 6000 六千, 5000 五千, 4000 四千, 3000 三千, 2000 二千, 1000 千, 900 九百, 800 八百, 700 七百, 600 六百, 500 五百, 400 四百, 300 三百, 200 二百, 100 百, 90 九十, 80 八十, 70 七十, 60 六十, 50 五十, 40 四十, 30 三十, 20 二十, 10 十, 9 九, 8 八, 7 七, 6 六, 5 五, 4 四, 3 三, 2 二, 1 一, 0 零 */
+  system: -internal-korean-hanja-informal;
   suffix: ', ';
   negative: "\B9C8\C774\B108\C2A4  ";
   /* 마이너스 (followed by a space) */
+  fallback: cjk-decimal;
 }
 
 @counter-style korean-hanja-formal {
-  system: additive;
-  range: -9999 9999;
-  additive-symbols: 9000 \4E5D\4EDF, 8000 \516B\4EDF, 7000 \4E03\4EDF, 6000 \516D\4EDF, 5000 \4E94\4EDF, 4000 \56DB\4EDF, 3000 \53C3\4EDF, 2000 \8CB3\4EDF, 1000 \58F9\4EDF, 900 \4E5D\767E, 800 \516B\767E, 700 \4E03\767E, 600 \516D\767E, 500 \4E94\767E, 400 \56DB\767E, 300 \53C3\767E, 200 \8CB3\767E, 100 \58F9\767E, 90 \4E5D\62FE, 80 \516B\62FE, 70 \4E03\62FE, 60 \516D\62FE, 50 \4E94\62FE, 40 \56DB\62FE, 30 \53C3\62FE, 20 \8CB3\62FE, 10 \58F9\62FE, 9 \4E5D, 8 \516B, 7 \4E03, 6 \516D, 5 \4E94, 4 \56DB, 3 \53C3, 2 \8CB3, 1 \58F9, 0 \96F6;
-  /* 9000 九仟, 8000 八仟, 7000 七仟, 6000 六仟, 5000 五仟, 4000 四仟, 3000 參仟, 2000 貳仟, 1000 壹仟, 900 九百, 800 八百, 700 七百, 600 六百, 500 五百, 400 四百, 300 參百, 200 貳百, 100 壹百, 90 九拾, 80 八拾, 70 七拾, 60 六拾, 50 五拾, 40 四拾, 30 參拾, 20 貳拾, 10 壹拾, 9 九, 8 八, 7 七, 6 六, 5 五, 4 四, 3 參, 2 貳, 1 壹, 0 零 */
+  system: -internal-korean-hanja-formal;
   suffix: ', ';
   negative: "\B9C8\C774\B108\C2A4  ";
   /* 마이너스 (followed by a space) */
+  fallback: cjk-decimal;
 }
 
 /* https://drafts.csswg.org/css-counter-styles-3/#limited-chinese */
diff --git a/third_party/blink/renderer/core/dom/flat_tree_node_data.h b/third_party/blink/renderer/core/dom/flat_tree_node_data.h
index 46bc1e73..9f69a4b 100644
--- a/third_party/blink/renderer/core/dom/flat_tree_node_data.h
+++ b/third_party/blink/renderer/core/dom/flat_tree_node_data.h
@@ -49,6 +49,7 @@
   friend class FlatTreeTraversal;
   friend class HTMLSlotElement;
   friend HTMLSlotElement* Node::AssignedSlot() const;
+  friend HTMLSlotElement* Node::AssignedSlotWithoutRecalc() const;
   friend void Node::ClearFlatTreeNodeDataIfHostChanged(const ContainerNode&);
   friend Element* Node::FlatTreeParentForChildDirty() const;
 
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index a89396ae..2921689 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -3031,13 +3031,15 @@
   RareData()->DecrementConnectedSubframeCount();
 }
 
-HTMLSlotElement* Node::AssignedSlot() const {
+ShadowRoot* Node::GetSlotAssignmentRoot() const {
   DCHECK(!IsPseudoElement());
   ShadowRoot* root = ShadowRootOfParent();
-  if (!root)
-    return nullptr;
+  return (root && root->HasSlotAssignment()) ? root : nullptr;
+}
 
-  if (!root->HasSlotAssignment())
+HTMLSlotElement* Node::AssignedSlot() const {
+  ShadowRoot* root = GetSlotAssignmentRoot();
+  if (!root)
     return nullptr;
 
   // TODO(hayato): Node::AssignedSlot() shouldn't be called while
@@ -3068,6 +3070,18 @@
   return nullptr;
 }
 
+// Used when assignment recalc is forbidden, i.e., DetachLayoutTree().
+// Returned assignedSlot is not guaranteed up to date.
+HTMLSlotElement* Node::AssignedSlotWithoutRecalc() const {
+  if (!GetSlotAssignmentRoot())
+    return nullptr;
+
+  if (FlatTreeNodeData* data = GetFlatTreeNodeData())
+    return data->AssignedSlot();
+
+  return nullptr;
+}
+
 HTMLSlotElement* Node::assignedSlotForBinding() {
   // assignedSlot doesn't need to recalc slot assignment
   if (ShadowRoot* root = ShadowRootOfParent()) {
diff --git a/third_party/blink/renderer/core/dom/node.h b/third_party/blink/renderer/core/dom/node.h
index 1d461454..1eb9972 100644
--- a/third_party/blink/renderer/core/dom/node.h
+++ b/third_party/blink/renderer/core/dom/node.h
@@ -859,6 +859,7 @@
   StaticNodeList* getDestinationInsertionPoints();
   HTMLSlotElement* AssignedSlot() const;
   HTMLSlotElement* assignedSlotForBinding();
+  HTMLSlotElement* AssignedSlotWithoutRecalc() const;
 
   bool IsFinishedParsingChildren() const {
     return GetFlag(kIsFinishedParsingChildrenFlag);
@@ -1098,6 +1099,7 @@
     DCHECK(!HasRareData());
     return reinterpret_cast<NodeRenderingData*>(data_.Get());
   }
+  ShadowRoot* GetSlotAssignmentRoot() const;
 
   uint32_t node_flags_;
   Member<Node> parent_or_shadow_host_node_;
diff --git a/third_party/blink/renderer/core/dom/shadow_root.cc b/third_party/blink/renderer/core/dom/shadow_root.cc
index 9ed5b24..fad64af308 100644
--- a/third_party/blink/renderer/core/dom/shadow_root.cc
+++ b/third_party/blink/renderer/core/dom/shadow_root.cc
@@ -134,6 +134,20 @@
   RebuildChildrenLayoutTrees(whitespace_attacher);
 }
 
+void ShadowRoot::DetachLayoutTree(bool performing_reattach) {
+  ContainerNode::DetachLayoutTree(performing_reattach);
+
+  // Shadow host may contain unassigned light dom children that need detaching.
+  // Assigned nodes are detached by the slot element.
+  for (Node& child : NodeTraversal::ChildrenOf(host())) {
+    if (!child.IsSlotable() || child.AssignedSlotWithoutRecalc())
+      continue;
+
+    if (child.GetDocument() == GetDocument())
+      child.DetachLayoutTree(performing_reattach);
+  }
+}
+
 Node::InsertionNotificationRequest ShadowRoot::InsertedInto(
     ContainerNode& insertion_point) {
   DocumentFragment::InsertedInto(insertion_point);
diff --git a/third_party/blink/renderer/core/dom/shadow_root.h b/third_party/blink/renderer/core/dom/shadow_root.h
index c47ce8a5..20584ad6 100644
--- a/third_party/blink/renderer/core/dom/shadow_root.h
+++ b/third_party/blink/renderer/core/dom/shadow_root.h
@@ -98,6 +98,7 @@
   unsigned ChildShadowRootCount() const { return child_shadow_root_count_; }
 
   void RebuildLayoutTree(WhitespaceAttacher&);
+  void DetachLayoutTree(bool performing_reattach) override;
 
   void RegisterScopedHTMLStyleChild();
   void UnregisterScopedHTMLStyleChild();
diff --git a/third_party/blink/renderer/core/frame/DEPS b/third_party/blink/renderer/core/frame/DEPS
index 0651137..c431ea6 100644
--- a/third_party/blink/renderer/core/frame/DEPS
+++ b/third_party/blink/renderer/core/frame/DEPS
@@ -33,6 +33,7 @@
     "+components/paint_preview/common/paint_preview_tracker.h",
     "+printing/buildflags/buildflags.h",
     "+printing/metafile_skia.h",
+    "+ui/gfx/transform_util.h",
   ],
   "visual_viewport\.cc": [
     "+cc/layers/solid_color_scrollbar_layer.h",
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 5a7b5b5e..8c250d1 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame_view.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/core/frame/remote_frame_view.h"
 
-#include "cc/base/math_util.h"
 #include "components/paint_preview/common/paint_preview_tracker.h"
 #include "printing/buildflags/buildflags.h"
 #include "third_party/blink/public/mojom/frame/frame_owner_element_type.mojom-blink.h"
@@ -23,6 +22,7 @@
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 #include "third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h"
 #include "third_party/blink/renderer/platform/widget/frame_widget.h"
+#include "ui/gfx/transform_util.h"
 
 #if BUILDFLAG(ENABLE_PRINTING)
 // nogncheck because dependency on //printing is conditional upon
@@ -201,12 +201,11 @@
       local_root_transform_state.AccumulatedTransform());
   if (local_root_transform.HasPerspective()) {
     frame_to_local_root_scale_factor =
-        cc::MathUtil::ComputeApproximateMaxScale(local_root_transform);
+        gfx::ComputeApproximateMaxScale(local_root_transform);
   } else {
     gfx::Vector2dF scale_components =
-        cc::MathUtil::ComputeTransform2dScaleComponents(
-            local_root_transform,
-            /*fallback_scale=*/1.0f);
+        gfx::ComputeTransform2dScaleComponents(local_root_transform,
+                                               /*fallback_scale=*/1.0f);
     frame_to_local_root_scale_factor =
         std::max(scale_components.x(), scale_components.y());
   }
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 5f487f2b2..4e666ac 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -3130,6 +3130,11 @@
       layout_object_.SetShouldSkipNextLayoutShiftTracking(b);
     }
 
+    void SetShouldAssumePaintOffsetTranslationForLayoutShiftTracking(bool b) {
+      layout_object_
+          .SetShouldAssumePaintOffsetTranslationForLayoutShiftTracking(b);
+    }
+
     FragmentData& FirstFragment() { return layout_object_.fragment_; }
 
     void EnsureId() { layout_object_.fragment_.EnsureId(); }
@@ -3356,6 +3361,14 @@
     bitfields_.SetShouldSkipNextLayoutShiftTracking(b);
   }
 
+  bool ShouldAssumePaintOffsetTranslationForLayoutShiftTracking() const {
+    return bitfields_
+        .ShouldAssumePaintOffsetTranslationForLayoutShiftTracking();
+  }
+  void SetShouldAssumePaintOffsetTranslationForLayoutShiftTracking(bool b) {
+    bitfields_.SetShouldAssumePaintOffsetTranslationForLayoutShiftTracking(b);
+  }
+
  protected:
   // Identifiers for each of LayoutObject subclasses.
   // The identifier name for blink::LayoutFoo should be kLayoutObjectFoo.
@@ -3788,6 +3801,8 @@
           transform_affects_vector_effect_(false),
           is_layout_ng_object_for_canvas_formatted_text(false),
           should_skip_next_layout_shift_tracking_(true),
+          should_assume_paint_offset_translation_for_layout_shift_tracking_(
+              false),
           positioned_state_(kIsStaticallyPositioned),
           selection_state_(static_cast<unsigned>(SelectionState::kNone)),
           subtree_paint_property_update_reasons_(
@@ -4109,6 +4124,15 @@
     ADD_BOOLEAN_BITFIELD(should_skip_next_layout_shift_tracking_,
                          ShouldSkipNextLayoutShiftTracking);
 
+    // Whether, on the next time PaintPropertyTreeBuilder builds for this
+    // object, it should be assumed it had the same paint offset transform last
+    // time as it has this time. This is used when layout reattach loses the
+    // information from the previous frame; this bit stores that information
+    // to inform the next frame for layout shift tracking.
+    ADD_BOOLEAN_BITFIELD(
+        should_assume_paint_offset_translation_for_layout_shift_tracking_,
+        ShouldAssumePaintOffsetTranslationForLayoutShiftTracking);
+
    private:
     // This is the cached 'position' value of this object
     // (see ComputedStyle::position).
diff --git a/third_party/blink/renderer/core/layout/layout_shift_tracker.cc b/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
index 8607a90..cc8fad30 100644
--- a/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
+++ b/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
@@ -706,8 +706,11 @@
   PhysicalRect visual_overflow_rect = box.PreviousPhysicalVisualOverflowRect();
   if (visual_overflow_rect.IsEmpty() && box.PreviousSize().IsEmpty())
     return;
+  bool has_paint_offset_transform = false;
+  if (auto* properties = fragment.PaintProperties())
+    has_paint_offset_transform = properties->PaintOffsetTranslation();
   map.Set(&node, Geometry{fragment.PaintOffset(), box.PreviousSize(),
-                          visual_overflow_rect});
+                          visual_overflow_rect, has_paint_offset_transform});
 }
 
 void ReattachHookScope::NotifyAttach(const Node& node) {
@@ -729,6 +732,8 @@
           iter->value.paint_offset, iter->value.size,
           iter->value.visual_overflow_rect);
   layout_object->SetShouldSkipNextLayoutShiftTracking(false);
+  layout_object->SetShouldAssumePaintOffsetTranslationForLayoutShiftTracking(
+      iter->value.has_paint_offset_translation);
 }
 
 }  // namespace blink
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 5b0c973..d45ba7a 100644
--- a/third_party/blink/renderer/core/layout/layout_shift_tracker.h
+++ b/third_party/blink/renderer/core/layout/layout_shift_tracker.h
@@ -99,6 +99,7 @@
       PhysicalOffset paint_offset;
       LayoutSize size;
       PhysicalRect visual_overflow_rect;
+      bool has_paint_offset_translation;
     };
     HeapHashMap<Member<const Node>, Geometry> geometries_before_detach_;
   };
diff --git a/third_party/blink/renderer/core/layout/list_marker_text.cc b/third_party/blink/renderer/core/layout/list_marker_text.cc
index 3a8e58f8..0fff3c3 100644
--- a/third_party/blink/renderer/core/layout/list_marker_text.cc
+++ b/third_party/blink/renderer/core/layout/list_marker_text.cc
@@ -26,6 +26,7 @@
 #include "third_party/blink/renderer/core/layout/list_marker_text.h"
 
 #include "third_party/blink/renderer/core/layout/text_run_constructor.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
@@ -178,18 +179,31 @@
   DCHECK_GE(number, 0);
   DCHECK_LE(number, 999999);
 
+  Vector<UChar> letters;
+
   if (number == 0) {
     static const UChar kHebrewZero[3] = {0x05E1, 0x05E4, 0x05D0};
-    return String(kHebrewZero, 3);
+    letters.Append(kHebrewZero, 3);
+  } else {
+    if (number > 999) {
+      ToHebrewUnder1000(number / 1000, letters);
+      if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled())
+        letters.push_front(kHebrewPunctuationGereshCharacter);
+      else
+        letters.push_front('\'');
+      number = number % 1000;
+    }
+    ToHebrewUnder1000(number, letters);
   }
 
-  Vector<UChar> letters;
-  if (number > 999) {
-    ToHebrewUnder1000(number / 1000, letters);
-    letters.push_front('\'');
-    number = number % 1000;
+  if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+    // Since Hebrew is RTL, legacy implementation generates letters in the
+    // reversed ordering, which is actually wrong because characters in a String
+    // should always be in the logical ordering. We re-reverse it so that the
+    // output ordering is correct.
+    std::reverse(letters.begin(), letters.end());
   }
-  ToHebrewUnder1000(number, letters);
+
   return String(letters);
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
index ed48bd1a..f07d5eb7 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -242,10 +242,16 @@
   if (cached_set_indices.has_value())
     return cached_set_indices.value();
 
+  // We only calculate the indexes if:
+  // 1. The item is in flow (it is a grid item) or
+  // 2. The item is out of flow, but the line was not defined as 'auto' and
+  // the line is within the bounds of the grid, since an out of flow item
+  // cannot create grid lines.
   wtf_size_t start_line, end_line;
   if (item_type == ItemType::kInGridFlow) {
     start_line = StartLine(track_direction);
     end_line = EndLine(track_direction);
+
     DCHECK_NE(start_line, kNotFound);
     DCHECK_NE(end_line, kNotFound);
   } else {
@@ -254,32 +260,36 @@
         track_collection, node.Style(), &start_line, &end_line);
   }
 
-  // We only calculate the indexes if:
-  // 1. The item is in flow (it is a grid item) or
-  // 2. The item is out of flow, but the line was not defined as 'auto' and
-  // the line is within the bounds of the grid, since an out of flow item
-  // cannot create grid lines.
-  // TODO(ansollan): The start line of an out of flow item can be the last
-  // line of the grid. If that is the case, |set_indices.begin| has to be
-  // computed as |set_indices.end|. Similarly, if an end line is the first line
-  // of the grid, |set_indices.end| has to be computed as |set_indices.begin|.
   ItemSetIndices set_indices;
-  set_indices.begin = kNotFound;
-  set_indices.end = kNotFound;
-
   if (start_line != kNotFound) {
-    wtf_size_t first_spanned_range =
-        track_collection.RangeIndexFromTrackNumber(start_line);
-    set_indices.begin =
-        track_collection.RangeStartingSetIndex(first_spanned_range);
+    DCHECK(track_collection.IsGridLineWithinImplicitGrid(start_line));
+    // If a start line of an out of flow item is the last line of the grid, then
+    // the |set_indices.begin| is the number of sets in the collection.
+    if (track_collection.EndLineOfImplicitGrid() == start_line) {
+      DCHECK_EQ(item_type, ItemType::kOutOfFlow);
+      set_indices.begin = track_collection.SetCount();
+    } else {
+      wtf_size_t first_spanned_range =
+          track_collection.RangeIndexFromTrackNumber(start_line);
+      set_indices.begin =
+          track_collection.RangeStartingSetIndex(first_spanned_range);
+    }
   }
 
   if (end_line != kNotFound) {
-    wtf_size_t last_spanned_range =
-        track_collection.RangeIndexFromTrackNumber(end_line - 1);
-    set_indices.end =
-        track_collection.RangeStartingSetIndex(last_spanned_range) +
-        track_collection.RangeSetCount(last_spanned_range);
+    DCHECK(track_collection.IsGridLineWithinImplicitGrid(end_line));
+    // If an end line of an out of flow item is the first line of the grid, then
+    // the |set_indices.end| is 0.
+    if (!end_line) {
+      DCHECK_EQ(item_type, ItemType::kOutOfFlow);
+      set_indices.end = 0;
+    } else {
+      wtf_size_t last_spanned_range =
+          track_collection.RangeIndexFromTrackNumber(end_line - 1);
+      set_indices.end =
+          track_collection.RangeStartingSetIndex(last_spanned_range) +
+          track_collection.RangeSetCount(last_spanned_range);
+    }
   }
 
 #if DCHECK_IS_ON()
@@ -287,7 +297,7 @@
     DCHECK_LE(set_indices.end, track_collection.SetCount());
     DCHECK_LT(set_indices.begin, set_indices.end);
   } else if (set_indices.begin != kNotFound) {
-    DCHECK_LT(set_indices.begin, track_collection.SetCount());
+    DCHECK_LE(set_indices.begin, track_collection.SetCount());
   } else if (set_indices.end != kNotFound) {
     DCHECK_LE(set_indices.end, track_collection.SetCount());
   }
@@ -2057,14 +2067,17 @@
     end_offset = set_offsets[end_index];
     *size = end_offset - *start_offset - gutter_size;
   }
+
+#if DCHECK_IS_ON()
   if (start_index != kNotFound && end_index != kNotFound) {
     DCHECK_LT(start_index, end_index);
     DCHECK_LT(end_index, set_offsets.size());
     DCHECK_GE(*size, 0);
   } else {
     // Only out of flow items can have an undefined ('auto') value for the start
-    // and/or end indices.
+    // and/or end |set_indices|.
     DCHECK_EQ(item.item_type, ItemType::kOutOfFlow);
   }
+#endif
 }
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
index a2ae223..5db08ed 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
@@ -38,8 +38,8 @@
   };
 
   struct ItemSetIndices {
-    wtf_size_t begin;
-    wtf_size_t end;
+    wtf_size_t begin = kNotFound;
+    wtf_size_t end = kNotFound;
   };
 
   struct GridItemData {
@@ -68,6 +68,8 @@
     // For this item and track direction, computes and stores the pair of
     // indices "begin" and "end" such that the item spans every set from the
     // respective collection's |sets_| with an index in the range [begin, end).
+    // |grid_placement| is used to resolve the grid lines of out of flow items
+    // and it has a default nullptr value for grid items.
     ItemSetIndices SetIndices(
         const NGGridLayoutAlgorithmTrackCollection& track_collection,
         NGGridPlacement* grid_placement = nullptr);
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc
index 0e1a775..979994d 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc
@@ -1714,6 +1714,23 @@
         grid-column-start: 5;
         grid-column-end: 6;
       }
+
+      #fifthItem {
+        grid-column-start: auto;
+        grid-column-end: 1;
+        grid-row-start: 2;
+        grid-row-end: 3;
+        background-color: hotpink;
+      }
+
+      #sixthItem {
+        grid-column-start: 4;
+        grid-column-end: auto;
+        grid-row-start: 2;
+        grid-row-end: 3;
+        background-color: purple;
+      }
+
     </style>
     <div id="wrapper">
       <div id="grid">
@@ -1721,6 +1738,8 @@
         <div class="absolute" id="secondItem"></div>
         <div class="absolute" id="thirdItem"></div>
         <div class="absolute" id="fourthItem"></div>
+        <div class="absolute" id="fifthItem"></div>
+        <div class="absolute" id="sixthItem"></div>
         <div class="item"></div>
         <div class="item"></div>
         <div class="item"></div>
@@ -1751,6 +1770,8 @@
       offset:5,235 size:50x50
       offset:205,5 size:50x50
       offset:5,5 size:50x50
+      offset:5,110 size:50x50
+      offset:310,110 size:50x50
 )DUMP";
   EXPECT_EQ(expectation, dump);
 }
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.cc
index deec384..b109667c0 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.cc
@@ -328,6 +328,24 @@
   return packing_behavior_ == PackingBehavior::kSparse;
 }
 
+namespace {
+
+bool IsStartLineAuto(const GridTrackSizingDirection track_direction,
+                     const ComputedStyle& out_of_flow_item_style) {
+  return (track_direction == kForColumns)
+             ? out_of_flow_item_style.GridColumnStart().IsAuto()
+             : out_of_flow_item_style.GridRowStart().IsAuto();
+}
+
+bool IsEndLineAuto(const GridTrackSizingDirection track_direction,
+                   const ComputedStyle& out_of_flow_item_style) {
+  return (track_direction == kForColumns)
+             ? out_of_flow_item_style.GridColumnEnd().IsAuto()
+             : out_of_flow_item_style.GridRowEnd().IsAuto();
+}
+
+}  // namespace
+
 void NGGridPlacement::ResolveOutOfFlowItemGridLines(
     const NGGridLayoutAlgorithmTrackCollection& track_collection,
     const ComputedStyle& out_of_flow_item_style,
@@ -347,29 +365,26 @@
     return;
   }
 
-  if (span.UntranslatedStartLine() > -1) {
-    // TODO(ansollan): Handle out of flow positioned items with negative
-    // indexes.
-    span.Translate(StartOffset(track_direction));
+  // Handle the case where the start line is 'auto' and the end line is the
+  // first line of the grid.
+  // TODO(ansollan): Handle out of flow positioned items with negative indexes.
+  if (span.UntranslatedStartLine() < 0 &&
+      IsStartLineAuto(track_direction, out_of_flow_item_style)) {
+    *start_line = kNotFound;
+    *end_line = 0;
+    return;
   }
 
+  span.Translate(StartOffset(track_direction));
   *start_line = span.StartLine();
   *end_line = span.EndLine();
 
-  bool is_start_line_auto =
-      (track_direction == kForColumns)
-          ? out_of_flow_item_style.GridColumnStart().IsAuto()
-          : out_of_flow_item_style.GridRowStart().IsAuto();
-  if (is_start_line_auto ||
+  if (IsStartLineAuto(track_direction, out_of_flow_item_style) ||
       !track_collection.IsGridLineWithinImplicitGrid(*start_line)) {
     *start_line = kNotFound;
   }
-
-  bool is_end_line_auto = (track_direction == kForColumns)
-                              ? out_of_flow_item_style.GridColumnEnd().IsAuto()
-                              : out_of_flow_item_style.GridRowEnd().IsAuto();
-  if (is_end_line_auto ||
-      !track_collection.IsGridLineWithinImplicitGrid(*end_line - 1)) {
+  if (IsEndLineAuto(track_direction, out_of_flow_item_style) ||
+      !track_collection.IsGridLineWithinImplicitGrid(*end_line)) {
     *end_line = kNotFound;
   }
 }
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc
index 9eb42c9..8955234 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc
@@ -606,7 +606,7 @@
 bool NGGridLayoutAlgorithmTrackCollection::IsGridLineWithinImplicitGrid(
     wtf_size_t grid_line) const {
   DCHECK_NE(grid_line, kInvalidRangeIndex);
-  return grid_line < EndLineOfImplicitGrid();
+  return grid_line <= EndLineOfImplicitGrid();
 }
 
 NGGridSet& NGGridLayoutAlgorithmTrackCollection::SetAt(wtf_size_t set_index) {
diff --git a/third_party/blink/renderer/core/paint/paint_invalidator.cc b/third_party/blink/renderer/core/paint/paint_invalidator.cc
index 6f18d24d..931646c 100644
--- a/third_party/blink/renderer/core/paint/paint_invalidator.cc
+++ b/third_party/blink/renderer/core/paint/paint_invalidator.cc
@@ -321,7 +321,9 @@
         PaintInvalidatorContext::kSubtreeInvalidationChecking;
   }
 
-  if (UNLIKELY(object.ContainsInlineWithOutlineAndContinuation())) {
+  if (UNLIKELY(object.ContainsInlineWithOutlineAndContinuation()) &&
+      // Need this only if the subtree needs to check geometry change.
+      PrePaintTreeWalk::ObjectRequiresTreeBuilderContext(object)) {
     // Force subtree invalidation checking to ensure invalidation of focus rings
     // when continuation's geometry changes.
     context.subtree_flags |=
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 3e6632d..91ffa756 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -571,8 +571,10 @@
       context_.fixed_position.transform = properties_->PaintOffsetTranslation();
     }
 
-    context_.current.additional_offset_to_layout_shift_root_delta +=
-        PhysicalOffset(*paint_offset_translation);
+    if (!object_.ShouldAssumePaintOffsetTranslationForLayoutShiftTracking()) {
+      context_.current.additional_offset_to_layout_shift_root_delta +=
+          PhysicalOffset(*paint_offset_translation);
+    }
   } else {
     OnClear(properties_->ClearPaintOffsetTranslation());
   }
@@ -3675,6 +3677,9 @@
     }
   }
 
+  object_.GetMutableForPainting()
+      .SetShouldAssumePaintOffsetTranslationForLayoutShiftTracking(false);
+
   return property_changed;
 }
 
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
index f3031b63..d6de62c 100644
--- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
+++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -455,7 +455,7 @@
 
   return frame_view.GetLayoutView() &&
          (ObjectRequiresTreeBuilderContext(*frame_view.GetLayoutView()) ||
-          ContextRequiresTreeBuilderContext(context));
+          ContextRequiresChildTreeBuilderContext(context));
 }
 
 bool PrePaintTreeWalk::ObjectRequiresPrePaint(const LayoutObject& object) {
@@ -467,7 +467,7 @@
   ;
 }
 
-bool PrePaintTreeWalk::ContextRequiresPrePaint(
+bool PrePaintTreeWalk::ContextRequiresChildPrePaint(
     const PrePaintTreeWalkContext& context) {
   return context.paint_invalidator_context.NeedsSubtreeWalk() ||
          context.effective_allowed_touch_action_changed ||
@@ -483,12 +483,16 @@
            object.DescendantShouldCheckGeometryForPaintInvalidation()));
 }
 
-bool PrePaintTreeWalk::ContextRequiresTreeBuilderContext(
+bool PrePaintTreeWalk::ContextRequiresChildTreeBuilderContext(
     const PrePaintTreeWalkContext& context) {
-  return context.tree_builder_context &&
-         (context.tree_builder_context->force_subtree_update_reasons ||
-          // PaintInvalidator forced subtree walk implies geometry update.
-          context.paint_invalidator_context.NeedsSubtreeWalk());
+  if (!context.NeedsTreeBuilderContext()) {
+    DCHECK(!context.tree_builder_context->force_subtree_update_reasons);
+    DCHECK(!context.paint_invalidator_context.NeedsSubtreeWalk());
+    return false;
+  }
+  return context.tree_builder_context->force_subtree_update_reasons ||
+         // PaintInvalidator forced subtree walk implies geometry update.
+         context.paint_invalidator_context.NeedsSubtreeWalk();
 }
 
 #if DCHECK_IS_ON()
@@ -497,7 +501,7 @@
     const PrePaintTreeWalkContext& parent_context) {
   if (parent_context.tree_builder_context ||
       (!ObjectRequiresTreeBuilderContext(object) &&
-       !ContextRequiresTreeBuilderContext(parent_context))) {
+       !ContextRequiresChildTreeBuilderContext(parent_context))) {
     return;
   }
 
@@ -579,11 +583,7 @@
   base::Optional<NGPrePaintInfo> pre_paint_info_storage;
   NGPrePaintInfo* pre_paint_info = nullptr;
   if (iterator) {
-    bool allow_reset = context.tree_builder_context.has_value()
-#if DCHECK_IS_ON()
-                       && context.tree_builder_context->is_actually_needed
-#endif
-        ;
+    bool allow_reset = context.NeedsTreeBuilderContext();
     pre_paint_info_storage.emplace(SetupFragmentData(*iterator, allow_reset));
     pre_paint_info = &pre_paint_info_storage.value();
   }
@@ -959,7 +959,7 @@
   };
 
   bool needs_tree_builder_context_update =
-      ContextRequiresTreeBuilderContext(parent_context()) ||
+      ContextRequiresChildTreeBuilderContext(parent_context()) ||
       ObjectRequiresTreeBuilderContext(object);
 
 #if DCHECK_IS_ON()
@@ -968,7 +968,7 @@
 
   // Early out from the tree walk if possible.
   if (!needs_tree_builder_context_update && !ObjectRequiresPrePaint(object) &&
-      !ContextRequiresPrePaint(parent_context())) {
+      !ContextRequiresChildPrePaint(parent_context())) {
     return;
   }
 
@@ -999,8 +999,9 @@
   // If we need a subtree walk due to context flags, we need to store that
   // information on the display lock, since subsequent walks might not set the
   // same bits on the context.
-  if (child_walk_blocked && (ContextRequiresTreeBuilderContext(context()) ||
-                             ContextRequiresPrePaint(context()))) {
+  if (child_walk_blocked &&
+      (ContextRequiresChildTreeBuilderContext(context()) ||
+       ContextRequiresChildPrePaint(context()))) {
     // Note that |effective_allowed_touch_action_changed| and
     // |blocking_wheel_event_handler_changed| are special in that they requires
     // us to specifically recalculate this value on each subtree element. Other
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
index 32030a1..3e4ddc8 100644
--- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
+++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
@@ -74,6 +74,15 @@
     base::Optional<PaintPropertyTreeBuilderContext> tree_builder_context;
     PaintInvalidatorContext paint_invalidator_context;
 
+    bool NeedsTreeBuilderContext() const {
+#if DCHECK_IS_ON()
+      DCHECK(tree_builder_context);
+      return tree_builder_context->is_actually_needed;
+#else
+      return tree_builder_context.has_value();
+#endif
+    }
+
     // The ancestor in the PaintLayer tree which is a scroll container. Note
     // that it is tree ancestor, not containing block or stacking ancestor.
     PaintLayer* ancestor_scroll_container_paint_layer = nullptr;
@@ -103,8 +112,9 @@
         paint_invalidation_container_for_stacked_contents = nullptr;
   };
 
-  static bool ContextRequiresPrePaint(const PrePaintTreeWalkContext&);
-  static bool ContextRequiresTreeBuilderContext(const PrePaintTreeWalkContext&);
+  static bool ContextRequiresChildPrePaint(const PrePaintTreeWalkContext&);
+  static bool ContextRequiresChildTreeBuilderContext(
+      const PrePaintTreeWalkContext&);
 
 #if DCHECK_IS_ON()
   void CheckTreeBuilderContextState(const LayoutObject&,
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc
index c03d7323f..ff9e1ed 100644
--- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc
+++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc
@@ -480,4 +480,21 @@
             foreign.FirstFragment().GetCullRect().Rect());
 }
 
+TEST_P(PrePaintTreeWalkTest, InlineOutlineWithContinuationPaintInvalidation) {
+  SetBodyInnerHTML(R"HTML(
+    <div>
+      <span style="outline: 1px solid black">
+        <span id="child-span">span</span>
+        <div>continuation</div>
+      </span>
+    </div>
+  )HTML");
+
+  // This test passes if the following doesn't crash.
+  GetDocument()
+      .getElementById("child-span")
+      ->setAttribute(html_names::kStyleAttr, "color: blue");
+  UpdateAllLifecyclePhasesForTest();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 9e3f47e4..b92727d8 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -2203,6 +2203,7 @@
     "//ui/base:features",
     "//ui/base/prediction",
     "//ui/gfx",
+    "//ui/gfx:test_support",
     "//ui/gfx/geometry",
     "//ui/gfx/geometry/mojom:test_interfaces_blink",
     "//ui/gfx/mojom:test_interfaces_blink",
diff --git a/third_party/blink/renderer/platform/animation/animation_translation_util_test.cc b/third_party/blink/renderer/platform/animation/animation_translation_util_test.cc
index d383ab0..39531f3 100644
--- a/third_party/blink/renderer/platform/animation/animation_translation_util_test.cc
+++ b/third_party/blink/renderer/platform/animation/animation_translation_util_test.cc
@@ -49,24 +49,24 @@
       50.2, 100, -4, TransformOperation::kScale3D));
   ToCompositorTransformOperations(ops, &out_ops, FloatSize());
 
-  EXPECT_EQ(3UL, out_ops.AsCcTransformOperations().size());
+  EXPECT_EQ(3UL, out_ops.AsGfxTransformOperations().size());
   const float kErr = 0.0001;
 
-  auto& op0 = out_ops.AsCcTransformOperations().at(0);
-  EXPECT_EQ(cc::TransformOperation::TRANSFORM_OPERATION_TRANSLATE, op0.type);
+  auto& op0 = out_ops.AsGfxTransformOperations().at(0);
+  EXPECT_EQ(gfx::TransformOperation::TRANSFORM_OPERATION_TRANSLATE, op0.type);
   EXPECT_NEAR(op0.translate.x, 2.0f, kErr);
   EXPECT_NEAR(op0.translate.y, 0.0f, kErr);
   EXPECT_NEAR(op0.translate.z, 0.0f, kErr);
 
-  auto& op1 = out_ops.AsCcTransformOperations().at(1);
-  EXPECT_EQ(cc::TransformOperation::TRANSFORM_OPERATION_ROTATE, op1.type);
+  auto& op1 = out_ops.AsGfxTransformOperations().at(1);
+  EXPECT_EQ(gfx::TransformOperation::TRANSFORM_OPERATION_ROTATE, op1.type);
   EXPECT_NEAR(op1.rotate.axis.x, 0.1f, kErr);
   EXPECT_NEAR(op1.rotate.axis.y, 0.2f, kErr);
   EXPECT_NEAR(op1.rotate.axis.z, 0.3f, kErr);
   EXPECT_NEAR(op1.rotate.angle, 200000.4f, 0.01f);
 
-  auto& op2 = out_ops.AsCcTransformOperations().at(2);
-  EXPECT_EQ(cc::TransformOperation::TRANSFORM_OPERATION_SCALE, op2.type);
+  auto& op2 = out_ops.AsGfxTransformOperations().at(2);
+  EXPECT_EQ(gfx::TransformOperation::TRANSFORM_OPERATION_SCALE, op2.type);
   EXPECT_NEAR(op2.scale.x, 50.2f, kErr);
   EXPECT_NEAR(op2.scale.y, 100.0f, kErr);
   EXPECT_NEAR(op2.scale.z, -4.0f, kErr);
@@ -82,10 +82,10 @@
 
   CompositorTransformOperations out_ops;
   ToCompositorTransformOperations(ops, &out_ops, FloatSize(200, 100));
-  ASSERT_EQ(out_ops.AsCcTransformOperations().size(), 1u);
+  ASSERT_EQ(out_ops.AsGfxTransformOperations().size(), 1u);
 
-  auto& op0 = out_ops.AsCcTransformOperations().at(0);
-  EXPECT_EQ(cc::TransformOperation::TRANSFORM_OPERATION_TRANSLATE, op0.type);
+  auto& op0 = out_ops.AsGfxTransformOperations().at(0);
+  EXPECT_EQ(gfx::TransformOperation::TRANSFORM_OPERATION_TRANSLATE, op0.type);
   EXPECT_EQ(op0.translate.x, 100.0f);
   EXPECT_EQ(op0.translate.y, 50.0f);
   EXPECT_EQ(op0.translate.z, 0.0f);
@@ -104,14 +104,14 @@
 
   CompositorTransformOperations out_ops;
   ToCompositorTransformOperations(ops_c, &out_ops, FloatSize(100, 100));
-  ASSERT_EQ(out_ops.AsCcTransformOperations().size(), 1u);
+  ASSERT_EQ(out_ops.AsGfxTransformOperations().size(), 1u);
 
-  auto& op0 = out_ops.AsCcTransformOperations().at(0);
-  cc::TransformOperations ops_expected;
+  auto& op0 = out_ops.AsGfxTransformOperations().at(0);
+  gfx::TransformOperations ops_expected;
   ops_expected.AppendTranslate(25, 0, 0);
-  EXPECT_EQ(cc::TransformOperation::TRANSFORM_OPERATION_MATRIX, op0.type);
-  cc::ExpectTransformationMatrixNear(op0.matrix, ops_expected.at(0).matrix,
-                                     1e-6f);
+  EXPECT_EQ(gfx::TransformOperation::TRANSFORM_OPERATION_MATRIX, op0.type);
+  gfx::ExpectTransformationMatrixNear(op0.matrix, ops_expected.at(0).matrix,
+                                      1e-6f);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.cc b/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.cc
index a3932b7..786d16e2 100644
--- a/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.cc
+++ b/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.cc
@@ -6,8 +6,8 @@
 
 #include "cc/animation/keyframed_animation_curve.h"
 #include "cc/animation/timing_function.h"
-#include "cc/animation/transform_operations.h"
 #include "third_party/blink/renderer/platform/animation/compositor_transform_operations.h"
+#include "ui/gfx/transform_operations.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.cc b/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.cc
index 1c13d89..2c5273e 100644
--- a/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.cc
+++ b/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.cc
@@ -14,7 +14,7 @@
     const TimingFunction& timing_function)
     : transform_keyframe_(
           cc::TransformKeyframe::Create(base::TimeDelta::FromSecondsD(time),
-                                        value.ReleaseCcTransformOperations(),
+                                        value.ReleaseGfxTransformOperations(),
                                         timing_function.CloneToCC())) {}
 
 CompositorTransformKeyframe::~CompositorTransformKeyframe() = default;
diff --git a/third_party/blink/renderer/platform/animation/compositor_transform_operations.cc b/third_party/blink/renderer/platform/animation/compositor_transform_operations.cc
index fdbf638..b5f4dca 100644
--- a/third_party/blink/renderer/platform/animation/compositor_transform_operations.cc
+++ b/third_party/blink/renderer/platform/animation/compositor_transform_operations.cc
@@ -4,19 +4,19 @@
 
 #include "third_party/blink/renderer/platform/animation/compositor_transform_operations.h"
 
-#include "cc/animation/transform_operation.h"
 #include "third_party/skia/include/core/SkMatrix44.h"
 #include "ui/gfx/transform.h"
+#include "ui/gfx/transform_operations.h"
 
 namespace blink {
 
-const cc::TransformOperations&
-CompositorTransformOperations::AsCcTransformOperations() const {
+const gfx::TransformOperations&
+CompositorTransformOperations::AsGfxTransformOperations() const {
   return transform_operations_;
 }
 
-cc::TransformOperations
-CompositorTransformOperations::ReleaseCcTransformOperations() {
+gfx::TransformOperations
+CompositorTransformOperations::ReleaseGfxTransformOperations() {
   return std::move(transform_operations_);
 }
 
diff --git a/third_party/blink/renderer/platform/animation/compositor_transform_operations.h b/third_party/blink/renderer/platform/animation/compositor_transform_operations.h
index 5c6daa4..3cc95a12 100644
--- a/third_party/blink/renderer/platform/animation/compositor_transform_operations.h
+++ b/third_party/blink/renderer/platform/animation/compositor_transform_operations.h
@@ -5,9 +5,9 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_TRANSFORM_OPERATIONS_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_TRANSFORM_OPERATIONS_H_
 
-#include "cc/animation/transform_operations.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "ui/gfx/transform_operations.h"
 
 class SkMatrix44;
 
@@ -17,8 +17,8 @@
   STACK_ALLOCATED();
 
  public:
-  const cc::TransformOperations& AsCcTransformOperations() const;
-  cc::TransformOperations ReleaseCcTransformOperations();
+  const gfx::TransformOperations& AsGfxTransformOperations() const;
+  gfx::TransformOperations ReleaseGfxTransformOperations();
 
   // Returns true if these operations can be blended. It will only return
   // false if we must resort to matrix interpolation, and matrix interpolation
@@ -37,7 +37,7 @@
   bool IsIdentity() const;
 
  private:
-  cc::TransformOperations transform_operations_;
+  gfx::TransformOperations transform_operations_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index f73321e..1731fdd 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -383,7 +383,7 @@
     },
     {
       name: "CompositingOptimizations",
-      status: "experimental"
+      status: "stable"
     },
     {
       name: "ComputedAccessibilityInfo",
diff --git a/third_party/blink/renderer/platform/transforms/transformation_matrix_test_helpers.h b/third_party/blink/renderer/platform/transforms/transformation_matrix_test_helpers.h
index 11503ae..a9a70c4 100644
--- a/third_party/blink/renderer/platform/transforms/transformation_matrix_test_helpers.h
+++ b/third_party/blink/renderer/platform/transforms/transformation_matrix_test_helpers.h
@@ -5,8 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_TRANSFORMS_TRANSFORMATION_MATRIX_TEST_HELPERS_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_TRANSFORMS_TRANSFORMATION_MATRIX_TEST_HELPERS_H_
 
-#include "cc/test/geometry_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/test/transform_test_util.h"
 #include "ui/gfx/transform.h"
 
 namespace blink {
@@ -18,7 +18,7 @@
 #define EXPECT_TRANSFORMATION_MATRIX(expected, actual) \
   do {                                                 \
     SCOPED_TRACE("");                                  \
-    cc::ExpectTransformationMatrixNear(                \
+    gfx::ExpectTransformationMatrixNear(               \
         TransformationMatrix::ToTransform(expected),   \
         TransformationMatrix::ToTransform(actual),     \
         kFloatingPointErrorTolerance);                 \
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 59ee4e9..c1ed214 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -275,6 +275,8 @@
 
             # Chromium geometry operations.
             'cc::MathUtil',
+            'gfx::ComputeApproximateMaxScale',
+            'gfx::ComputeTransform2dScaleComponents',
             'gfx::ToFlooredPoint',
 
             # Range type.
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 9809809d..0f3831d 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -753,17 +753,8 @@
 crbug.com/1066577 external/wpt/css/css-lists/li-value-reversed-004.html [ Failure ]
 
 # [css-counter-styles-3]
-# Implemented as custom counter styles, but not exactly match existing behavior:
-# - Complex CJK styles should fallback to 'cjk-decimal', not 'decimal'
-# - 'armenian', 'upper-armenian', 'hebrew', and CJK styles should support
-#   larger value ranges, matching the old behavior
-# - 'hebrew' representation of 0
 crbug.com/687225 fast/css/content-counter-large-negative-cjk.html [ Failure ]
-crbug.com/687225 fast/lists/css3-counter-styles-054.html [ Failure ]
-crbug.com/687225 fast/lists/css3-counter-styles-059.html [ Failure ]
-crbug.com/687225 fast/lists/css3-counter-styles-064.html [ Failure ]
-crbug.com/687225 fast/lists/w3-css3-list-styles-fallback-style.html [ Failure ]
-crbug.com/687225 fast/lists/w3-list-styles.html [ Failure ]
+# Missing ref files for these tests
 crbug.com/687225 external/wpt/css/css-counter-styles/* [ Skip ]
 
 # [css-overflow]
@@ -1248,13 +1239,10 @@
 crbug.com/1068610 external/wpt/css/css-color/predefined-014.html [ Failure ]
 crbug.com/1068610 external/wpt/css/css-color/predefined-002.html [ Failure ]
 crbug.com/1068610 external/wpt/css/css-color/predefined-012.html [ Failure ]
-crbug.com/1068610 external/wpt/css/css-color/predefined-017.html [ Failure ]
 crbug.com/1068610 external/wpt/css/css-color/predefined-016.html [ Failure ]
 crbug.com/1068610 external/wpt/css/css-color/predefined-006.html [ Failure ]
-crbug.com/1068610 external/wpt/css/css-color/predefined-004.html [ Failure ]
 crbug.com/1068610 external/wpt/css/css-color/predefined-009.html [ Failure ]
 crbug.com/1068610 external/wpt/css/css-color/predefined-010.html [ Failure ]
-crbug.com/1068610 external/wpt/css/css-color/predefined-003.html [ Failure ]
 
 # @supports
 crbug.com/1158554 external/wpt/css/css-conditional/css-supports-040.xht [ Failure ]
@@ -2436,6 +2424,39 @@
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-206.xht [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/rec2020-004.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/a98rgb-004.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/a98rgb-004.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/prophoto-rgb-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/rec2020-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/prophoto-rgb-001.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/lch-008.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/rec2020-005.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/prophoto-rgb-002.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/lab-008.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/a98rgb-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/prophoto-rgb-005.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/rec2020-001.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/rec2020-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/a98rgb-003.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/a98rgb-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/lab-008.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/rec2020-005.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/prophoto-rgb-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/rec2020-002.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/prophoto-rgb-004.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/lch-008.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/prophoto-rgb-004.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/a98rgb-001.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/rec2020-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/a98rgb-002.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/prophoto-rgb-002.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-color/rec2020-004.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/rec2020-002.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/prophoto-rgb-005.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/prophoto-rgb-001.html [ Failure ]
+crbug.com/626703 virtual/system-color-compute/external/wpt/css/css-color/a98rgb-002.html [ Failure ]
+crbug.com/626703 [ Mac10.15 ] external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-screenx-screeny.html [ Timeout ]
 crbug.com/626703 [ Linux ] virtual/threaded/external/wpt/css/css-animations/nested-scale-animations.html [ Failure ]
 crbug.com/626703 external/wpt/shadow-dom/focus/focus-pseudo-on-shadow-host-1.html [ Failure ]
 crbug.com/626703 external/wpt/shadow-dom/focus/focus-pseudo-on-shadow-host-2.html [ Failure ]
@@ -3312,7 +3333,6 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-gaps-rtl-001.html [ Crash Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-implicit-grid-001.html [ Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-padding-001.html [ Crash ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-unknown-named-grid-line-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-within-grid-implicit-track-001.html [ Crash Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-003.html [ Failure ]
@@ -3363,11 +3383,6 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-align-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-align-cycles-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-justify-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-012.html [ Crash Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-013.html [ Crash Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-014.html [ Crash Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-015.html [ Crash Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-016.html [ Crash Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-017.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-self-baseline-synthesized-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-self-baseline-synthesized-002.html [ Failure ]
@@ -3423,11 +3438,6 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-5.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-6.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-7.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-012.html [ Crash Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-013.html [ Crash Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-014.html [ Crash Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-015.html [ Crash Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-016.html [ Crash Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-017.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-002.html [ Failure ]
@@ -3436,11 +3446,6 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-005.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-008.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-011.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-011.html [ Crash Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-012.html [ Crash Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-013.html [ Crash Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-014.html [ Crash Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-015.html [ Crash Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-016.html [ Crash Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-009.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-010.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index cc60f06d..e823b332 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -54882,6 +54882,58 @@
      ]
     },
     "css-color": {
+     "a98rgb-001.html": [
+      "727a0aef7d83069ebf420fe551cde09fd2033dea",
+      [
+       null,
+       [
+        [
+         "/css/css-color/greensquare-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "a98rgb-002.html": [
+      "930c7692525430119ee5f9897006a3921c2edfa2",
+      [
+       null,
+       [
+        [
+         "/css/css-color/blacksquare-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "a98rgb-003.html": [
+      "f4ad2b7bd9bd04df12299b39abfc8e51184ee9c4",
+      [
+       null,
+       [
+        [
+         "/css/css-color/a98rgb-003-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "a98rgb-004.html": [
+      "24c476b7c75c042b9a92c72a57184fdf833e64df",
+      [
+       null,
+       [
+        [
+         "/css/css-color/a98rgb-004-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "border-bottom-color.xht": [
       "994bb4e904ccc28fb54865031ffe55c7ec50bac2",
       [
@@ -55363,6 +55415,19 @@
        {}
       ]
      ],
+     "lab-008.html": [
+      "b0510a620ea1ab1afb27af11f7697a1a18af9747",
+      [
+       null,
+       [
+        [
+         "/css/css-color/greensquare-display-p3-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "lch-001.html": [
       "904e2e5bd7c75dade264e22aa3a145ad56625d67",
       [
@@ -55454,6 +55519,19 @@
        {}
       ]
      ],
+     "lch-008.html": [
+      "feedb9853b93bb03702f24c509a65e9a073cf988",
+      [
+       null,
+       [
+        [
+         "/css/css-color/greensquare-display-p3-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "named-001.html": [
       "61a98dcb7bb02fab3db18ed337eee5ddb07724fc",
       [
@@ -55506,32 +55584,6 @@
        {}
       ]
      ],
-     "predefined-003.html": [
-      "cb05147f996563d2d35d22fa5ad70b8cab2da1ad",
-      [
-       null,
-       [
-        [
-         "/css/css-color/greensquare-090-ref.html",
-         "=="
-        ]
-       ],
-       {}
-      ]
-     ],
-     "predefined-004.html": [
-      "6c4399dcf72d8c1ba5b8f47f29f7bc89f411e032",
-      [
-       null,
-       [
-        [
-         "/css/css-color/greensquare-090-ref.html",
-         "=="
-        ]
-       ],
-       {}
-      ]
-     ],
      "predefined-005.html": [
       "99b611c063eb878aadaa1adfa788fc506a52a46c",
       [
@@ -55611,7 +55663,7 @@
       ]
      ],
      "predefined-011.html": [
-      "e79a7e46de861143efdefa859c8d5c96d119b7bb",
+      "78065d990f4340ff018d8432a7ba553f9dcb7f87",
       [
        null,
        [
@@ -55624,7 +55676,7 @@
       ]
      ],
      "predefined-012.html": [
-      "76a23ef292178bacb1cf6b757948a480091a479e",
+      "70b92df6bcdd136339641ee089ac4394c469c952",
       [
        null,
        [
@@ -55688,13 +55740,130 @@
        {}
       ]
      ],
-     "predefined-017.html": [
-      "766fdfe0899b883c054b8f6100b6f222eae47fd2",
+     "prophoto-rgb-001.html": [
+      "ca4c866c98fab7fabc7d0a20ac042a409496d77f",
       [
        null,
        [
         [
-         "/css/css-color/greensquare-090-ref.html",
+         "/css/css-color/greensquare-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "prophoto-rgb-002.html": [
+      "46e5445d04c7454ff3c3931a75b3a7a64e916627",
+      [
+       null,
+       [
+        [
+         "/css/css-color/blacksquare-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "prophoto-rgb-003.html": [
+      "3a9ede14588c504c34b7ab6c590eecb8311aa753",
+      [
+       null,
+       [
+        [
+         "/css/css-color/prophoto-rgb-003-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "prophoto-rgb-004.html": [
+      "7912ff6dfb50a811fcf104356029b0a5cba5504d",
+      [
+       null,
+       [
+        [
+         "/css/css-color/prophoto-rgb-004-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "prophoto-rgb-005.html": [
+      "73e5cc80866d22bf6e0702a41b35800bfd33b0d3",
+      [
+       null,
+       [
+        [
+         "/css/css-color/greensquare-display-p3-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "rec2020-001.html": [
+      "b51a458c11ab8acd4cc3822682cb0399b8c53e69",
+      [
+       null,
+       [
+        [
+         "/css/css-color/greensquare-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "rec2020-002.html": [
+      "bca9f50436ed1e77405d715ad58b115e60736d59",
+      [
+       null,
+       [
+        [
+         "/css/css-color/blacksquare-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "rec2020-003.html": [
+      "6c6fc9d738b4eccd609ced0c52a1dd91be7e4998",
+      [
+       null,
+       [
+        [
+         "/css/css-color/rec2020-003-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "rec2020-004.html": [
+      "4719ba764ce0017bce56ae5c8ac6cb5b69391859",
+      [
+       null,
+       [
+        [
+         "/css/css-color/rec2020-004-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "rec2020-005.html": [
+      "74e2305e338ad0f4e395748c1cdf2de8e630c1f5",
+      [
+       null,
+       [
+        [
+         "/css/css-color/greensquare-display-p3-ref.html",
          "=="
         ]
        ],
@@ -185858,6 +186027,14 @@
       "a0e70aa6539e88373bc8615c3f4e1453010e85d5",
       []
      ],
+     "a98rgb-003-ref.html": [
+      "9db28b6de5aaabe81cc4477f7e4bd048a5d43cab",
+      []
+     ],
+     "a98rgb-004-ref.html": [
+      "3b8771a704a5f79e7062f790c04f0bbd24efb05b",
+      []
+     ],
      "blacksquare-ref.html": [
       "14bc74b33fa848b6f3056adf24fa9645483e7e2e",
       []
@@ -185882,6 +186059,10 @@
       "18bdcf55c47a0710011c58ff1613daba080ed129",
       []
      ],
+     "greensquare-display-p3-ref.html": [
+      "2134c9681f08afa8ef3b657cf2f66c7cd9de6dc7",
+      []
+     ],
      "greensquare-ref.html": [
       "35a31f8f56468e5c273e2a9efd3ab614c6adc977",
       []
@@ -185934,10 +186115,26 @@
       "bab1f80f685f9e52ea74b8b98f5153dcd9516624",
       []
      ],
+     "prophoto-rgb-003-ref.html": [
+      "e938de60345bf348d9092d03af79c16bccec9929",
+      []
+     ],
+     "prophoto-rgb-004-ref.html": [
+      "8c5f24bcf7e47c07e6cd1dc268b8ecbc3dce8cd7",
+      []
+     ],
      "rebeccapurple-ref.html": [
       "8c15364f38e53cc1651f2f6c115c7b2fca3f4ba9",
       []
      ],
+     "rec2020-003-ref.html": [
+      "da95008fcf417e4ad5841c32b2b58a7359b310c3",
+      []
+     ],
+     "rec2020-004-ref.html": [
+      "68068041f9f81ac54c8b90ffd6e8cc4a787992b1",
+      []
+     ],
      "t31-color-currentColor-b-ref.html": [
       "3013c7050c3c6f057e295923d43c87da6c09751f",
       []
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-001.html b/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-001.html
new file mode 100644
index 0000000..727a0ae
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-001.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: a98-rgb</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-a98-rgb">
+<link rel="match" href="greensquare-ref.html">
+<meta name="assert" content="a98-rgb with no alpha">
+<style>
+    .test { background-color: red; width: 12em; height: 12em; }
+    .test { background-color: color(a98-rgb 0.281363 0.498012 0.116746); } /* green (sRGB #008000) converted to a98-rgb */
+</style>
+<body>
+    <p>Test passes if you see a green square, and no red.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-002.html b/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-002.html
new file mode 100644
index 0000000..930c769
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-002.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: a98-rgb</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-a98-rgb">
+<link rel="match" href="blacksquare-ref.html">
+<meta name="assert" content="a98-rgb with no alpha">
+<style>
+    .test { background-color: red; width: 12em; height: 12em; }
+    .test { background-color: color(a98-rgb 0 0 0); } /* black (sRGB #000000) converted to a98-rgb */
+</style>
+<body>
+    <p>Test passes if you see a black square, and no red.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-003-ref.html
new file mode 100644
index 0000000..9db28b6d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-003-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: CSS Color 4: a98-rgb</title>
+<style>
+    body { background-color: grey; }
+    .test { background-color: rgb(99.993% 100% 100%); width: 12em; height: 12em; } /* color(a98-rgb 1 1 1) converted to sRGB */
+</style>
+<body>
+    <p>Test passes if you see a single square, and not two rectangles of different colors.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-003.html b/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-003.html
new file mode 100644
index 0000000..f4ad2b7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-003.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: a98-rgb</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-a98-rgb">
+<link rel="match" href="a98rgb-003-ref.html">
+<meta name="assert" content="a98-rgb with no alpha">
+<style>
+    body { background-color: grey; }
+    .test { background-color: red; width: 12em; height: 6em; margin-top: 0; }
+    .ref { background-color: rgb(99.993% 100% 100%); width: 12em; height: 6em; margin-bottom: 0; } /* color(a98-rgb 1 1 1) converted to sRGB */
+    .test { background-color: color(a98-rgb 1 1 1); }
+</style>
+<body>
+    <p>Test passes if you see a single square, and not two rectangles of different colors.</p>
+    <div class="ref"></div>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-004-ref.html b/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-004-ref.html
new file mode 100644
index 0000000..3b8771a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-004-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: CSS Color 4: a98-rgb</title>
+<style>
+    .test { background-color: lab(83.2141% -129.1072 87.1718); width: 12em; height: 12em; } /* color(a98-rgb 0 1 0) converted to Lab */
+</style>
+<body>
+    <p>Test passes if you see a single square, and not two rectangles of different colors.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-004.html b/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-004.html
new file mode 100644
index 0000000..24c476b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/a98rgb-004.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: a98-rgb</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-a98-rgb">
+<link rel="match" href="a98rgb-004-ref.html">
+<meta name="assert" content="a98-rgb with no alpha">
+<style>
+    .test { background-color: red; width: 12em; height: 6em; margin-top: 0; }
+    .ref { background-color: lab(83.2141% -129.1072 87.1718); width: 12em; height: 6em; margin-bottom: 0; } /* color(a98-rgb 0 1 0) converted to Lab */
+    .test { background-color: color(a98-rgb 0 1 0); }
+</style>
+<body>
+    <p>Test passes if you see a single square, and not two rectangles of different colors.</p>
+    <div class="ref"></div>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/greensquare-display-p3-ref.html b/third_party/blink/web_tests/external/wpt/css/css-color/greensquare-display-p3-ref.html
new file mode 100644
index 0000000..2134c968
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/greensquare-display-p3-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Green square color(display-p3 0 1 0) reference</title>
+<style>
+    .test { background-color: color(display-p3 0 1 0); width: 12em; height: 12em; }
+</style>
+<body>
+    <p>Test passes if you see a green square, and no red.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/lab-008.html b/third_party/blink/web_tests/external/wpt/css/css-color/lab-008.html
new file mode 100644
index 0000000..b0510a6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/lab-008.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: Specifying Lab and LCH</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#specifying-lab-lch">
+<link rel="match" href="greensquare-display-p3-ref.html">
+<meta name="assert" content="lab() outside the sRGB gamut">
+<style>
+    .test { background-color: red; width: 12em; height: 12em; }
+    .test { background-color: lab(86.6146% -106.5599 102.8717); } /* green color(display-p3 0 1 0) converted to Lab */
+</style>
+<body>
+    <p>Test passes if you see a green square, and no red.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/lch-008.html b/third_party/blink/web_tests/external/wpt/css/css-color/lch-008.html
new file mode 100644
index 0000000..feedb9853
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/lch-008.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: Specifying Lab and LCH</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#specifying-lab-lch">
+<link rel="match" href="greensquare-display-p3-ref.html">
+<meta name="assert" content="lch() outside the sRGB gamut">
+<style>
+    .test { background-color: red; width: 12em; height: 12em; }
+    .test { background-color: lch(86.6146% 148.1135 136.0089); } /* green color(display-p3 0 1 0) converted to LCH */
+</style>
+<body>
+    <p>Test passes if you see a green square, and no red.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/predefined-003.html b/third_party/blink/web_tests/external/wpt/css/css-color/predefined-003.html
deleted file mode 100644
index cb05147..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-color/predefined-003.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>CSS Color 4: predefined colorspaces, default srgb, decimal values</title>
-<link rel="author" title="Chris Lilley" href="mailto:chris@w3.org">
-<link rel="help" href="https://drafts.csswg.org/css-color-4/#predefined">
-<link rel="match" href="greensquare-090-ref.html">
-<meta name="assert" content="Color function with default srgb value as decimal matches sRGB #009900">
-<style>
-    .test { background-color: red; width: 12em; height: 6em; margin-top:0}
-    .ref { background-color: #009900; width: 12em; height: 6em; margin-bottom: 0}
-    .test {background-color: color(0 0.6 0)}
-</style>
-<body>
-    <p>Test passes if you see a green square, and no red.</p>
-    <p class="ref"> </p>
-    <p class="test"> </p>
-</body>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/predefined-004.html b/third_party/blink/web_tests/external/wpt/css/css-color/predefined-004.html
deleted file mode 100644
index 6c4399d..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-color/predefined-004.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>CSS Color 4: predefined colorspaces, default srgb, percent values</title>
-<link rel="author" title="Chris Lilley" href="mailto:chris@w3.org">
-<link rel="help" href="https://drafts.csswg.org/css-color-4/#predefined">
-<link rel="match" href="greensquare-090-ref.html">
-<meta name="assert" content="Color function with default srgb value as percent matches sRGB #009900">
-<style>
-    .test { background-color: red; width: 12em; height: 6em; margin-top:0}
-    .ref { background-color: #009900; width: 12em; height: 6em; margin-bottom: 0}
-    .test {background-color: color(0% 60% 0%)}
-</style>
-<body>
-    <p>Test passes if you see a green square, and no red.</p>
-    <p class="ref"> </p>
-    <p class="test"> </p>
-</body>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/predefined-011.html b/third_party/blink/web_tests/external/wpt/css/css-color/predefined-011.html
index e79a7e46..78065d99 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/predefined-011.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/predefined-011.html
@@ -8,7 +8,7 @@
 <style>
     .test { background-color: red; width: 12em; height: 6em; margin-top:0}
     .ref { background-color: #009900; width: 12em; height: 6em; margin-bottom: 0}
-    .test {background-color: color(rec2020 0.33033 0.55976 0.14863)}
+    .test {background-color: color(rec2020 0.299218 0.533327 0.120785)}
 </style>
 <body>
     <p>Test passes if you see a green square, and no red.</p>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/predefined-012.html b/third_party/blink/web_tests/external/wpt/css/css-color/predefined-012.html
index 76a23ef..70b92df 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/predefined-012.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/predefined-012.html
@@ -8,7 +8,7 @@
 <style>
     .test { background-color: red; width: 12em; height: 6em; margin-top:0}
     .ref { background-color: #009900; width: 12em; height: 6em; margin-bottom: 0}
-    .test {background-color: color(rec2020 33.033% 55.976% 14.863%)}
+    .test {background-color: color(rec2020 29.9218% 53.3327% 12.0785%)}
 </style>
 <body>
     <p>Test passes if you see a green square, and no red.</p>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/predefined-017.html b/third_party/blink/web_tests/external/wpt/css/css-color/predefined-017.html
deleted file mode 100644
index 766fdfe0..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-color/predefined-017.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>CSS Color 4: predefined colorspaces, lab</title>
-<link rel="author" title="Chris Lilley" href="mailto:chris@w3.org">
-<link rel="help" href="https://drafts.csswg.org/css-color-4/#predefined">
-<link rel="match" href="greensquare-090-ref.html">
-<meta name="assert" content="Color function with explicit XYZ percentage value matches sRGB #009900">
-<style>
-    .test { background-color: red; width: 12em; height: 6em; margin-top:0}
-    .ref { background-color: #009900; width: 12em; height: 6em; margin-bottom: 0}
-    .test {background-color: color(xyz 12.266% 22.836% 3.093%)}
-</style>
-<body>
-    <p>Test passes if you see a green square, and no red.</p>
-    <p class="ref"> </p>
-    <p class="test"> </p>
-</body>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-001.html b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-001.html
new file mode 100644
index 0000000..ca4c866c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-001.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: prophoto-rgb</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-prophoto-rgb">
+<link rel="match" href="greensquare-ref.html">
+<meta name="assert" content="prophoto-rgb with no alpha">
+<style>
+    .test { background-color: red; width: 12em; height: 12em; }
+    .test { background-color: color(prophoto-rgb 0.230479 0.395789 0.129968); } /* green (sRGB #008000) converted to prophoto-rgb */
+</style>
+<body>
+    <p>Test passes if you see a green square, and no red.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-002.html b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-002.html
new file mode 100644
index 0000000..46e5445
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-002.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: prophoto-rgb</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-prophoto-rgb">
+<link rel="match" href="blacksquare-ref.html">
+<meta name="assert" content="prophoto-rgb with no alpha">
+<style>
+    .test { background-color: red; width: 12em; height: 12em; }
+    .test { background-color: color(prophoto-rgb 0 0 0); } /* black (sRGB #000000) converted to prophoto-rgb */
+</style>
+<body>
+    <p>Test passes if you see a black square, and no red.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-003-ref.html
new file mode 100644
index 0000000..e938de60
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-003-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: CSS Color 4: prophoto-rgb</title>
+<style>
+    body { background-color: grey; }
+    .test { background-color: lab(100% 0.0131 0.0085); width: 12em; height: 12em; } /* color(prophoto-rgb 1 1 1) converted to Lab */
+</style>
+<body>
+    <p>Test passes if you see a single square, and not two rectangles of different colors.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-003.html b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-003.html
new file mode 100644
index 0000000..3a9ede1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-003.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: prophoto-rgb</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-prophoto-rgb">
+<link rel="match" href="prophoto-rgb-003-ref.html">
+<meta name="assert" content="prophoto-rgb with no alpha">
+<style>
+    body { background-color: grey; }
+    .test { background-color: red; width: 12em; height: 6em; margin-top: 0; }
+    .ref { background-color: lab(100% 0.0131 0.0085); width: 12em; height: 6em; margin-bottom: 0; } /* color(prophoto-rgb 1 1 1) converted to Lab */
+    .test { background-color: color(prophoto-rgb 1 1 1); }
+</style>
+<body>
+    <p>Test passes if you see a single square, and not two rectangles of different colors.</p>
+    <div class="ref"></div>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-004-ref.html b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-004-ref.html
new file mode 100644
index 0000000..8c5f24b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-004-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: CSS Color 4: prophoto-rgb</title>
+<style>
+    .test { background-color: lab(87.5745% -186.6921 150.9905); width: 12em; height: 12em; } /* color(prophoto-rgb 0 1 0) converted to Lab */
+</style>
+<body>
+    <p>Test passes if you see a single square, and not two rectangles of different colors.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-004.html b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-004.html
new file mode 100644
index 0000000..7912ff6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-004.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: prophoto-rgb</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-prophoto-rgb">
+<link rel="match" href="prophoto-rgb-004-ref.html">
+<meta name="assert" content="prophoto-rgb with no alpha">
+<style>
+    .test { background-color: red; width: 12em; height: 6em; margin-top: 0; }
+    .ref { background-color: lab(87.5745% -186.6921 150.9905); width: 12em; height: 6em; margin-bottom: 0; } /* color(prophoto-rgb 0 1 0) converted to Lab */
+    .test { background-color: color(prophoto-rgb 0 1 0); }
+</style>
+<body>
+    <p>Test passes if you see a single square, and not two rectangles of different colors.</p>
+    <div class="ref"></div>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-005.html b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-005.html
new file mode 100644
index 0000000..73e5cc80
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/prophoto-rgb-005.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: prophoto-rgb</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-prophoto-rgb">
+<link rel="match" href="greensquare-display-p3-ref.html">
+<meta name="assert" content="prophoto-rgb outside the sRGB gamut">
+<style>
+    .test { background-color: red; width: 12em; height: 12em; }
+    .test { background-color: color(prophoto-rgb 0.42444 0.934918 0.190922); } /* green color(display-p3 0 1 0) converted to prophoto-rgb */
+</style>
+<body>
+    <p>Test passes if you see a green square, and no red.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-001.html b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-001.html
new file mode 100644
index 0000000..b51a458c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-001.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: rec2020</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-rec2020">
+<link rel="match" href="greensquare-ref.html">
+<meta name="assert" content="rec2020 with no alpha">
+<style>
+    .test { background-color: red; width: 12em; height: 12em; }
+    .test { background-color: color(rec2020 0.235202 0.431704 0.085432); } /* green (sRGB #008000) converted to rec2020 */
+</style>
+<body>
+    <p>Test passes if you see a green square, and no red.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-002.html b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-002.html
new file mode 100644
index 0000000..bca9f50
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-002.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: rec2020</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-rec2020">
+<link rel="match" href="blacksquare-ref.html">
+<meta name="assert" content="rec2020 with no alpha">
+<style>
+    .test { background-color: red; width: 12em; height: 12em; }
+    .test { background-color: color(rec2020 0 0 0); } /* black (sRGB #000000) converted to rec2020 */
+</style>
+<body>
+    <p>Test passes if you see a black square, and no red.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-003-ref.html
new file mode 100644
index 0000000..da95008f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-003-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: CSS Color 4: rec2020</title>
+<style>
+    body { background-color: grey; }
+    .test { background-color: rgb(99.993% 100% 100%); width: 12em; height: 12em; } /* color(rec2020 1 1 1) converted to sRGB */
+</style>
+<body>
+    <p>Test passes if you see a single square, and not two rectangles of different colors.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-003.html b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-003.html
new file mode 100644
index 0000000..6c6fc9d73
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-003.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: rec2020</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-rec2020">
+<link rel="match" href="rec2020-003-ref.html">
+<meta name="assert" content="rec2020 with no alpha">
+<style>
+    body { background-color: grey; }
+    .test { background-color: red; width: 12em; height: 6em; margin-top: 0; }
+    .ref { background-color: rgb(99.993% 100% 100%); width: 12em; height: 6em; margin-bottom: 0; } /* color(rec2020 1 1 1) converted to sRGB */
+    .test { background-color: color(rec2020 1 1 1); }
+</style>
+<body>
+    <p>Test passes if you see a single square, and not two rectangles of different colors.</p>
+    <div class="ref"></div>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-004-ref.html b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-004-ref.html
new file mode 100644
index 0000000..6806804
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-004-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: CSS Color 4: rec2020</title>
+<style>
+    .test { background-color: lab(85.7729% -160.7259 109.2319); width: 12em; height: 12em; } /* color(rec2020 0 1 0) converted to Lab */
+</style>
+<body>
+    <p>Test passes if you see a single square, and not two rectangles of different colors.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-004.html b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-004.html
new file mode 100644
index 0000000..4719ba7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-004.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: rec2020</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-rec2020">
+<link rel="match" href="rec2020-004-ref.html">
+<meta name="assert" content="rec2020 with no alpha">
+<style>
+    .test { background-color: red; width: 12em; height: 6em; margin-top: 0; }
+    .ref { background-color: lab(85.7729% -160.7259 109.2319); width: 12em; height: 6em; margin-bottom: 0; } /* color(rec2020 0 1 0) converted to Lab */
+    .test { background-color: color(rec2020 0 1 0); }
+</style>
+<body>
+    <p>Test passes if you see a single square, and not two rectangles of different colors.</p>
+    <div class="ref"></div>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-005.html b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-005.html
new file mode 100644
index 0000000..74e2305e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/rec2020-005.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: rec2020</title>
+<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#valdef-color-rec2020">
+<link rel="match" href="greensquare-display-p3-ref.html">
+<meta name="assert" content="rec2020 outside the sRGB gamut">
+<style>
+    .test { background-color: red; width: 12em; height: 12em; }
+    .test { background-color: color(rec2020 0.431836 0.970723 0.079208); } /* green color(display-p3 0 1 0) converted to rec2020 */
+</style>
+<body>
+    <p>Test passes if you see a green square, and no red.</p>
+    <div class="test"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/layout-instability/display-change-with-transform.html b/third_party/blink/web_tests/external/wpt/layout-instability/display-change-with-transform.html
new file mode 100644
index 0000000..36aa438
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/layout-instability/display-change-with-transform.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>Layout Instability: change display type with transform</title>
+<link rel="help" href="https://wicg.github.io/layout-instability/" />
+<style>
+  div {
+    width: 100px;
+    height: 100px;
+  }
+  #target {
+    transform: translateX(0);
+  }
+</style>
+<div id=target>
+  <div id=shift>test</div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/util.js"></script>
+<script>
+
+promise_test(async () => {
+  const watcher = new ScoreWatcher;
+  await waitForAnimationFrames(2);
+
+  target.style.display = 'flex';
+
+  await waitForAnimationFrames(1);
+
+  assert_equals(watcher.score, 0);
+}, 'Shift accompanied by body display change.');
+
+</script>
diff --git a/third_party/blink/web_tests/fast/forms/color/input-color-under-shadow-popup-crash-expected.txt b/third_party/blink/web_tests/fast/forms/color/input-color-under-shadow-popup-crash-expected.txt
new file mode 100644
index 0000000..ee0fc92
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/color/input-color-under-shadow-popup-crash-expected.txt
@@ -0,0 +1 @@
+PASS - The popup isn't present.
diff --git a/third_party/blink/web_tests/fast/forms/color/input-color-under-shadow-popup-crash.html b/third_party/blink/web_tests/fast/forms/color/input-color-under-shadow-popup-crash.html
new file mode 100644
index 0000000..9fa854f
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/color/input-color-under-shadow-popup-crash.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<!-- crbug.com/1160433 -->
+<title>Test that popup, its owner element unassigned under a shadow root, is cleanup when the page is shutdown. </title>
+<script src="../resources/picker-common.js"></script>
+<canvas>
+<video>
+<select>
+<input type="color" id="color" value="#126465">
+</canvas>
+
+<div>FAIL</div>
+
+<form action="../resources/popup-close-after-navigation.html" id="form1"></form>
+<script>
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+
+function openCallback() {
+    form1.submit();
+}
+
+function errorCallback() {
+    testRunner.notifyDone();
+}
+
+window.onload = function () {
+    openPicker(color, openCallback, errorCallback);
+}
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/resources/popup-close-after-navigation.html b/third_party/blink/web_tests/fast/forms/resources/popup-close-after-navigation.html
new file mode 100644
index 0000000..1ceb1eb0
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/resources/popup-close-after-navigation.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<div id="content">FAIL</div>
+<script>
+
+if (window.chrome && chrome.gpuBenchmarking) {
+    let pointerActions =
+        [{source: "mouse",
+          actions: [
+            { name: "pointerMove", x: 50, y: 50 },
+            { name: "pointerDown", x: 50, y: 50, button: 0},
+            { name: "pointerUp", button: 0 }]}];
+
+    chrome.gpuBenchmarking.pointerActionSequence(pointerActions, () => {
+        content.innerHTML = "PASS - The popup isn't present.";
+        testRunner.notifyDone();
+    });
+}
+else {
+    testRunner.notifyDone();
+}
+</script>
+</html>
diff --git a/third_party/blink/web_tests/fast/lists/w3-css3-list-styles-fallback-style-expected.txt b/third_party/blink/web_tests/fast/lists/w3-css3-list-styles-fallback-style-expected.txt
index c2b4344..3da8d27c 100644
--- a/third_party/blink/web_tests/fast/lists/w3-css3-list-styles-fallback-style-expected.txt
+++ b/third_party/blink/web_tests/fast/lists/w3-css3-list-styles-fallback-style-expected.txt
@@ -29,10 +29,10 @@
 
 hebrew
 PASS list marker is -1.
-PASS list marker is ספא.
+PASS list marker is אפס.
 PASS list marker is א.
 
-PASS list marker is טצקתת'טצקתת.
+PASS list marker is תתקצט׳תתקצט.
 PASS list marker is 1000000.
 PASS list marker is 1000001.
 
diff --git a/third_party/blink/web_tests/fast/lists/w3-css3-list-styles-fallback-style.html b/third_party/blink/web_tests/fast/lists/w3-css3-list-styles-fallback-style.html
index 44ebbdb..5e53d1d 100644
--- a/third_party/blink/web_tests/fast/lists/w3-css3-list-styles-fallback-style.html
+++ b/third_party/blink/web_tests/fast/lists/w3-css3-list-styles-fallback-style.html
@@ -119,11 +119,11 @@
         <h2>hebrew</h2>
         <ol class="hebrew" start="-1">
             <li>-1</li>
-            <li>&#x5E1;&#x5E4;&#x5D0;</li>
+            <li>&#x5D0;&#x5E4;&#x5E1;</li>
             <li>&#x5D0;</li>
         </ol>
         <ol class="hebrew" start="999999">
-            <li>&#x5D8;&#x5E6;&#x5E7;&#x5EA;&#x5EA;&#x27;&#x5D8;&#x5E6;&#x5E7;&#x5EA;&#x5EA;</li>
+            <li>&#x5EA;&#x5EA;&#x5E7;&#x5E6;&#x5D8;&#x5F3;&#x5EA;&#x5EA;&#x5E7;&#x5E6;&#x5D8;</li>
             <li>1000000</li>
             <li>1000001</li>
         </ol>
diff --git a/third_party/blink/web_tests/fast/lists/w3-list-styles-expected.txt b/third_party/blink/web_tests/fast/lists/w3-list-styles-expected.txt
index 7fd44cf..116033a0 100644
--- a/third_party/blink/web_tests/fast/lists/w3-list-styles-expected.txt
+++ b/third_party/blink/web_tests/fast/lists/w3-list-styles-expected.txt
@@ -266,9 +266,9 @@
 צח ninety-eight, undefined, may show צח
 צט ninety-nine, undefined, may show צט
 ק hundred, undefined, may show ק
-אק a hundred and one, undefined, may show קא
+קא a hundred and one, undefined, may show קא
 
-ספא zero, undefined, may show אפס
+אפס zero, undefined, may show אפס
 א one, should show א
 
 georgian
diff --git a/third_party/blink/web_tests/http/tests/mojo/associated-interfaces.html b/third_party/blink/web_tests/http/tests/mojo/associated-interfaces.html
index e7ff872..fb49c56 100644
--- a/third_party/blink/web_tests/http/tests/mojo/associated-interfaces.html
+++ b/third_party/blink/web_tests/http/tests/mojo/associated-interfaces.html
@@ -1,4 +1,168 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="./associated-interfaces.js" type="module"></script>
+<script type="module">
+import {Counter, CounterObserverReceiver, CounterRemote} from '/gen/content/test/data/mojo_bindings_web_test.test-mojom.m.js';
+
+class ObserverImpl {
+  constructor() {
+    this.count_ = null;
+    this.disconnectResolvers_ = [];
+  }
+
+  get count() {
+    return this.count_;
+  }
+
+  async nextCloneDisconnect() {
+    return new Promise(r => this.disconnectResolvers_.push(r));
+  }
+
+  onCountChanged(count) {
+    this.count_ = count;
+  }
+
+  onCloneDisconnected() {
+    let resolvers = [];
+    [resolvers, this.disconnectResolvers_] =
+        [this.disconnectResolvers_, resolvers];
+    resolvers.forEach(r => r());
+  }
+}
+
+function getCounterRemote() {
+  const {handle0, handle1} = Mojo.createMessagePipe();
+  const remote = new CounterRemote(handle1);
+  Mojo.bindInterface(Counter.$interfaceName, handle0, 'process');
+  return remote;
+}
+
+async function waitForDisconnect(receiver) {
+  return new Promise(r => receiver.onConnectionError.addListener(r));
+}
+
+promise_test(async () => {
+  const counter = getCounterRemote();
+
+  counter.increment();
+  counter.increment();
+  const {count} = await counter.increment();
+  assert_equals(count, 3);
+}, 'basic validity check for browser-side support of these tests');
+
+promise_test(async () => {
+  const counter = getCounterRemote();
+  const observerA = new ObserverImpl;
+  const receiverA = new CounterObserverReceiver(observerA);
+  const observerB = new ObserverImpl;
+  const receiverB = new CounterObserverReceiver(observerB);
+
+  counter.addObserver(receiverA.$.associateAndPassRemote());
+  counter.addObserver(receiverB.$.associateAndPassRemote());
+
+  counter.increment();
+  const {count} = await counter.increment();
+  assert_equals(count, 2);
+
+  // The observers should always observe changes before the caller of increment
+  // gets a reply, so the above await should guarantee that the observers' count
+  // values are up-to-date.
+  assert_equals(observerA.count, 2);
+  assert_equals(observerB.count, 2);
+}, 'associated remotes can be created and passed');
+
+promise_test(async () => {
+  const counter = getCounterRemote();
+  const observerA = new ObserverImpl;
+  const receiverA = new CounterObserverReceiver(observerA);
+  const observerB = new ObserverImpl;
+  const receiverB = new CounterObserverReceiver(observerB);
+
+  receiverA.$.bindHandle((await counter.addNewObserver()).receiver.handle);
+  receiverB.$.bindHandle((await counter.addNewObserver()).receiver.handle);
+
+  counter.increment();
+  const {count} = await counter.increment();
+  assert_equals(count, 2);
+
+  assert_equals(observerA.count, 2);
+  assert_equals(observerB.count, 2);
+}, 'associated receivers can be deserialized and receive messages');
+
+promise_test(async () => {
+  const counterA = getCounterRemote();
+  const counterB = new CounterRemote;
+  const counterC = new CounterRemote;
+  const counterD = new CounterRemote;
+  counterA.clone(counterB.$.associateAndPassReceiver());
+  counterA.clone(counterC.$.associateAndPassReceiver());
+  counterB.clone(counterD.$.associateAndPassReceiver());
+
+  // Increment operations among the three interfaces should be strictly ordered.
+  const increments = [
+    counterA.increment(),
+    counterB.increment(),
+    counterC.increment(),
+    counterD.increment(),
+    counterA.increment(),
+    counterB.increment(),
+    counterC.increment(),
+    counterD.increment(),
+  ];
+  const replies = await Promise.all(increments);
+  const results = replies.map(reply => reply.count);
+  assert_array_equals([1, 2, 3, 4, 5, 6, 7, 8], results);
+}, 'associated receivers can be created and passed, and message ordering is preserved among endpoints');
+
+promise_test(async () => {
+  const counterA = getCounterRemote();
+  const {remote: counterB} = await counterA.cloneToNewRemote();
+  const {remote: counterC} = await counterA.cloneToNewRemote();
+  const {remote: counterD} = await counterC.cloneToNewRemote();
+
+  const increments = [
+    counterA.increment(),
+    counterB.increment(),
+    counterC.increment(),
+    counterD.increment(),
+    counterA.increment(),
+    counterB.increment(),
+    counterC.increment(),
+    counterD.increment(),
+  ];
+  const replies = await Promise.all(increments);
+  const results = replies.map(reply => reply.count);
+  assert_array_equals([1, 2, 3, 4, 5, 6, 7, 8], results);
+}, 'associated remotes can be deserialized and used to send messages, and message ordering is preserved among endpoints');
+
+promise_test(async () => {
+  const counter = getCounterRemote();
+  const observer = new ObserverImpl;
+  const receiver = new CounterObserverReceiver(observer);
+  counter.addObserver(receiver.$.associateAndPassRemote());
+  counter.increment();
+  counter.increment();
+  counter.increment();
+  await counter.$.flushForTesting();
+  assert_equals(observer.count, 3);
+}, 'associated endpoints can use flushForTesting');
+
+promise_test(async () => {
+  const counter = getCounterRemote();
+  const {remote: clone} = await counter.cloneToNewRemote();
+  const observer = new ObserverImpl;
+  const receiver = new CounterObserverReceiver(observer);
+  counter.addObserver(receiver.$.associateAndPassRemote());
+  clone.$.close();
+  observer.nextCloneDisconnect();
+}, 'closing an associated endpoint from JavaScript will signal its peer');
+
+promise_test(async () => {
+  const counter = getCounterRemote();
+  const observer = new ObserverImpl;
+  const receiver = new CounterObserverReceiver(observer);
+  counter.addObserver(receiver.$.associateAndPassRemote());
+  counter.removeAllObservers();
+  await waitForDisconnect(receiver);
+}, 'JavaScript associated endpoints are notified when their peers close');
+</script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/associated-interfaces.js b/third_party/blink/web_tests/http/tests/mojo/associated-interfaces.js
deleted file mode 100644
index 6c3a86d7..0000000
--- a/third_party/blink/web_tests/http/tests/mojo/associated-interfaces.js
+++ /dev/null
@@ -1,163 +0,0 @@
-import {Counter, CounterObserverReceiver, CounterRemote} from '/gen/content/test/data/mojo_bindings_web_test.test-mojom.m.js';
-
-class ObserverImpl {
-  constructor() {
-    this.count_ = null;
-    this.disconnectResolvers_ = [];
-  }
-
-  get count() {
-    return this.count_;
-  }
-
-  async nextCloneDisconnect() {
-    return new Promise(r => this.disconnectResolvers_.push(r));
-  }
-
-  onCountChanged(count) {
-    this.count_ = count;
-  }
-
-  onCloneDisconnected() {
-    let resolvers = [];
-    [resolvers, this.disconnectResolvers_] =
-        [this.disconnectResolvers_, resolvers];
-    resolvers.forEach(r => r());
-  }
-}
-
-function getCounterRemote() {
-  const {handle0, handle1} = Mojo.createMessagePipe();
-  const remote = new CounterRemote(handle1);
-  Mojo.bindInterface(Counter.$interfaceName, handle0, 'process');
-  return remote;
-}
-
-async function waitForDisconnect(receiver) {
-  return new Promise(r => receiver.onConnectionError.addListener(r));
-}
-
-promise_test(async () => {
-  const counter = getCounterRemote();
-
-  counter.increment();
-  counter.increment();
-  const {count} = await counter.increment();
-  assert_equals(count, 3);
-}, 'basic validity check for browser-side support of these tests');
-
-promise_test(async () => {
-  const counter = getCounterRemote();
-  const observerA = new ObserverImpl;
-  const receiverA = new CounterObserverReceiver(observerA);
-  const observerB = new ObserverImpl;
-  const receiverB = new CounterObserverReceiver(observerB);
-
-  counter.addObserver(receiverA.$.associateAndPassRemote());
-  counter.addObserver(receiverB.$.associateAndPassRemote());
-
-  counter.increment();
-  const {count} = await counter.increment();
-  assert_equals(count, 2);
-
-  // The observers should always observe changes before the caller of increment
-  // gets a reply, so the above await should guarantee that the observers' count
-  // values are up-to-date.
-  assert_equals(observerA.count, 2);
-  assert_equals(observerB.count, 2);
-}, 'associated remotes can be created and passed');
-
-promise_test(async () => {
-  const counter = getCounterRemote();
-  const observerA = new ObserverImpl;
-  const receiverA = new CounterObserverReceiver(observerA);
-  const observerB = new ObserverImpl;
-  const receiverB = new CounterObserverReceiver(observerB);
-
-  receiverA.$.bindHandle((await counter.addNewObserver()).receiver.handle);
-  receiverB.$.bindHandle((await counter.addNewObserver()).receiver.handle);
-
-  counter.increment();
-  const {count} = await counter.increment();
-  assert_equals(count, 2);
-
-  assert_equals(observerA.count, 2);
-  assert_equals(observerB.count, 2);
-}, 'associated receivers can be deserialized and receive messages');
-
-promise_test(async () => {
-  const counterA = getCounterRemote();
-  const counterB = new CounterRemote;
-  const counterC = new CounterRemote;
-  const counterD = new CounterRemote;
-  counterA.clone(counterB.$.associateAndPassReceiver());
-  counterA.clone(counterC.$.associateAndPassReceiver());
-  counterB.clone(counterD.$.associateAndPassReceiver());
-
-  // Increment operations among the three interfaces should be strictly ordered.
-  const increments = [
-    counterA.increment(),
-    counterB.increment(),
-    counterC.increment(),
-    counterD.increment(),
-    counterA.increment(),
-    counterB.increment(),
-    counterC.increment(),
-    counterD.increment(),
-  ];
-  const replies = await Promise.all(increments);
-  const results = replies.map(reply => reply.count);
-  assert_array_equals([1, 2, 3, 4, 5, 6, 7, 8], results);
-}, 'associated receivers can be created and passed, and message ordering is preserved among endpoints');
-
-promise_test(async () => {
-  const counterA = getCounterRemote();
-  const {remote: counterB} = await counterA.cloneToNewRemote();
-  const {remote: counterC} = await counterA.cloneToNewRemote();
-  const {remote: counterD} = await counterC.cloneToNewRemote();
-
-  const increments = [
-    counterA.increment(),
-    counterB.increment(),
-    counterC.increment(),
-    counterD.increment(),
-    counterA.increment(),
-    counterB.increment(),
-    counterC.increment(),
-    counterD.increment(),
-  ];
-  const replies = await Promise.all(increments);
-  const results = replies.map(reply => reply.count);
-  assert_array_equals([1, 2, 3, 4, 5, 6, 7, 8], results);
-}, 'associated remotes can be deserialized and used to send messages, and message ordering is preserved among endpoints');
-
-promise_test(async () => {
-  const counter = getCounterRemote();
-  const observer = new ObserverImpl;
-  const receiver = new CounterObserverReceiver(observer);
-  counter.addObserver(receiver.$.associateAndPassRemote());
-  counter.increment();
-  counter.increment();
-  counter.increment();
-  await counter.$.flushForTesting();
-  assert_equals(observer.count, 3);
-}, 'associated endpoints can use flushForTesting');
-
-promise_test(async () => {
-  const counter = getCounterRemote();
-  const {remote: clone} = await counter.cloneToNewRemote();
-  const observer = new ObserverImpl;
-  const receiver = new CounterObserverReceiver(observer);
-  counter.addObserver(receiver.$.associateAndPassRemote());
-  clone.$.close();
-  observer.nextCloneDisconnect();
-}, 'closing an associated endpoint from JavaScript will signal its peer');
-
-promise_test(async () => {
-  const counter = getCounterRemote();
-  const observer = new ObserverImpl;
-  const receiver = new CounterObserverReceiver(observer);
-  counter.addObserver(receiver.$.associateAndPassRemote());
-  counter.removeAllObservers();
-  await waitForDisconnect(receiver);
-}, 'JavaScript associated endpoints are notified when their peers close');
diff --git a/third_party/blink/web_tests/http/tests/mojo/associated_binding.html b/third_party/blink/web_tests/http/tests/mojo/associated_binding.html
deleted file mode 100644
index 3977a5a7..0000000
--- a/third_party/blink/web_tests/http/tests/mojo/associated_binding.html
+++ /dev/null
@@ -1,125 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom.js"></script>
-<script>
-'use strict';
-
-function SenderImpl(callback) {
-  this.callback = callback;
-}
-
-SenderImpl.prototype.echo = function(value) {
-  return Promise.resolve({value: value});
-};
-
-SenderImpl.prototype.send = function(value) {
-  if (this.callback) {
-    this.callback(value);
-  }
-};
-
-var IntegerSenderImpl = SenderImpl;
-
-function IntegerSenderConnectionImpl() {
-  this.integerSenderBindings = new mojo.AssociatedBindingSet(
-      mojo.test.IntegerSender);
-}
-
-IntegerSenderConnectionImpl.prototype.getSender = function(
-    integerSenderRequest) {
-  this.integerSenderBindings.addBinding(new IntegerSenderImpl(),
-      integerSenderRequest);
-};
-
-promise_test(async () => {
-  var integerSenderConnection = new mojo.test.IntegerSenderConnectionPtr();
-  var integerSenderConnectionImpl = new IntegerSenderConnectionImpl();
-  var integerSenderConnectionBinding = new mojo.Binding(
-      mojo.test.IntegerSenderConnection,
-      integerSenderConnectionImpl,
-      mojo.makeRequest(integerSenderConnection));
-
-  // AssociatedInterfaceRequest for integerSender.
-  var integerSenderPtrInfo0 = new mojo.AssociatedInterfacePtrInfo();
-  var integerSenderRequest0 = mojo.makeRequest(integerSenderPtrInfo0);
-  var integerSender0 = new mojo.test.IntegerSenderAssociatedPtr(
-      integerSenderPtrInfo0);
-
-  var integerSenderPtrInfo1 = new mojo.AssociatedInterfacePtrInfo();
-  var integerSenderRequest1 = mojo.makeRequest(integerSenderPtrInfo1);
-  var integerSender1 = new mojo.test.IntegerSenderAssociatedPtr(
-      integerSenderPtrInfo1);
-
-  integerSenderConnection.getSender(integerSenderRequest0);
-  integerSenderConnection.getSender(integerSenderRequest1);
-
-  // Master Binding close triggers connection error handler on
-  // interface endpoint clients for all associated endpoints.
-  var connectionErrorHandler0 = new Promise((resolve, reject) => {
-    integerSender0.ptr.setConnectionErrorHandler(() => {
-      resolve();
-    });
-  });
-
-  var connectionErrorHandler1 = new Promise((resolve, reject) => {
-    integerSender1.ptr.setConnectionErrorHandler(() => {
-      resolve();
-    });
-  });
-
-  setTimeout(integerSenderConnectionBinding.close.bind(
-      integerSenderConnectionBinding), 0);
-  await Promise.all([connectionErrorHandler0, connectionErrorHandler1]);
-}, 'all endpoints connectionErrorHandler called on master binding close');
-
-promise_test(async () => {
-  var integerSenderConnection = new mojo.test.IntegerSenderConnectionPtr();
-  var integerSenderConnectionImpl = new IntegerSenderConnectionImpl();
-  var integerSenderConnectionBinding = new mojo.Binding(
-      mojo.test.IntegerSenderConnection,
-      integerSenderConnectionImpl,
-      mojo.makeRequest(integerSenderConnection));
-
-  var integerSenders = [];
-  for (var i = 0; i < 3; i++) {
-    // AssociatedInterfaceRequest for integerSender.
-    var integerSenderPtrInfo = new mojo.AssociatedInterfacePtrInfo();
-    var integerSenderRequest = mojo.makeRequest(integerSenderPtrInfo);
-    var integerSender =
-        new mojo.test.IntegerSenderAssociatedPtr(integerSenderPtrInfo);
-    integerSenderConnection.getSender(integerSenderRequest);
-
-    // Wait for integerSenderConnection getSender message to be received by
-    // integerSenderConnection's binding side and all integerSender binding
-    // to be created.
-    assert_equals((await integerSender.echo(3)).value, 3);
-    integerSenders.push(integerSender);
-  }
-
-  await new Promise((resolve, reject) => {
-    integerSenderConnectionImpl.integerSenderBindings
-        .setConnectionErrorHandler(() => {resolve();});
-    integerSenders[0].ptr.reset();
-  });
-
-  await new Promise((resolve, reject) => {
-    integerSenderConnectionImpl.integerSenderBindings
-        .setConnectionErrorHandler(function({customReason, description}) {
-      assert_equals(customReason, 32);
-      assert_equals(description, 'goodbye');
-      resolve();
-    });
-    integerSenders[1].ptr.resetWithReason({customReason: 32,
-        description: 'goodbye'});
-  });
-
-  // integerSender2's binding should still exist.
-  assert_equals((await integerSenders[2].echo(11)).value, 11);
-
-  integerSenderConnectionImpl.integerSenderBindings.closeAllBindings();
-  assert_true(integerSenderConnectionImpl.integerSenderBindings.isEmpty());
-}, 'associated binding set');
-
-</script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/associated_interface_ptr.html b/third_party/blink/web_tests/http/tests/mojo/associated_interface_ptr.html
deleted file mode 100644
index 50e56be0..0000000
--- a/third_party/blink/web_tests/http/tests/mojo/associated_interface_ptr.html
+++ /dev/null
@@ -1,345 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom.js"></script>
-<script>
-'use strict';
-
-function SenderImpl(callback) {
-  this.callback = callback;
-}
-
-SenderImpl.prototype.echo = function(value) {
-  return Promise.resolve({value: value});
-};
-
-SenderImpl.prototype.send = function(value) {
-  if (this.callback) {
-    this.callback(value);
-  }
-};
-
-var IntegerSenderImpl = SenderImpl;
-var StringSenderImpl = SenderImpl;
-
-function IntegerSenderConnectionImpl() {
-  this.integerSenderBinding_ = null;
-}
-
-IntegerSenderConnectionImpl.prototype.getSender = function(
-    integerSenderRequest) {
-  this.integerSenderBinding_ = new mojo.AssociatedBinding(
-      mojo.test.IntegerSender, new IntegerSenderImpl(), integerSenderRequest);
-};
-
-IntegerSenderConnectionImpl.prototype.asyncGetSender = function() {
-  var integerSenderPtrInfo = new mojo.AssociatedInterfacePtrInfo();
-  var integerSenderRequest = mojo.makeRequest(integerSenderPtrInfo);
-  this.getSender(integerSenderRequest);
-  return Promise.resolve({sender: integerSenderPtrInfo});
-};
-
-function IntegerSenderConnectionAtBothEndsImpl() {
-  this.integerSender_ = null;
-}
-
-IntegerSenderConnectionAtBothEndsImpl.prototype.getSender =
-    IntegerSenderConnectionImpl.prototype.getSender;
-
-IntegerSenderConnectionAtBothEndsImpl.prototype.setSender = function(
-    integerSenderPtrInfo) {
-  this.integerSender_ = new mojo.test.IntegerSenderAssociatedPtr(
-      integerSenderPtrInfo);
-  return this.integerSender_.echo(456);
-};
-
-function IntegerSenderConnectionImplWithConnectionError() {
-  this.integerSenderBinding_ = null;
-}
-
-IntegerSenderConnectionImplWithConnectionError.prototype.getSender =
-    function(integerSenderRequest) {
-  this.integerSenderBinding_ = new mojo.AssociatedBinding(
-      mojo.test.IntegerSender, new IntegerSenderImpl(), integerSenderRequest);
-  this.integerSenderBinding_.closeWithReason(
-      {customReason: 42, description: 'hey'});
-};
-
-function SenderConnectionBindLaterImpl({getIntegerSenderCallback,
-    getStringSenderCallback} = {}) {
-  this.getIntegerSenderCallback = getIntegerSenderCallback;
-  this.getStringSenderCallback = getStringSenderCallback;
-  this.integerSenderBinding_ = null;
-  this.stringSenderBinding_ = null;
-}
-
-SenderConnectionBindLaterImpl.prototype.getIntegerSender =
-    function(integerSenderRequest) {
-  setTimeout(() => {
-    this.integerSenderBinding_ = new mojo.AssociatedBinding(
-        mojo.test.IntegerSender,
-        new IntegerSenderImpl(this.getIntegerSenderCallback),
-        integerSenderRequest);
-  }, 0);
-};
-
-SenderConnectionBindLaterImpl.prototype.getStringSender =
-    function(stringSenderRequest) {
-  this.stringSenderBinding_ = new mojo.AssociatedBinding(
-      mojo.test.StringSender,
-      new StringSenderImpl(this.getStringSenderCallback),
-      stringSenderRequest);
-};
-
-function SenderConnectionImpl({getIntegerSenderCallback,
-    getStringSenderCallback} = {}) {
-  this.getIntegerSenderCallback = getIntegerSenderCallback;
-  this.getStringSenderCallback = getStringSenderCallback;
-  this.integerSenderBinding_ = null;
-  this.stringSenderBinding_ = null;
-}
-
-SenderConnectionImpl.prototype.getIntegerSender =
-    function(integerSenderRequest) {
-  this.integerSenderBinding_ = new mojo.AssociatedBinding(
-      mojo.test.IntegerSender,
-      new IntegerSenderImpl(this.getIntegerSenderCallback),
-      integerSenderRequest);
-};
-
-SenderConnectionImpl.prototype.getStringSender =
-    function(stringSenderRequest) {
-  this.stringSenderBinding_ = new mojo.AssociatedBinding(
-      mojo.test.StringSender,
-      new StringSenderImpl(this.getStringSenderCallback),
-      stringSenderRequest);
-};
-
-promise_test(async () => {
-  var integerSenderConnection = new
-      mojo.test.IntegerSenderConnectionPtr();
-  var integerSenderConnectionBinding = new mojo.Binding(
-      mojo.test.IntegerSenderConnection,
-      new IntegerSenderConnectionImpl(),
-      mojo.makeRequest(integerSenderConnection));
-
-  // Sending AssociatedInterfaceRequest.
-  var integerSenderPtrInfo0 = new mojo.AssociatedInterfacePtrInfo();
-  var integerSenderRequest0 = mojo.makeRequest(integerSenderPtrInfo0);
-
-  var integerSender0 = new mojo.test.IntegerSenderAssociatedPtr(
-      integerSenderPtrInfo0);
-
-  integerSenderConnection.getSender(integerSenderRequest0);
-  assert_equals((await integerSender0.echo(123)).value, 123);
-
-  // Recieving AssociatedInterfacePtrInfo.
-  var integerSenderPtrInfo1 =
-      (await integerSenderConnection.asyncGetSender()).sender;
-  var integerSender1 = new mojo.test.IntegerSenderAssociatedPtr(
-      integerSenderPtrInfo1);
-  assert_equals((await integerSender1.echo(456)).value, 456);
-}, 'pass associated interfaces');
-
-// Bind to the same pipe two associated interfaces, whose implementation
-// lives at different ends. Test that the two don't interfere.
-promise_test(async () => {
-  var integerSenderConnectionAtBothEnds = new
-      mojo.test.IntegerSenderConnectionAtBothEndsPtr();
-  var integerSenderConnectionAtBothEndsBinding = new mojo.Binding(
-      mojo.test.IntegerSenderConnectionAtBothEnds,
-      new IntegerSenderConnectionAtBothEndsImpl(),
-      mojo.makeRequest(integerSenderConnectionAtBothEnds));
-
-  // Associated Interface whose Binding Impl lives on the other side.
-  // Sending AssociatedInterfaceRequest.
-  var integerSenderPtrInfo0 = new mojo.AssociatedInterfacePtrInfo();
-  var integerSenderRequest0 = mojo.makeRequest(integerSenderPtrInfo0);
-
-  var integerSender0 = new mojo.test.IntegerSenderAssociatedPtr(
-      integerSenderPtrInfo0);
-
-  integerSenderConnectionAtBothEnds.getSender(integerSenderRequest0);
-  assert_equals((await integerSender0.echo(123)).value, 123);
-
-  // Associated Interface whose Binding Impl lives on this side.
-  // Sending AssociatedInterfacePtrInfo.
-  var integerSenderPtrInfo1 = new mojo.AssociatedInterfacePtrInfo();
-  var integerSenderRequest1 = mojo.makeRequest(integerSenderPtrInfo1);
-
-  var integerSenderBinding = new mojo.AssociatedBinding(
-      mojo.test.IntegerSender, new IntegerSenderImpl(),
-      integerSenderRequest1);
-
-  assert_equals((await integerSenderConnectionAtBothEnds.setSender(
-      integerSenderPtrInfo1)).value, 456);
-}, 'associated interfaces on both ends');
-
-promise_test(async () => {
-  var integerSenderConnection = new mojo.test.IntegerSenderConnectionPtr();
-  var integerSenderConnectionBinding = new mojo.Binding(
-      mojo.test.IntegerSenderConnection,
-      new IntegerSenderConnectionImplWithConnectionError(),
-      mojo.makeRequest(integerSenderConnection));
-
-  // Sending AssociatedInterfaceRequest.
-  var integerSenderPtrInfo0 = new mojo.AssociatedInterfacePtrInfo();
-  var integerSenderRequest0 = mojo.makeRequest(integerSenderPtrInfo0);
-
-  var integerSender0 = new mojo.test.IntegerSenderAssociatedPtr(
-          integerSenderPtrInfo0);
-
-  integerSenderConnection.getSender(integerSenderRequest0);
-  await new Promise((resolve, reject) => {
-    integerSender0.ptr.setConnectionErrorHandler(function({customReason,
-        description}) {
-      assert_equals(customReason, 42);
-      assert_equals(description, 'hey');
-      resolve();
-    });
-  });
-}, 'connection error with reason');
-
-// Test that AssociatedInterfacePtr is notified with connection error when
-// the interface hasn't associated with a message pipe and the peer is
-// closed.
-promise_test(async () => {
-  var integerSenderPtrInfo = new mojo.AssociatedInterfacePtrInfo();
-  var integerSenderRequest = mojo.makeRequest(integerSenderPtrInfo);
-
-  var integerSender = new mojo.test.IntegerSenderAssociatedPtr(
-      integerSenderPtrInfo);
-
-  await new Promise((resolve, reject) => {
-    integerSender.ptr.setConnectionErrorHandler(function({customReason,
-        description}) {
-      assert_equals(customReason, 42);
-      assert_equals(description, 'hey');
-      resolve();
-    });
-    integerSenderRequest.resetWithReason({customReason: 42,
-        description: 'hey'})
-  });
-}, 'pending AssociatedInterfacePtr connection error with reason');
-
-promise_test(async () => {
-  var integerSenderConnection = new mojo.test.IntegerSenderConnectionPtr();
-  var integerSenderConnectionBinding = new mojo.Binding(
-      mojo.test.IntegerSenderConnection, new IntegerSenderConnectionImpl(),
-      mojo.makeRequest(integerSenderConnection));
-
-  // Sending AssociatedInterfaceRequest.
-  var integerSenderPtrInfo0 = new mojo.AssociatedInterfacePtrInfo();
-  var integerSenderRequest0 = mojo.makeRequest(integerSenderPtrInfo0);
-  var integerSender0 = new mojo.test.IntegerSenderAssociatedPtr(
-      integerSenderPtrInfo0);
-  integerSenderConnection.getSender(integerSenderRequest0);
-
-  // Recieving AssociatedInterfacePtrInfo.
-  var integerSenderPtrInfo1 =
-      (await integerSenderConnection.asyncGetSender()).sender;
-  var integerSender1 = new mojo.test.IntegerSenderAssociatedPtr(
-      integerSenderPtrInfo1);
-
-  // Master InterfacePtrController reset triggers connection error handler on
-  // interface endpoint clients for all associated endpoints.
-  var connectionErrorHandler0 = new Promise((resolve, reject) => {
-    integerSender0.ptr.setConnectionErrorHandler(() => {
-      resolve();
-    });
-  });
-
-  var connectionErrorHandler1 = new Promise((resolve, reject) => {
-    integerSender1.ptr.setConnectionErrorHandler(() => {
-      resolve();
-    });
-  });
-
-  setTimeout(integerSenderConnection.ptr.reset.bind(
-      integerSenderConnection.ptr), 0);
-  await Promise.all([connectionErrorHandler0, connectionErrorHandler1]);
-}, 'all endpoints connectionErrorHandler called on master interface reset');
-
-// Cache the current message and pause processing incoming messages if
-// endpoint does not have client attached yet to ensure fifo message arrival.
-promise_test(async () => {
-  var senderConnection = new mojo.test.SenderConnectionPtr();
-  var senderConnectionBindLaterImpl = new SenderConnectionBindLaterImpl();
-  var senderConnectionBinding = new mojo.Binding(
-      mojo.test.SenderConnection, senderConnectionBindLaterImpl,
-      mojo.makeRequest(senderConnection));
-
-  // AssociatedInterfaceRequest for stringSender.
-  var stringSenderPtrInfo = new mojo.AssociatedInterfacePtrInfo();
-  var stringSenderRequest = mojo.makeRequest(stringSenderPtrInfo);
-  var stringSender = new mojo.test.StringSenderAssociatedPtr(
-      stringSenderPtrInfo);
-
-  // AssociatedInterfaceRequest for integerSender.
-  var integerSenderPtrInfo = new mojo.AssociatedInterfacePtrInfo();
-  var integerSenderRequest = mojo.makeRequest(integerSenderPtrInfo);
-  var integerSender = new mojo.test.IntegerSenderAssociatedPtr(
-      integerSenderPtrInfo);
-
-  var value = await new Promise(function(resolve, reject) {
-    senderConnectionBindLaterImpl.getIntegerSenderCallback = resolve;
-    senderConnectionBindLaterImpl.getStringSenderCallback= reject;
-    senderConnection.getStringSender(stringSenderRequest);
-    senderConnection.getIntegerSender(integerSenderRequest);
-    // Test FIFO arrival order of message.
-    integerSender.send(456); // This message should arrive first.
-    stringSender.send('goodbye');
-  });
-
-  assert_equals(value, 456);
-}, 'fifo order should be preserved for messages');
-
-promise_test(async () => {
-  var senderConnection = new mojo.test.SenderConnectionPtr();
-  var senderConnectionImpl = new SenderConnectionImpl();
-  var senderConnectionBinding = new mojo.Binding(
-      mojo.test.SenderConnection, senderConnectionImpl,
-      mojo.makeRequest(senderConnection));
-
-  // AssociatedInterfaceRequest for stringSender.
-  var stringSenderPtrInfo = new mojo.AssociatedInterfacePtrInfo();
-  var stringSenderRequest = mojo.makeRequest(stringSenderPtrInfo);
-  var stringSender = new mojo.test.StringSenderAssociatedPtr(
-      stringSenderPtrInfo);
-
-  // AssociatedInterfaceRequest for integerSender.
-  var integerSenderPtrInfo = new mojo.AssociatedInterfacePtrInfo();
-  var integerSenderRequest = mojo.makeRequest(integerSenderPtrInfo);
-  var integerSender = new mojo.test.IntegerSenderAssociatedPtr(
-      integerSenderPtrInfo);
-
-  var value = await new Promise(function(resolve, reject) {
-    senderConnectionImpl.getIntegerSenderCallback = reject;
-    senderConnectionImpl.getStringSenderCallback= resolve;
-    senderConnection.getStringSender(stringSenderRequest);
-    senderConnection.getIntegerSender(integerSenderRequest);
-
-    // Wait for integerSenderBinding to be created.
-    integerSender.echo(100).then(function(result) {
-      assert_equals(result.value, 100);
-
-      // This causes this endpoint handle's endpoint client to be detached.
-      var handle = senderConnectionImpl.integerSenderBinding_.
-          interfaceEndpointClient_.passHandle();
-
-      // Cache message. Connector will pause processing incoming messages.
-      integerSender.send(456);
-      stringSender.send('goodbye');
-
-      // Closing the target endpoint handle of the cached message will cause
-      // the cached message to be discarded and the connector to resume
-      // processing incoming messages.
-      setTimeout(handle.reset.bind(handle), 0);
-    });
-  });
-
-  assert_equals(value, 'goodbye');
-}, 'discard cached message if target endpoint closed');
-
-</script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/bind-interface.html b/third_party/blink/web_tests/http/tests/mojo/bind-interface.html
index a248f36..5e8fe018 100644
--- a/third_party/blink/web_tests/http/tests/mojo/bind-interface.html
+++ b/third_party/blink/web_tests/http/tests/mojo/bind-interface.html
@@ -2,112 +2,102 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/content/test/data/mojo_web_test_helper_test.mojom.js"></script>
-<script src="resources/helpers.js"></script>
-<script>
-
-promise_test(() => {
-  let helper = new content.mojom.MojoWebTestHelperPtr;
-  Mojo.bindInterface(content.mojom.MojoWebTestHelper.name,
-                     mojo.makeRequest(helper).handle);
-
-  const kTestMessage = "hello world.";
-  const kExpectedReply = ".dlrow olleh";
-  return helper.reverse(kTestMessage).then(reply => {
-    assert_equals(reply.reversed, kExpectedReply);
-  });
-}, "can bind interfaces");
-
-promise_test(() => {
-  let helperImpl = new TestHelperImpl;
-  let interceptor =
-      new MojoInterfaceInterceptor(content.mojom.MojoWebTestHelper.name);
-  interceptor.oninterfacerequest = e => {
-    helperImpl.bindRequest(e.handle);
-  };
-  interceptor.start();
-
-  let helper = new content.mojom.MojoWebTestHelperPtr;
-  Mojo.bindInterface(content.mojom.MojoWebTestHelper.name,
-                     mojo.makeRequest(helper).handle);
-  interceptor.stop();
-
-  return helper.reverse("doesn't matter").then(reply => {
-    assert_equals(reply.reversed, kTestReply);
-  });
-}, "can intercept calls to bindInterface");
+<script type="module">
+import {MojoWebTestHelper, MojoWebTestHelperRemote} from '/gen/content/test/data/mojo_web_test_helper_test.mojom.m.js';
+import {kTestReply, TestHelperImpl} from './resources/helpers.js';
 
 promise_test(async () => {
-  // Intercept this interface at "context" scope to check that it is being
-  // requested at "process" scope.
-  let helperImpl = new TestHelperImpl;
+  let helper = new MojoWebTestHelperRemote();
+  helper.$.bindNewPipeAndPassReceiver().bindInBrowser();
+
+  const kTestMessage = 'hello world.';
+  const kExpectedReply = '.dlrow olleh';
+  const {reversed} = await helper.reverse(kTestMessage);
+  assert_equals(reversed, kExpectedReply);
+}, 'can bind interfaces');
+
+promise_test(async () => {
+  let helperImpl = new TestHelperImpl();
   let interceptor =
-      new MojoInterfaceInterceptor(content.mojom.MojoWebTestHelper.name);
+      new MojoInterfaceInterceptor(MojoWebTestHelper.$interfaceName);
   interceptor.oninterfacerequest = e => {
     helperImpl.bindRequest(e.handle);
   };
   interceptor.start();
 
-  let helper = new content.mojom.MojoWebTestHelperPtr;
-  Mojo.bindInterface(content.mojom.MojoWebTestHelper.name,
-                     mojo.makeRequest(helper).handle,
-                     "process");
+  let helper = new MojoWebTestHelperRemote();
+  helper.$.bindNewPipeAndPassReceiver().bindInBrowser();
+  interceptor.stop();
 
-  const kTestMessage = "hello world.";
-  const kExpectedReply = ".dlrow olleh";
-  await helper.reverse(kTestMessage).then(reply => {
-    assert_equals(reply.reversed, kExpectedReply);
-  });
+  const {reversed} = await helper.reverse("doesn't matter");
+  assert_equals(reversed, kTestReply);
+}, 'can intercept calls to bindInterface');
+
+promise_test(async () => {
+  // Intercept this interface at 'context' scope to check that it is being
+  // requested at 'process' scope.
+  let helperImpl = new TestHelperImpl();
+  let interceptor =
+      new MojoInterfaceInterceptor(MojoWebTestHelper.$interfaceName);
+  interceptor.oninterfacerequest = e => {
+    helperImpl.bindRequest(e.handle);
+  };
+  interceptor.start();
+
+  let helper = new MojoWebTestHelperRemote();
+  helper.$.bindNewPipeAndPassReceiver().bindInBrowser('process');
+
+  const kTestMessage = 'hello world.';
+  const kExpectedReply = '.dlrow olleh';
+  const {reversed} = await helper.reverse(kTestMessage);
+  assert_equals(reversed, kExpectedReply);
 
   interceptor.stop();
-}, "can request interfaces at process scope");
+}, 'can request interfaces at process scope');
 
-promise_test(() => {
-  let helperImpl = new TestHelperImpl;
+promise_test(async () => {
+  let helperImpl = new TestHelperImpl();
   let interceptor = new MojoInterfaceInterceptor(
-      content.mojom.MojoWebTestHelper.name, "process");
+      MojoWebTestHelper.$interfaceName, 'process');
   interceptor.oninterfacerequest = e => {
     helperImpl.bindRequest(e.handle);
   };
   interceptor.start();
 
-  let helper = new content.mojom.MojoWebTestHelperPtr;
-  Mojo.bindInterface(content.mojom.MojoWebTestHelper.name,
-                     mojo.makeRequest(helper).handle,
-                     "process");
+  let helper = new MojoWebTestHelperRemote();
+  helper.$.bindNewPipeAndPassReceiver().bindInBrowser('process');
   interceptor.stop();
 
-  return helper.reverse("doesn't matter").then(reply => {
-    assert_equals(reply.reversed, kTestReply);
-  });
-}, "can intercept interfaces at process scope");
+  const {reversed} = await helper.reverse("doesn't matter");
+  assert_equals(reversed, kTestReply);
+}, 'can intercept interfaces at process scope');
 
 test(() => {
-  let a = new MojoInterfaceInterceptor(content.mojom.MojoWebTestHelper.name);
-  let b = new MojoInterfaceInterceptor(content.mojom.MojoWebTestHelper.name);
+  let a = new MojoInterfaceInterceptor(MojoWebTestHelper.$interfaceName);
+  let b = new MojoInterfaceInterceptor(MojoWebTestHelper.$interfaceName);
   a.oninterfacerequest = () => {};
   b.oninterfacerequest = () => {};
   a.start();
   assert_throws_dom('InvalidModificationError', () => { b.start(); });
   a.stop();
-}, "interface interceptors are mutually exclusive");
+}, 'interface interceptors are mutually exclusive');
 
 test(() => {
-  let a = new MojoInterfaceInterceptor(content.mojom.MojoWebTestHelper.name,
-                                       "process");
-  let b = new MojoInterfaceInterceptor(content.mojom.MojoWebTestHelper.name,
-                                       "process");
+  let a = new MojoInterfaceInterceptor(
+      MojoWebTestHelper.$interfaceName, 'process');
+  let b = new MojoInterfaceInterceptor(
+      MojoWebTestHelper.$interfaceName, 'process');
   a.oninterfacerequest = () => {};
   b.oninterfacerequest = () => {};
   a.start();
   assert_throws_dom('InvalidModificationError', () => { b.start(); });
   a.stop();
-}, "process scope interface interceptors are mutually exclusive");
+}, 'process scope interface interceptors are mutually exclusive');
 
 promise_test(async t => {
   // First check that the interceptor can be started and intercepts requests.
   let interceptor =
-      new MojoInterfaceInterceptor(content.mojom.MojoWebTestHelper.name);
+      new MojoInterfaceInterceptor(MojoWebTestHelper.$interfaceName);
   let promise = new Promise(resolve => {
     interceptor.oninterfacerequest = e => {
       resolve(e.handle);
@@ -116,7 +106,7 @@
   interceptor.start();
 
   let pipe = Mojo.createMessagePipe();
-  Mojo.bindInterface(content.mojom.MojoWebTestHelper.name, pipe.handle0);
+  Mojo.bindInterface(MojoWebTestHelper.$interfaceName, pipe.handle0);
   let interceptedHandle = await promise;
   assert_true(interceptedHandle instanceof MojoHandle);
   interceptedHandle.close();
@@ -125,27 +115,25 @@
   // Stop the interceptor and make another request.
   interceptor.stop();
 
-  let helper = new content.mojom.MojoWebTestHelperPtr;
+  let helper = new MojoWebTestHelperRemote();
   interceptor.oninterfacerequest = t.step_func(() => {
-    assert_unreached("unexpected 'interfacerequest' event after stop");
+    assert_unreached('unexpected "interfacerequest" event after stop');
   });
-  Mojo.bindInterface(content.mojom.MojoWebTestHelper.name,
-                     mojo.makeRequest(helper).handle);
+  helper.$.bindNewPipeAndPassReceiver().bindInBrowser();
 
   // Enusre that the interface is functioning, i.e. the request definitely was
   // not intercepted.
-  await helper.reverse("abc").then(reply => {
-    assert_equals(reply.reversed, "cba");
-  });
+  const {reversed} = await helper.reverse('abc');
+  assert_equals(reversed, 'cba');
   pipe.handle1.close();
 
   // And ensure that we can start a new interceptor for the same interface since
   // the previous one was stopped.
   interceptor =
-      new MojoInterfaceInterceptor(content.mojom.MojoWebTestHelper.name);
+      new MojoInterfaceInterceptor(MojoWebTestHelper.$interfaceName);
   interceptor.oninterfacerequest = e => {};
   interceptor.start();
   interceptor.stop();
-}, "interceptors cancel properly");
+}, 'interceptors cancel properly');
 
 </script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/binding.html b/third_party/blink/web_tests/http/tests/mojo/binding.html
deleted file mode 100644
index 18129f6..0000000
--- a/third_party/blink/web_tests/http/tests/mojo/binding.html
+++ /dev/null
@@ -1,118 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/math_calculator.mojom.js"></script>
-<script>
-'use strict';
-
-function CalculatorImpl() {
-  this.total = 0;
-}
-
-CalculatorImpl.prototype.clear = function() {
-  this.total = 0;
-  return Promise.resolve({value: this.total});
-};
-
-CalculatorImpl.prototype.add = function(value) {
-  this.total += value;
-  return Promise.resolve({value: this.total});
-};
-
-CalculatorImpl.prototype.multiply = function(value) {
-  this.total *= value;
-  return Promise.resolve({value: this.total});
-};
-
-test(() => {
-  var binding = new mojo.Binding(math.Calculator, new CalculatorImpl());
-  assert_false(binding.isBound());
-
-  var calc = new math.CalculatorPtr();
-  var request = mojo.makeRequest(calc);
-  binding.bind(request);
-  assert_true(binding.isBound());
-
-  binding.close();
-  assert_false(binding.isBound());
-}, 'is bound');
-
-promise_test(async () => {
-  var calc1 = new math.CalculatorPtr();
-  var calcBinding = new mojo.Binding(math.Calculator, new CalculatorImpl(),
-                                     mojo.makeRequest(calc1));
-  assert_equals((await calc1.add(2)).value, 2);
-
-  var calc2 = new math.CalculatorPtr();
-  calcBinding.bind(mojo.makeRequest(calc2));
-  assert_equals((await calc2.add(2)).value, 4);
-}, 'reusable');
-
-promise_test(async () => {
-  var calc = new math.CalculatorPtr();
-  var calcBinding = new mojo.Binding(math.Calculator, new CalculatorImpl(),
-                                     mojo.makeRequest(calc));
-
-  await new Promise((resolve, reject) => {
-    calcBinding.setConnectionErrorHandler(() => { resolve(); });
-    calc.ptr.reset();
-  });
-}, 'connection error');
-
-promise_test(async () => {
-  var calc = new math.CalculatorPtr();
-  var calcBinding = new mojo.Binding(math.Calculator, new CalculatorImpl(),
-                                     mojo.makeRequest(calc));
-
-  await new Promise((resolve, reject) => {
-    calcBinding.setConnectionErrorHandler(({customReason, description}) => {
-      assert_equals(customReason, 32);
-      assert_equals(description, 'goodbye');
-      resolve();
-    });
-    calc.ptr.resetWithReason({customReason: 32, description: 'goodbye'});
-  });
-}, 'connection error with reason');
-
-promise_test(async () => {
-  var calc = new math.CalculatorPtr();
-  var calcBinding = new mojo.Binding(math.Calculator, new CalculatorImpl(),
-                                     mojo.makeRequest(calc));
-  assert_equals((await calc.add(2)).value, 2);
-
-  var interfaceRequest = calcBinding.unbind();
-  assert_false(calcBinding.isBound());
-
-  var newCalcBinding = new mojo.Binding(math.Calculator, new CalculatorImpl(),
-                                        interfaceRequest);
-  assert_equals((await calc.add(2)).value, 2);
-}, 'unbind');
-
-promise_test(async () => {
-  var calc1 = new math.CalculatorPtr();
-  var calc2 = new math.CalculatorPtr();
-  var calcImpl = new CalculatorImpl();
-
-  var bindingSet = new mojo.BindingSet(math.Calculator);
-  assert_true(bindingSet.isEmpty());
-
-  bindingSet.addBinding(calcImpl, mojo.makeRequest(calc1));
-  bindingSet.addBinding(calcImpl, mojo.makeRequest(calc2));
-  assert_false(bindingSet.isEmpty());
-
-  assert_equals((await calc1.add(3)).value, 3);
-  assert_equals((await calc2.add(4)).value, 7);
-
-  await new Promise((resolve, reject) => {
-    bindingSet.setConnectionErrorHandler(() => { resolve(); });
-    calc1.ptr.reset();
-  });
-
-  assert_equals((await calc2.add(5)).value, 12);
-
-  bindingSet.closeAllBindings();
-  assert_true(bindingSet.isEmpty());
-}, 'binding set');
-
-</script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/bindings-tests.js b/third_party/blink/web_tests/http/tests/mojo/bindings-tests.js
deleted file mode 100644
index 4fbba4c6..0000000
--- a/third_party/blink/web_tests/http/tests/mojo/bindings-tests.js
+++ /dev/null
@@ -1,396 +0,0 @@
-import {
-  TestMessageTargetReceiver,
-  TestMessageTarget_NestedEnum,
-  TestMessageTarget,
-  TestMessageTargetCallbackRouter,
-  SubinterfaceCallbackRouter,
-  SubinterfaceClientCallbackRouter,
-  SubinterfaceRemote}
-    from '/gen/content/test/data/mojo_bindings_web_test.test-mojom.m.js';
-import {MojoEcho, MojoEchoRemote}
-    from '/gen/content/web_test/common/mojo_echo.mojom.m.js';
-
-const kTestMessage = 'hello there';
-const kTestNumbers = [0, 1, 1, 2, 3, 5, 8, 13, 21];
-
-class TargetImpl {
-  constructor() {
-    this.numPokes = 0;
-    this.target = new TestMessageTargetReceiver(this);
-  }
-
-  poke() { this.numPokes++; }
-  ping() { return Promise.resolve(); }
-  repeat(message, numbers) { return {message: message, numbers: numbers}; }
-  echo(nested) { return Promise.resolve({nested: nested}); }
-  deconstruct(test_struct) {}
-  flatten(values) {}
-  flattenUnions(unions) {}
-  requestSubinterface(request, client) {}
-}
-
-promise_test(() => {
-  let impl = new TargetImpl;
-  let remote = impl.target.$.bindNewPipeAndPassRemote();
-  remote.poke();
-  return remote.ping().then(() => {
-    assert_equals(impl.numPokes, 1);
-  });
-}, 'messages with replies return Promises that resolve on reply received');
-
-promise_test(() => {
-  let impl = new TargetImpl;
-  let remote = impl.target.$.bindNewPipeAndPassRemote();
-  return remote.repeat(kTestMessage, kTestNumbers)
-               .then(reply => {
-                 assert_equals(reply.message, kTestMessage);
-                 assert_array_equals(reply.numbers, kTestNumbers);
-               });
-}, 'implementations can reply with multiple reply arguments');
-
-promise_test(() => {
-  let impl = new TargetImpl;
-  let remote = impl.target.$.bindNewPipeAndPassRemote();
-  const enumValue = TestMessageTarget_NestedEnum.kFoo;
-  return remote.echo(enumValue)
-               .then(({nested}) => assert_equals(nested, enumValue));
-}, 'nested enums are usable as arguments and responses.');
-
-promise_test(async (t) => {
-  const impl = new TargetImpl;
-  const remote = impl.target.$.bindNewPipeAndPassRemote();
-
-  await remote.ping();
-  remote.$.close();
-
-  await promise_rejects_js(t, Error, remote.ping());
-}, 'after the pipe is closed all future calls should fail');
-
-promise_test(async (t) => {
-  const impl = new TargetImpl;
-  const remote = impl.target.$.bindNewPipeAndPassRemote();
-
-  // None of these promises should successfully resolve because we are
-  // immediately closing the pipe.
-  const promises = []
-  for (let i = 0; i < 10; i++) {
-    promises.push(remote.ping());
-  }
-
-  remote.$.close();
-
-  for (const promise of promises) {
-    await promise_rejects_js(t, Error, promise);
-  }
-}, 'closing the pipe drops any pending messages');
-
-promise_test(() => {
-  let impl = new TargetImpl;
-
-  // Intercept any browser-bound request for TestMessageTarget and bind it
-  // instead to the local |impl| object.
-  let interceptor = new MojoInterfaceInterceptor(
-      TestMessageTarget.$interfaceName);
-  interceptor.oninterfacerequest = e => {
-    impl.target.$.bindHandle(e.handle);
-  }
-  interceptor.start();
-
-  let remote = TestMessageTarget.getRemote();
-  remote.poke();
-  return remote.ping().then(() => {
-    assert_equals(impl.numPokes, 1);
-  });
-}, 'getRemote() attempts to send requests to the frame host');
-
-promise_test(() => {
-  let router = new TestMessageTargetCallbackRouter;
-  let remote = router.$.bindNewPipeAndPassRemote();
-  return new Promise(resolve => {
-    router.poke.addListener(resolve);
-    remote.poke();
-  });
-}, 'basic generated CallbackRouter behavior works as intended');
-
-promise_test(() => {
-  let router = new TestMessageTargetCallbackRouter;
-  let remote = router.$.bindNewPipeAndPassRemote();
-  let numPokes = 0;
-  router.poke.addListener(() => ++numPokes);
-  router.ping.addListener(() => Promise.resolve());
-  remote.poke();
-  return remote.ping().then(() => assert_equals(numPokes, 1));
-}, 'CallbackRouter listeners can reply to messages');
-
-promise_test(() => {
-  let router = new TestMessageTargetCallbackRouter;
-  let remote = router.$.bindNewPipeAndPassRemote();
-  router.repeat.addListener(
-    (message, numbers) => ({message: message, numbers: numbers}));
-  return remote.repeat(kTestMessage, kTestNumbers)
-               .then(reply => {
-                 assert_equals(reply.message, kTestMessage);
-                 assert_array_equals(reply.numbers, kTestNumbers);
-               });
-}, 'CallbackRouter listeners can reply with multiple reply arguments');
-
-promise_test(() => {
-  let targetRouter = new TestMessageTargetCallbackRouter;
-  let targetRemote = targetRouter.$.bindNewPipeAndPassRemote();
-  let subinterfaceRouter = new SubinterfaceCallbackRouter;
-  targetRouter.requestSubinterface.addListener((request, client) => {
-    let values = [];
-    subinterfaceRouter.$.bindHandle(request.handle);
-    subinterfaceRouter.push.addListener(value => values.push(value));
-    subinterfaceRouter.flush.addListener(() => {
-      client.didFlush(values);
-      values = [];
-    });
-  });
-
-  let clientRouter = new SubinterfaceClientCallbackRouter;
-  let subinterfaceRemote = new SubinterfaceRemote;
-  targetRemote.requestSubinterface(
-    subinterfaceRemote.$.bindNewPipeAndPassReceiver(),
-    clientRouter.$.bindNewPipeAndPassRemote());
-  return new Promise(resolve => {
-    clientRouter.didFlush.addListener(values => {
-      assert_array_equals(values, kTestNumbers);
-      resolve();
-    });
-
-    kTestNumbers.forEach(n => subinterfaceRemote.push(n));
-    subinterfaceRemote.flush();
-  });
-}, 'can send and receive interface requests and proxies');
-
-promise_test(() => {
-  const targetRouter = new TestMessageTargetCallbackRouter;
-  const targetRemote = targetRouter.$.bindNewPipeAndPassRemote();
-  targetRouter.deconstruct.addListener(({x, y, z}) => ({
-    x: x,
-    y: y,
-    z: z
-  }));
-
-  return targetRemote.deconstruct({x: 1}).then(reply => {
-    assert_equals(reply.x, 1);
-    assert_equals(reply.y, 2);
-    assert_equals(reply.z, 1);
-  });
-}, 'structs with default values from nested enums and constants are ' +
-   'correctly serialized');
-
-promise_test(() => {
-  const targetRouter = new TestMessageTargetCallbackRouter;
-  const targetRemote = targetRouter.$.bindNewPipeAndPassRemote();
-  targetRouter.flatten.addListener(values => ({values: values.map(v => v.x)}));
-  return targetRemote.flatten([{x: 1}, {x: 2}, {x: 3}]).then(reply => {
-    assert_array_equals(reply.values, [1, 2, 3]);
-  });
-}, 'regression test for complex array serialization');
-
-promise_test(() => {
-  const targetRouter = new TestMessageTargetCallbackRouter;
-  const targetRemote = targetRouter.$.bindNewPipeAndPassRemote();
-  targetRouter.flattenUnions.addListener(unions => {
-    return {x: unions.filter(u => u.x !== undefined).map(u => u.x),
-            s: unions.filter(u => u.s !== undefined).map(u => u.s.x)};
-  });
-
-  return targetRemote.flattenUnions(
-    [{x: 1}, {x: 2}, {s: {x: 3}}, {s: {x: 4}}, {x: 5}, {s: {x: 6}}])
-                     .then(reply => {
-                       assert_array_equals(reply.x, [1, 2, 5]);
-                       assert_array_equals(reply.s, [3, 4, 6]);
-                     });
-}, 'can serialize and deserialize unions');
-
-promise_test(() => {
-  let impl = new TargetImpl;
-  let remote = impl.target.$.bindNewPipeAndPassRemote();
-
-  // Poke a bunch of times. These should never race with the assertion below,
-  // because the |flushForTesting| request/response is ordered against other
-  // messages on |remote|.
-  const kNumPokes = 100;
-  for (let i = 0; i < kNumPokes; ++i)
-    remote.poke();
-  return remote.$.flushForTesting().then(() => {
-    assert_equals(impl.numPokes, kNumPokes);
-  });
-}, 'can use generated flushForTesting API for synchronization in tests');
-
-promise_test(async(t) => {
-  const impl = new TargetImpl;
-  const remote = impl.target.$.bindNewPipeAndPassRemote();
-  const disconnectPromise = new Promise(resolve => impl.target.onConnectionError.addListener(resolve));
-  remote.$.close();
-  return disconnectPromise;
-}, 'InterfaceTarget connection error handler runs when set on an Interface object');
-
-promise_test(() => {
-  const router = new TestMessageTargetCallbackRouter;
-  const remote = router.$.bindNewPipeAndPassRemote();
-  const disconnectPromise = new Promise(resolve => router.onConnectionError.addListener(resolve));
-  remote.$.close();
-  return disconnectPromise;
-}, 'InterfaceTarget connection error handler runs when set on an InterfaceCallbackRouter object');
-
-function getMojoEchoRemote() {
-  // MojoEchoRemote.getRemote() only works for frame interfaces
-  // and MojoEcho is a process interface.
-  let remote = new MojoEchoRemote;
-  remote.$.bindNewPipeAndPassReceiver().bindInBrowser('process');
-  return remote;
-}
-
-promise_test(async () => {
-  const remote = getMojoEchoRemote();
-  {
-    const {value} = await remote.echoBoolFromUnion({boolValue: true});
-    assert_true(value);
-  }
-  {
-    const {value} = await remote.echoInt32FromUnion({int32Value: 123});
-    assert_equals(value, 123);
-  }
-  {
-    const {value} = await remote.echoStringFromUnion({stringValue: "foo"});
-    assert_equals(value, "foo");
-  }
-}, 'JS encoding and C++ decoding of unions work as expected.');
-
-promise_test(async() => {
-  const remote = getMojoEchoRemote();
-  {
-    const {testUnion: {boolValue}} = await remote.echoBoolAsUnion(true);
-    assert_equals(boolValue, true);
-  }
-  {
-    const {testUnion: {int32Value}} = await remote.echoInt32AsUnion(123);
-    assert_equals(int32Value, 123);
-  }
-  {
-    const {testUnion: {stringValue}} = await remote.echoStringAsUnion("foo");
-    assert_equals(stringValue, "foo");
-  }
-
-}, 'JS decoding and C++ encoding of unions work as expected.');
-
-promise_test(async () => {
-  const remote = getMojoEchoRemote();
-  {
-    const response = await remote.echoNullFromOptionalUnion();
-    assert_equals(Object.keys(response).length, 0);
-  }
-  {
-    const {value} = await remote.echoBoolFromOptionalUnion({boolValue: true});
-    assert_true(value);
-  }
-  {
-    const {value} = await remote.echoInt32FromOptionalUnion({int32Value: 123});
-    assert_equals(value, 123);
-  }
-  {
-    const {value} = await remote.echoStringFromOptionalUnion({stringValue: "foo"});
-    assert_equals(value, "foo");
-  }
-}, 'JS encoding and C++ decoding of optional unions work as expected.');
-
-promise_test(async() => {
-  const remote = getMojoEchoRemote();
-  {
-    const {testUnion} = await remote.echoNullAsOptionalUnion();
-    assert_equals(testUnion, null);
-  }
-  {
-    const {testUnion: {boolValue}} = await remote.echoBoolAsOptionalUnion(true);
-    assert_equals(boolValue, true);
-  }
-  {
-    const {testUnion: {int32Value}} = await remote.echoInt32AsOptionalUnion(123);
-    assert_equals(int32Value, 123);
-  }
-  {
-    const {testUnion: {stringValue}} =
-      await remote.echoStringAsOptionalUnion("foo");
-    assert_equals(stringValue, "foo");
-  }
-
-}, 'JS decoding and C++ encoding of optional unions work as expected.');
-
-promise_test(async() => {
-  const remote = getMojoEchoRemote();
-  {
-    const {value} = await remote.echoInt8FromNestedUnion({int8Value: -10});
-    assert_equals(value, -10);
-  }
-  {
-    const {value} = await remote.echoBoolFromNestedUnion({unionValue: {boolValue: true}});
-    assert_true(value);
-  }
-  {
-    const {value} = await remote.echoStringFromNestedUnion({unionValue: {stringValue: 'foo'}});
-    assert_equals(value, 'foo');
-  }
-}, 'JS encoding and C++ decoding of nested unions work as expected.');
-
-promise_test(async() => {
-  const remote = getMojoEchoRemote();
-  {
-    const {testUnion: {int8Value}} = await remote.echoInt8AsNestedUnion(-10);
-    assert_equals(int8Value, -10);
-  }
-  {
-    const {testUnion: {unionValue: {boolValue}}} = await remote.echoBoolAsNestedUnion(true);
-    assert_true(boolValue);
-  }
-  {
-    const {testUnion: {unionValue: {stringValue}}} =
-      await remote.echoStringAsNestedUnion('foo');
-    assert_equals(stringValue, 'foo');
-  }
-}, 'JS decoding and C++ encoding of nested unions work as expected.');
-
-promise_test(async() => {
-  const remote = getMojoEchoRemote();
-  {
-    const response = await remote.echoNullFromOptionalNestedUnion();
-    assert_equals(Object.keys(response).length, 0);
-  }
-  {
-    const {value} = await remote.echoInt8FromOptionalNestedUnion({int8Value: -10});
-    assert_equals(value, -10);
-  }
-  {
-    const {value} = await remote.echoBoolFromOptionalNestedUnion({unionValue: {boolValue: true}});
-    assert_true(value);
-  }
-  {
-    const {value} = await remote.echoStringFromOptionalNestedUnion({unionValue: {stringValue: 'foo'}});
-    assert_equals(value, 'foo');
-  }
-}, 'JS encoding and C++ decoding of optional nested unions work as expected.');
-
-promise_test(async() => {
-  const remote = getMojoEchoRemote();
-  {
-    const {testUnion} = await remote.echoNullAsOptionalNestedUnion();
-    assert_equals(testUnion, null);
-  }
-  {
-    const {testUnion: {int8Value}} = await remote.echoInt8AsOptionalNestedUnion(-10);
-    assert_equals(int8Value, -10);
-  }
-  {
-    const {testUnion: {unionValue: {boolValue}}} =
-      await remote.echoBoolAsOptionalNestedUnion(true);
-    assert_true(boolValue);
-  }
-  {
-    const {testUnion: {unionValue: {stringValue}}} =
-      await remote.echoStringAsOptionalNestedUnion('foo');
-    assert_equals(stringValue, 'foo');
-  }
-}, 'JS decoding and C++ encoding of optional nested unions work as expected.');
diff --git a/third_party/blink/web_tests/http/tests/mojo/bindings.html b/third_party/blink/web_tests/http/tests/mojo/bindings.html
index 7afd5f2..87144e0 100644
--- a/third_party/blink/web_tests/http/tests/mojo/bindings.html
+++ b/third_party/blink/web_tests/http/tests/mojo/bindings.html
@@ -1,4 +1,401 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="./bindings-tests.js" type="module"></script>
+<script type="module">
+import {
+  TestMessageTargetReceiver,
+  TestMessageTarget_NestedEnum,
+  TestMessageTarget,
+  TestMessageTargetCallbackRouter,
+  SubinterfaceCallbackRouter,
+  SubinterfaceClientCallbackRouter,
+  SubinterfaceRemote}
+    from '/gen/content/test/data/mojo_bindings_web_test.test-mojom.m.js';
+import {MojoEcho, MojoEchoRemote}
+    from '/gen/content/web_test/common/mojo_echo.mojom.m.js';
+
+const kTestMessage = 'hello there';
+const kTestNumbers = [0, 1, 1, 2, 3, 5, 8, 13, 21];
+
+class TargetImpl {
+  constructor() {
+    this.numPokes = 0;
+    this.target = new TestMessageTargetReceiver(this);
+  }
+
+  poke() { this.numPokes++; }
+  ping() { return Promise.resolve(); }
+  repeat(message, numbers) { return {message: message, numbers: numbers}; }
+  echo(nested) { return Promise.resolve({nested: nested}); }
+  deconstruct(test_struct) {}
+  flatten(values) {}
+  flattenUnions(unions) {}
+  requestSubinterface(request, client) {}
+}
+
+promise_test(() => {
+  let impl = new TargetImpl;
+  let remote = impl.target.$.bindNewPipeAndPassRemote();
+  remote.poke();
+  return remote.ping().then(() => {
+    assert_equals(impl.numPokes, 1);
+  });
+}, 'messages with replies return Promises that resolve on reply received');
+
+promise_test(() => {
+  let impl = new TargetImpl;
+  let remote = impl.target.$.bindNewPipeAndPassRemote();
+  return remote.repeat(kTestMessage, kTestNumbers)
+               .then(reply => {
+                 assert_equals(reply.message, kTestMessage);
+                 assert_array_equals(reply.numbers, kTestNumbers);
+               });
+}, 'implementations can reply with multiple reply arguments');
+
+promise_test(() => {
+  let impl = new TargetImpl;
+  let remote = impl.target.$.bindNewPipeAndPassRemote();
+  const enumValue = TestMessageTarget_NestedEnum.kFoo;
+  return remote.echo(enumValue)
+               .then(({nested}) => assert_equals(nested, enumValue));
+}, 'nested enums are usable as arguments and responses.');
+
+promise_test(async (t) => {
+  const impl = new TargetImpl;
+  const remote = impl.target.$.bindNewPipeAndPassRemote();
+
+  await remote.ping();
+  remote.$.close();
+
+  await promise_rejects_js(t, Error, remote.ping());
+}, 'after the pipe is closed all future calls should fail');
+
+promise_test(async (t) => {
+  const impl = new TargetImpl;
+  const remote = impl.target.$.bindNewPipeAndPassRemote();
+
+  // None of these promises should successfully resolve because we are
+  // immediately closing the pipe.
+  const promises = []
+  for (let i = 0; i < 10; i++) {
+    promises.push(remote.ping());
+  }
+
+  remote.$.close();
+
+  for (const promise of promises) {
+    await promise_rejects_js(t, Error, promise);
+  }
+}, 'closing the pipe drops any pending messages');
+
+promise_test(() => {
+  let impl = new TargetImpl;
+
+  // Intercept any browser-bound request for TestMessageTarget and bind it
+  // instead to the local |impl| object.
+  let interceptor = new MojoInterfaceInterceptor(
+      TestMessageTarget.$interfaceName);
+  interceptor.oninterfacerequest = e => {
+    impl.target.$.bindHandle(e.handle);
+  }
+  interceptor.start();
+
+  let remote = TestMessageTarget.getRemote();
+  remote.poke();
+  return remote.ping().then(() => {
+    assert_equals(impl.numPokes, 1);
+  });
+}, 'getRemote() attempts to send requests to the frame host');
+
+promise_test(() => {
+  let router = new TestMessageTargetCallbackRouter;
+  let remote = router.$.bindNewPipeAndPassRemote();
+  return new Promise(resolve => {
+    router.poke.addListener(resolve);
+    remote.poke();
+  });
+}, 'basic generated CallbackRouter behavior works as intended');
+
+promise_test(() => {
+  let router = new TestMessageTargetCallbackRouter;
+  let remote = router.$.bindNewPipeAndPassRemote();
+  let numPokes = 0;
+  router.poke.addListener(() => ++numPokes);
+  router.ping.addListener(() => Promise.resolve());
+  remote.poke();
+  return remote.ping().then(() => assert_equals(numPokes, 1));
+}, 'CallbackRouter listeners can reply to messages');
+
+promise_test(() => {
+  let router = new TestMessageTargetCallbackRouter;
+  let remote = router.$.bindNewPipeAndPassRemote();
+  router.repeat.addListener(
+    (message, numbers) => ({message: message, numbers: numbers}));
+  return remote.repeat(kTestMessage, kTestNumbers)
+               .then(reply => {
+                 assert_equals(reply.message, kTestMessage);
+                 assert_array_equals(reply.numbers, kTestNumbers);
+               });
+}, 'CallbackRouter listeners can reply with multiple reply arguments');
+
+promise_test(() => {
+  let targetRouter = new TestMessageTargetCallbackRouter;
+  let targetRemote = targetRouter.$.bindNewPipeAndPassRemote();
+  let subinterfaceRouter = new SubinterfaceCallbackRouter;
+  targetRouter.requestSubinterface.addListener((request, client) => {
+    let values = [];
+    subinterfaceRouter.$.bindHandle(request.handle);
+    subinterfaceRouter.push.addListener(value => values.push(value));
+    subinterfaceRouter.flush.addListener(() => {
+      client.didFlush(values);
+      values = [];
+    });
+  });
+
+  let clientRouter = new SubinterfaceClientCallbackRouter;
+  let subinterfaceRemote = new SubinterfaceRemote;
+  targetRemote.requestSubinterface(
+    subinterfaceRemote.$.bindNewPipeAndPassReceiver(),
+    clientRouter.$.bindNewPipeAndPassRemote());
+  return new Promise(resolve => {
+    clientRouter.didFlush.addListener(values => {
+      assert_array_equals(values, kTestNumbers);
+      resolve();
+    });
+
+    kTestNumbers.forEach(n => subinterfaceRemote.push(n));
+    subinterfaceRemote.flush();
+  });
+}, 'can send and receive interface requests and proxies');
+
+promise_test(() => {
+  const targetRouter = new TestMessageTargetCallbackRouter;
+  const targetRemote = targetRouter.$.bindNewPipeAndPassRemote();
+  targetRouter.deconstruct.addListener(({x, y, z}) => ({
+    x: x,
+    y: y,
+    z: z
+  }));
+
+  return targetRemote.deconstruct({x: 1}).then(reply => {
+    assert_equals(reply.x, 1);
+    assert_equals(reply.y, 2);
+    assert_equals(reply.z, 1);
+  });
+}, 'structs with default values from nested enums and constants are ' +
+   'correctly serialized');
+
+promise_test(() => {
+  const targetRouter = new TestMessageTargetCallbackRouter;
+  const targetRemote = targetRouter.$.bindNewPipeAndPassRemote();
+  targetRouter.flatten.addListener(values => ({values: values.map(v => v.x)}));
+  return targetRemote.flatten([{x: 1}, {x: 2}, {x: 3}]).then(reply => {
+    assert_array_equals(reply.values, [1, 2, 3]);
+  });
+}, 'regression test for complex array serialization');
+
+promise_test(() => {
+  const targetRouter = new TestMessageTargetCallbackRouter;
+  const targetRemote = targetRouter.$.bindNewPipeAndPassRemote();
+  targetRouter.flattenUnions.addListener(unions => {
+    return {x: unions.filter(u => u.x !== undefined).map(u => u.x),
+            s: unions.filter(u => u.s !== undefined).map(u => u.s.x)};
+  });
+
+  return targetRemote.flattenUnions(
+    [{x: 1}, {x: 2}, {s: {x: 3}}, {s: {x: 4}}, {x: 5}, {s: {x: 6}}])
+                     .then(reply => {
+                       assert_array_equals(reply.x, [1, 2, 5]);
+                       assert_array_equals(reply.s, [3, 4, 6]);
+                     });
+}, 'can serialize and deserialize unions');
+
+promise_test(() => {
+  let impl = new TargetImpl;
+  let remote = impl.target.$.bindNewPipeAndPassRemote();
+
+  // Poke a bunch of times. These should never race with the assertion below,
+  // because the |flushForTesting| request/response is ordered against other
+  // messages on |remote|.
+  const kNumPokes = 100;
+  for (let i = 0; i < kNumPokes; ++i)
+    remote.poke();
+  return remote.$.flushForTesting().then(() => {
+    assert_equals(impl.numPokes, kNumPokes);
+  });
+}, 'can use generated flushForTesting API for synchronization in tests');
+
+promise_test(async(t) => {
+  const impl = new TargetImpl;
+  const remote = impl.target.$.bindNewPipeAndPassRemote();
+  const disconnectPromise = new Promise(resolve => impl.target.onConnectionError.addListener(resolve));
+  remote.$.close();
+  return disconnectPromise;
+}, 'InterfaceTarget connection error handler runs when set on an Interface object');
+
+promise_test(() => {
+  const router = new TestMessageTargetCallbackRouter;
+  const remote = router.$.bindNewPipeAndPassRemote();
+  const disconnectPromise = new Promise(resolve => router.onConnectionError.addListener(resolve));
+  remote.$.close();
+  return disconnectPromise;
+}, 'InterfaceTarget connection error handler runs when set on an InterfaceCallbackRouter object');
+
+function getMojoEchoRemote() {
+  // MojoEchoRemote.getRemote() only works for frame interfaces
+  // and MojoEcho is a process interface.
+  let remote = new MojoEchoRemote;
+  remote.$.bindNewPipeAndPassReceiver().bindInBrowser('process');
+  return remote;
+}
+
+promise_test(async () => {
+  const remote = getMojoEchoRemote();
+  {
+    const {value} = await remote.echoBoolFromUnion({boolValue: true});
+    assert_true(value);
+  }
+  {
+    const {value} = await remote.echoInt32FromUnion({int32Value: 123});
+    assert_equals(value, 123);
+  }
+  {
+    const {value} = await remote.echoStringFromUnion({stringValue: "foo"});
+    assert_equals(value, "foo");
+  }
+}, 'JS encoding and C++ decoding of unions work as expected.');
+
+promise_test(async() => {
+  const remote = getMojoEchoRemote();
+  {
+    const {testUnion: {boolValue}} = await remote.echoBoolAsUnion(true);
+    assert_equals(boolValue, true);
+  }
+  {
+    const {testUnion: {int32Value}} = await remote.echoInt32AsUnion(123);
+    assert_equals(int32Value, 123);
+  }
+  {
+    const {testUnion: {stringValue}} = await remote.echoStringAsUnion("foo");
+    assert_equals(stringValue, "foo");
+  }
+
+}, 'JS decoding and C++ encoding of unions work as expected.');
+
+promise_test(async () => {
+  const remote = getMojoEchoRemote();
+  {
+    const response = await remote.echoNullFromOptionalUnion();
+    assert_equals(Object.keys(response).length, 0);
+  }
+  {
+    const {value} = await remote.echoBoolFromOptionalUnion({boolValue: true});
+    assert_true(value);
+  }
+  {
+    const {value} = await remote.echoInt32FromOptionalUnion({int32Value: 123});
+    assert_equals(value, 123);
+  }
+  {
+    const {value} = await remote.echoStringFromOptionalUnion({stringValue: "foo"});
+    assert_equals(value, "foo");
+  }
+}, 'JS encoding and C++ decoding of optional unions work as expected.');
+
+promise_test(async() => {
+  const remote = getMojoEchoRemote();
+  {
+    const {testUnion} = await remote.echoNullAsOptionalUnion();
+    assert_equals(testUnion, null);
+  }
+  {
+    const {testUnion: {boolValue}} = await remote.echoBoolAsOptionalUnion(true);
+    assert_equals(boolValue, true);
+  }
+  {
+    const {testUnion: {int32Value}} = await remote.echoInt32AsOptionalUnion(123);
+    assert_equals(int32Value, 123);
+  }
+  {
+    const {testUnion: {stringValue}} =
+      await remote.echoStringAsOptionalUnion("foo");
+    assert_equals(stringValue, "foo");
+  }
+
+}, 'JS decoding and C++ encoding of optional unions work as expected.');
+
+promise_test(async() => {
+  const remote = getMojoEchoRemote();
+  {
+    const {value} = await remote.echoInt8FromNestedUnion({int8Value: -10});
+    assert_equals(value, -10);
+  }
+  {
+    const {value} = await remote.echoBoolFromNestedUnion({unionValue: {boolValue: true}});
+    assert_true(value);
+  }
+  {
+    const {value} = await remote.echoStringFromNestedUnion({unionValue: {stringValue: 'foo'}});
+    assert_equals(value, 'foo');
+  }
+}, 'JS encoding and C++ decoding of nested unions work as expected.');
+
+promise_test(async() => {
+  const remote = getMojoEchoRemote();
+  {
+    const {testUnion: {int8Value}} = await remote.echoInt8AsNestedUnion(-10);
+    assert_equals(int8Value, -10);
+  }
+  {
+    const {testUnion: {unionValue: {boolValue}}} = await remote.echoBoolAsNestedUnion(true);
+    assert_true(boolValue);
+  }
+  {
+    const {testUnion: {unionValue: {stringValue}}} =
+      await remote.echoStringAsNestedUnion('foo');
+    assert_equals(stringValue, 'foo');
+  }
+}, 'JS decoding and C++ encoding of nested unions work as expected.');
+
+promise_test(async() => {
+  const remote = getMojoEchoRemote();
+  {
+    const response = await remote.echoNullFromOptionalNestedUnion();
+    assert_equals(Object.keys(response).length, 0);
+  }
+  {
+    const {value} = await remote.echoInt8FromOptionalNestedUnion({int8Value: -10});
+    assert_equals(value, -10);
+  }
+  {
+    const {value} = await remote.echoBoolFromOptionalNestedUnion({unionValue: {boolValue: true}});
+    assert_true(value);
+  }
+  {
+    const {value} = await remote.echoStringFromOptionalNestedUnion({unionValue: {stringValue: 'foo'}});
+    assert_equals(value, 'foo');
+  }
+}, 'JS encoding and C++ decoding of optional nested unions work as expected.');
+
+promise_test(async() => {
+  const remote = getMojoEchoRemote();
+  {
+    const {testUnion} = await remote.echoNullAsOptionalNestedUnion();
+    assert_equals(testUnion, null);
+  }
+  {
+    const {testUnion: {int8Value}} = await remote.echoInt8AsOptionalNestedUnion(-10);
+    assert_equals(int8Value, -10);
+  }
+  {
+    const {testUnion: {unionValue: {boolValue}}} =
+      await remote.echoBoolAsOptionalNestedUnion(true);
+    assert_true(boolValue);
+  }
+  {
+    const {testUnion: {unionValue: {stringValue}}} =
+      await remote.echoStringAsOptionalNestedUnion('foo');
+    assert_equals(stringValue, 'foo');
+  }
+}, 'JS decoding and C++ encoding of optional nested unions work as expected.');
+</script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/codec.html b/third_party/blink/web_tests/http/tests/mojo/codec.html
deleted file mode 100644
index 6fc99b1..0000000
--- a/third_party/blink/web_tests/http/tests/mojo/codec.html
+++ /dev/null
@@ -1,319 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/js-test-resources/testharness-helpers.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/sample_service.mojom.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/test_structs.mojom.js"></script>
-<script>
-'use strict';
-
-test(() => {
-  var bar = new sample.Bar();
-  bar.alpha = 1;
-  bar.beta = 2;
-  bar.gamma = 3;
-  bar.type = 0x08070605;
-  bar.extraProperty = "banana";
-
-  var messageName = 42;
-  var payloadSize = sample.Bar.encodedSize;
-
-  var builder = new mojo.internal.MessageV0Builder(messageName, payloadSize);
-  builder.encodeStruct(sample.Bar, bar);
-
-  var message = builder.finish();
-
-  var expectedMemory = new Uint8Array([
-    24, 0, 0, 0,
-     0, 0, 0, 0,
-     0, 0, 0, 0,
-    42, 0, 0, 0,
-     0, 0, 0, 0,
-     0, 0, 0, 0,
-
-    16, 0, 0, 0,
-     0, 0, 0, 0,
-
-     1, 2, 3, 0,
-     5, 6, 7, 8,
-  ]);
-
-  var actualMemory = new Uint8Array(message.buffer.arrayBuffer);
-  assert_weak_equals(actualMemory, expectedMemory);
-
-  var reader = new mojo.internal.MessageReader(message);
-
-  assert_equals(reader.payloadSize, payloadSize);
-  assert_equals(reader.messageName, messageName);
-
-  var bar2 = reader.decodeStruct(sample.Bar);
-
-  assert_equals(bar2.alpha, bar.alpha);
-  assert_equals(bar2.beta, bar.beta);
-  assert_equals(bar2.gamma, bar.gamma);
-  assert_false("extraProperty" in bar2);
-}, 'bar');
-
-test(() => {
-  var foo = new sample.Foo();
-  foo.x = 0x212B4D5;
-  foo.y = 0x16E93;
-  foo.a = 1;
-  foo.b = 0;
-  foo.c = 3; // This will get truncated to one bit.
-  foo.bar = new sample.Bar();
-  foo.bar.alpha = 91;
-  foo.bar.beta = 82;
-  foo.bar.gamma = 73;
-  foo.data = [
-    4, 5, 6, 7, 8,
-  ];
-  foo.extraBars = [
-    new sample.Bar(), new sample.Bar(), new sample.Bar(),
-  ];
-  for (var i = 0; i < foo.extraBars.length; ++i) {
-    foo.extraBars[i].alpha = 1 * i;
-    foo.extraBars[i].beta = 2 * i;
-    foo.extraBars[i].gamma = 3 * i;
-  }
-  foo.name = "I am a banana";
-  // This is supposed to be a handle, but we fake it with an integer.
-  foo.source = 23423782;
-  foo.arrayOfArrayOfBools = [
-    [true], [false, true]
-  ];
-  foo.arrayOfBools = [
-    true, false, true, false, true, false, true, true
-  ];
-
-
-  var messageName = 31;
-  var payloadSize = 304;
-
-  var builder = new mojo.internal.MessageV0Builder(messageName, payloadSize);
-  builder.encodeStruct(sample.Foo, foo);
-
-  var message = builder.finish();
-
-  var expectedMemory = new Uint8Array([
-    /*  0: */   24,    0,    0,    0,    0,    0,    0,    0,
-    /*  8: */    0,    0,    0,    0,   31,    0,    0,    0,
-    /* 16: */    0,    0,    0,    0,    0,    0,    0,    0,
-    /* 24: */   96,    0,    0,    0,    0,    0,    0,    0,
-    /* 32: */ 0xD5, 0xB4, 0x12, 0x02, 0x93, 0x6E, 0x01,    0,
-    /* 40: */    5,    0,    0,    0,    0,    0,    0,    0,
-    /* 48: */   72,    0,    0,    0,    0,    0,    0,    0,
-  ]);
-  // TODO(abarth): Test more of the message's raw memory.
-  var actualMemory = new Uint8Array(message.buffer.arrayBuffer,
-                                    0, expectedMemory.length);
-  assert_weak_equals(actualMemory, expectedMemory);
-
-  var expectedHandles = [
-    23423782,
-  ];
-
-  assert_weak_equals(message.handles, expectedHandles);
-
-  var reader = new mojo.internal.MessageReader(message);
-
-  assert_equals(reader.payloadSize, payloadSize);
-  assert_equals(reader.messageName, messageName);
-
-  var foo2 = reader.decodeStruct(sample.Foo);
-
-  assert_equals(foo2.x, foo.x);
-  assert_equals(foo2.y, foo.y);
-
-  assert_equals(foo2.a, foo.a & 1 ? true : false);
-  assert_equals(foo2.b, foo.b & 1 ? true : false);
-  assert_equals(foo2.c, foo.c & 1 ? true : false);
-
-  assert_weak_equals(foo2.bar, foo.bar);
-  assert_weak_equals(foo2.data, foo.data);
-
-  assert_weak_equals(foo2.extraBars, foo.extraBars);
-  assert_equals(foo2.name, foo.name);
-  assert_equals(foo2.source, foo.source);
-
-  assert_weak_equals(foo2.arrayOfBools, foo.arrayOfBools);
-}, 'foo');
-
-
-// Verify that the references to the imported Rect type in test_structs.mojom
-// are generated correctly.
-test(() => {
-
-  function createRect(x, y, width, height) {
-    var r = new mojo.test.Rect();
-    r.x = x;
-    r.y = y;
-    r.width = width;
-    r.height = height;
-    return r;
-  }
-
-  var r = new mojo.test.NamedRegion();
-  r.name = "rectangle";
-  r.rects = new Array(createRect(1, 2, 3, 4), createRect(10, 20, 30, 40));
-
-  var builder = new mojo.internal.MessageV0Builder(
-      1, mojo.test.NamedRegion.encodedSize);
-  builder.encodeStruct(mojo.test.NamedRegion, r);
-  var reader = new mojo.internal.MessageReader(builder.finish());
-  var result = reader.decodeStruct(mojo.test.NamedRegion);
-
-  assert_equals(result.name, "rectangle");
-  assert_weak_equals(result.rects[0], createRect(1, 2, 3, 4));
-  assert_weak_equals(result.rects[1], createRect(10, 20, 30, 40));
-}, 'named region');
-
-// Verify that a single boolean field in a struct is correctly decoded to
-// boolean type.
-test(() => {
-  var singleBool = new mojo.test.SingleBoolStruct();
-  singleBool.value = true;
-
-  var builder = new mojo.internal.MessageV0Builder(
-      1, mojo.test.SingleBoolStruct.encodedSize);
-  builder.encodeStruct(mojo.test.SingleBoolStruct, singleBool);
-  var reader = new mojo.internal.MessageReader(builder.finish());
-  var result = reader.decodeStruct(mojo.test.SingleBoolStruct);
-
-  assert_true(result.value);
-}, 'single boolean struct');
-
-test(() => {
-  function encodeDecode(cls, input, expectedResult, encodedSize) {
-    var messageName = 42;
-    var payloadSize = encodedSize || cls.encodedSize;
-
-    var builder = new mojo.internal.MessageV0Builder(messageName, payloadSize);
-    builder.encodeStruct(cls, input)
-    var message = builder.finish();
-
-    var reader = new mojo.internal.MessageReader(message);
-    assert_equals(reader.payloadSize, payloadSize);
-    assert_equals(reader.messageName, messageName);
-    var result = reader.decodeStruct(cls);
-    assert_equals(result, expectedResult);
-  }
-  encodeDecode(mojo.internal.String, "banana", "banana", 24);
-  encodeDecode(mojo.internal.NullableString, null, null, 8);
-  encodeDecode(mojo.internal.Int8, -1, -1);
-  encodeDecode(mojo.internal.Int8, 0xff, -1);
-  encodeDecode(mojo.internal.Int16, -1, -1);
-  encodeDecode(mojo.internal.Int16, 0xff, 0xff);
-  encodeDecode(mojo.internal.Int16, 0xffff, -1);
-  encodeDecode(mojo.internal.Int32, -1, -1);
-  encodeDecode(mojo.internal.Int32, 0xffff, 0xffff);
-  encodeDecode(mojo.internal.Int32, 0xffffffff, -1);
-  encodeDecode(mojo.internal.Float, 1.0, 1.0);
-  encodeDecode(mojo.internal.Double, 1.0, 1.0);
-}, 'types');
-
-test(() => {
-  var aligned = [
-    0, // 0
-    8, // 1
-    8, // 2
-    8, // 3
-    8, // 4
-    8, // 5
-    8, // 6
-    8, // 7
-    8, // 8
-    16, // 9
-    16, // 10
-    16, // 11
-    16, // 12
-    16, // 13
-    16, // 14
-    16, // 15
-    16, // 16
-    24, // 17
-    24, // 18
-    24, // 19
-    24, // 20
-  ];
-  for (var i = 0; i < aligned.length; ++i)
-    assert_equals(mojo.internal.align(i), aligned[i]);
-
-}, 'align');
-
-test(() => {
-  var str = "B\u03ba\u1f79";  // some UCS-2 codepoints
-  var messageName = 42;
-  var payloadSize = 24;
-
-  var builder = new mojo.internal.MessageV0Builder(messageName, payloadSize);
-  var encoder = builder.createEncoder(8);
-  encoder.encodeStringPointer(str);
-  var message = builder.finish();
-  var expectedMemory = new Uint8Array([
-    /*  0: */   24,    0,    0,    0,    0,    0,    0,    0,
-    /*  8: */    0,    0,    0,    0,   42,    0,    0,    0,
-    /* 16: */    0,    0,    0,    0,    0,    0,    0,    0,
-    /* 24: */    8,    0,    0,    0,    0,    0,    0,    0,
-    /* 32: */   14,    0,    0,    0,    6,    0,    0,    0,
-    /* 40: */ 0x42, 0xCE, 0xBA, 0xE1, 0xBD, 0xB9,    0,    0,
-  ]);
-  var actualMemory = new Uint8Array(message.buffer.arrayBuffer);
-  assert_weak_equals(actualMemory, expectedMemory);
-
-  var reader = new mojo.internal.MessageReader(message);
-  assert_equals(reader.payloadSize, payloadSize);
-  assert_equals(reader.messageName, messageName);
-  var str2 = reader.decoder.decodeStringPointer();
-  assert_equals(str2, str);
-}, 'utf8');
-
-test(() => {
-  var str = "Hello world ".repeat(100000);
-  var messageName = 42;
-  var payloadSize = 1200000;
-
-  var builder = new mojo.internal.MessageV0Builder(messageName, payloadSize);;
-  var encoder = builder.createEncoder(1200000);
-  encoder.encodeStringPointer(str);
-  var message = builder.finish();
-
-  var reader = new mojo.internal.MessageReader(message);
-  var str2 = reader.decoder.decodeStringPointer();
-  assert_equals(str2, str);
-}, 'very long utf8');
-
-test(() => {
-  var encoder = new mojo.internal.MessageV0Builder(42, 24).createEncoder(8);
-  function DummyClass() {};
-  var testCases = [
-    // method, args, invalid examples, valid examples
-    [encoder.encodeArrayPointer, [DummyClass], [75],
-        [[], null, undefined, new Uint8Array([])]],
-    [encoder.encodeStringPointer, [], [75, new String("foo")],
-        ["", "bar", null, undefined]],
-    [encoder.encodeMapPointer, [DummyClass, DummyClass], [75],
-        [new Map(), null, undefined]],
-  ];
-
-  testCases.forEach(function(test) {
-    var method = test[0];
-    var baseArgs = test[1];
-    var invalidExamples = test[2];
-    var validExamples = test[3];
-
-    var encoder = new mojo.internal.MessageV0Builder(42, 24).createEncoder(8);
-    invalidExamples.forEach(function(invalid) {
-      assert_throws_js(Error, function() {
-        method.apply(encoder, baseArgs.concat(invalid));
-      });
-    });
-
-    validExamples.forEach(function(valid) {
-      var encoder = new mojo.internal.MessageV0Builder(42, 24).createEncoder(8);
-      method.apply(encoder, baseArgs.concat(valid));
-    });
-  });
-}, 'typed pointer validation');
-</script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/connection.html b/third_party/blink/web_tests/http/tests/mojo/connection.html
deleted file mode 100644
index 17ea1dc..0000000
--- a/third_party/blink/web_tests/http/tests/mojo/connection.html
+++ /dev/null
@@ -1,83 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/sample_service.mojom.js"></script>
-<script>
-'use strict';
-
-promise_test(async () => {
-  function ServiceImpl() {
-  }
-
-  ServiceImpl.prototype.frobinate = function(foo, baz, port) {
-    assert_equals(foo.name, "Example name");
-    assert_equals(baz, sample.Service.BazOptions.REGULAR);
-    assert_true(port.ptr.isBound());
-    port.ptr.reset();
-
-    return Promise.resolve({result: 42});
-  };
-
-  var service = new sample.ServicePtr();
-  var serviceBinding = new mojo.Binding(
-      sample.Service, new ServiceImpl(), mojo.makeRequest(service));
-  var sourcePipe = Mojo.createMessagePipe();
-  var port = new sample.PortPtr();
-  var portRequest = mojo.makeRequest(port);
-
-  var foo = new sample.Foo();
-  foo.bar = new sample.Bar();
-  foo.name = "Example name";
-  foo.source = sourcePipe.handle0;
-
-  assert_equals((await service.frobinate(
-      foo, sample.Service.BazOptions.REGULAR, port)).result, 42);
-
-  service.ptr.reset();
-  serviceBinding.close();
-
-  // sourcePipe.handle1 hasn't been closed yet.
-  sourcePipe.handle1.close();
-
-  // portRequest.handle hasn't been closed yet.
-  portRequest.handle.close();
-}, 'client server');
-
-promise_test(async () => {
-  var service = new sample.ServicePtr();
-  // Discard the interface request.
-  var interfaceRequest = mojo.makeRequest(service);
-  interfaceRequest.close();
-
-  try {
-    await service.frobinate(null, sample.Service.BazOptions.REGULAR, null);
-    assert_unreached();
-  } catch (e) {
-    assert_not_equals(e, null);
-  }
-}, 'write to closed pipe');
-
-promise_test(async () => {
-  function ProviderImpl() {
-  }
-
-  ProviderImpl.prototype.echoString = function(a) {
-    return Promise.resolve({a: a});
-  };
-
-  ProviderImpl.prototype.echoStrings = function(a, b) {
-    return Promise.resolve({a: a, b: b});
-  };
-
-  var provider = new sample.ProviderPtr();
-  var providerBinding = new mojo.Binding(
-      sample.Provider, new ProviderImpl(), mojo.makeRequest(provider));
-  assert_equals((await provider.echoString("hello")).a, "hello");
-  var response = await provider.echoStrings("hello", "world");
-  assert_equals(response.a, "hello");
-  assert_equals(response.b, "world");
-}, 'request response');
-
-</script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/detached-frame.html b/third_party/blink/web_tests/http/tests/mojo/detached-frame.html
index 5b015ef..83867a6 100644
--- a/third_party/blink/web_tests/http/tests/mojo/detached-frame.html
+++ b/third_party/blink/web_tests/http/tests/mojo/detached-frame.html
@@ -1,19 +1,13 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/content/test/data/mojo_web_test_helper_test.mojom.js"></script>
 <body>
-<script>
+<script type="module">
+import {MojoWebTestHelper, MojoWebTestHelperRemote} from '/gen/content/test/data/mojo_web_test_helper_test.mojom.m.js';
 
 function frameLoaded(frame) {
-  return new Promise(resolve => {
-    let eventHandler = e => {
-      frame.removeEventListener('load', eventHandler);
-      resolve();
-    };
-    frame.addEventListener('load', eventHandler);
-  });
+  return new Promise(
+      resolve => frame.addEventListener('load', resolve, {once: true}));
 }
 
 promise_test(async () => {
@@ -27,12 +21,12 @@
   let frameMojo = frame.contentWindow.Mojo;
   document.body.removeChild(frame);
 
-  let helper = new content.mojom.MojoWebTestHelperPtr;
-  frameMojo.bindInterface(content.mojom.MojoWebTestHelper.name,
-                          mojo.makeRequest(helper).handle);
+  const {handle0, handle1} = frameMojo.createMessagePipe();
+  let helper = new MojoWebTestHelperRemote(handle0);
+  frameMojo.bindInterface(MojoWebTestHelper.$interfaceName, handle1);
 
   try {
-    let reply = await helper.reverse("hello world.");
+    await helper.reverse("hello world.");
     assert_unreached();
   } catch (e) {
     // Connection failure expected.
@@ -52,7 +46,7 @@
   document.body.removeChild(frame);
 
   let interceptor = new frameMojoInterfaceInterceptor(
-      content.mojom.MojoWebTestHelper.name);
+      MojoWebTestHelper.$interfaceName);
   try {
     interceptor.start();
     assert_unreached();
@@ -70,7 +64,7 @@
   // Create the interceptor while the frame is attached so that it is associated
   // with the frame's execution context.
   let interceptor = new frame.contentWindow.MojoInterfaceInterceptor(
-      content.mojom.MojoWebTestHelper.name);
+      MojoWebTestHelper.$interfaceName);
   document.body.removeChild(frame);
 
   try {
@@ -89,7 +83,7 @@
 
   // Create the interceptor and start it while the frame is attached.
   let interceptor = new frame.contentWindow.MojoInterfaceInterceptor(
-      content.mojom.MojoWebTestHelper.name);
+      MojoWebTestHelper.$interfaceName);
   interceptor.start();
   document.body.removeChild(frame);
 
diff --git a/third_party/blink/web_tests/http/tests/mojo/interface_ptr.html b/third_party/blink/web_tests/http/tests/mojo/interface_ptr.html
deleted file mode 100644
index 92043a3..0000000
--- a/third_party/blink/web_tests/http/tests/mojo/interface_ptr.html
+++ /dev/null
@@ -1,174 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/math_calculator.mojom.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom.js"></script>
-<script>
-'use strict';
-
-function CalculatorImpl() {
-  this.total = 0;
-}
-
-CalculatorImpl.prototype.clear = function() {
-  this.total = 0;
-  return Promise.resolve({value: this.total});
-};
-
-CalculatorImpl.prototype.add = function(value) {
-  this.total += value;
-  return Promise.resolve({value: this.total});
-};
-
-CalculatorImpl.prototype.multiply = function(value) {
-  this.total *= value;
-  return Promise.resolve({value: this.total});
-};
-
-function IntegerAccessorImpl() {
-  this.integer = 0;
-}
-
-IntegerAccessorImpl.prototype.getInteger = function() {
-  return Promise.resolve({data: this.integer});
-};
-
-IntegerAccessorImpl.prototype.setInteger = function(value) {
-  this.integer = value;
-};
-
-test(() => {
-  var calc = new math.CalculatorPtr();
-  assert_false(calc.ptr.isBound());
-
-  var request = mojo.makeRequest(calc);
-  assert_true(calc.ptr.isBound());
-
-  calc.ptr.reset();
-  assert_false(calc.ptr.isBound());
-}, 'is bound');
-
-promise_test(async () => {
-  var calc = new math.CalculatorPtr();
-  var calcBinding = new mojo.Binding(
-      math.Calculator, new CalculatorImpl(), mojo.makeRequest(calc));
-
-  assert_equals((await calc.add(2)).value, 2);
-  assert_equals((await calc.multiply(5)).value, 10);
-  assert_equals((await calc.clear()).value, 0);
-}, 'end to end');
-
-promise_test(async () => {
-  var calc = new math.CalculatorPtr();
-  var calcImpl1 = new CalculatorImpl();
-  var calcBinding1 = new mojo.Binding(math.Calculator, calcImpl1,
-                                      mojo.makeRequest(calc));
-  var calcImpl2 = new CalculatorImpl();
-  var calcBinding2 = new mojo.Binding(math.Calculator, calcImpl2);
-
-  assert_equals((await calc.add(2)).value, 2);
-  calcBinding2.bind(mojo.makeRequest(calc));
-  assert_equals((await calc.add(2)).value, 2);
-  assert_equals(calcImpl1.total, 2);
-  assert_equals(calcImpl2.total, 2);
-}, 'reusable');
-
-promise_test(async () => {
-  var calc = new math.CalculatorPtr();
-  var calcBinding = new mojo.Binding(math.Calculator, new CalculatorImpl(),
-                                     mojo.makeRequest(calc));
-
-  await new Promise((resolve, reject) => {
-    calc.ptr.setConnectionErrorHandler(() => { resolve(); });
-    calcBinding.close();
-  });
-}, 'connection error');
-
-promise_test(async () => {
-  var calc = new math.CalculatorPtr();
-  var calcBinding = new mojo.Binding(math.Calculator, new CalculatorImpl(),
-                                     mojo.makeRequest(calc));
-
-  await new Promise((resolve, reject) => {
-    calc.ptr.setConnectionErrorHandler(({customReason, description}) => {
-      assert_equals(customReason, 42);
-      assert_equals(description, 'hey');
-      resolve();
-    });
-    calcBinding.closeWithReason({customReason: 42, description: 'hey'});
-  });
-}, 'connection error with reason');
-
-promise_test(async () => {
-  var calc = new math.CalculatorPtr();
-  var newCalc = null;
-  var calcBinding = new mojo.Binding(math.Calculator, new CalculatorImpl(),
-                                     mojo.makeRequest(calc));
-
-  assert_equals((await calc.add(2)).value, 2);
-  newCalc = new math.CalculatorPtr();
-  newCalc.ptr.bind(calc.ptr.passInterface());
-  assert_false(calc.ptr.isBound());
-  assert_equals((await newCalc.add(2)).value, 4);
-
-}, 'pass interface');
-
-promise_test(async () => {
-  var pipe = Mojo.createMessagePipe();
-  var calc = new math.CalculatorPtr(pipe.handle0);
-  var newCalc = null;
-  var calcBinding = new mojo.Binding(math.Calculator, new CalculatorImpl(),
-                                     pipe.handle1);
-
-  assert_equals((await calc.add(2)).value, 2);
-
-}, 'bind raw handle');
-
-promise_test(async () => {
-  var integerAccessorPtr = new sample.IntegerAccessorPtr();
-
-  var integerAccessorBinding = new mojo.Binding(
-      sample.IntegerAccessor, new IntegerAccessorImpl(),
-      mojo.makeRequest(integerAccessorPtr));
-  assert_equals(integerAccessorPtr.ptr.version, 0);
-
-  assert_equals(await integerAccessorPtr.ptr.queryVersion(), 3);
-  assert_equals(integerAccessorPtr.ptr.version, 3);
-}, 'query version');
-
-promise_test(async () => {
-  var integerAccessorImpl = new IntegerAccessorImpl();
-  var integerAccessorPtr = new sample.IntegerAccessorPtr();
-  var integerAccessorBinding = new mojo.Binding(
-      sample.IntegerAccessor, integerAccessorImpl,
-      mojo.makeRequest(integerAccessorPtr));
-
-  // Inital version is 0.
-  assert_equals(integerAccessorPtr.ptr.version, 0);
-
-  integerAccessorPtr.ptr.requireVersion(1);
-  assert_equals(integerAccessorPtr.ptr.version, 1);
-  integerAccessorPtr.setInteger(123, sample.Enum.VALUE);
-  assert_equals((await integerAccessorPtr.getInteger()).data, 123);
-
-  integerAccessorPtr.ptr.requireVersion(3);
-  assert_equals(integerAccessorPtr.ptr.version, 3);
-  integerAccessorPtr.setInteger(456, sample.Enum.VALUE);
-  assert_equals((await integerAccessorPtr.getInteger()).data, 456);
-
-  // Require a version that is not supported by the impl side.
-  integerAccessorPtr.ptr.requireVersion(4);
-  assert_equals(integerAccessorPtr.ptr.version, 4);
-  integerAccessorPtr.setInteger(789, sample.Enum.VALUE);
-
-  await new Promise((resolve, reject) => {
-    integerAccessorPtr.ptr.setConnectionErrorHandler(() => {
-      resolve();
-    });
-  });
-  assert_equals(integerAccessorImpl.integer, 456);
-
-}, 'require version');
-
-</script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/module-loading-manual-deps-loading.html b/third_party/blink/web_tests/http/tests/mojo/module-loading-manual-deps-loading.html
deleted file mode 100644
index 798520e..0000000
--- a/third_party/blink/web_tests/http/tests/mojo/module-loading-manual-deps-loading.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<title>Mojo JavaScript bindings module loading tests (manual mojom deps loading)</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script>
-  mojo.config.autoLoadMojomDeps = false;
-</script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/echo.mojom.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/echo_import/echo_import.mojom.js"></script>
-<script>
-
-promise_test(async () => {
-  function EchoImpl() {}
-  EchoImpl.prototype.echoPoint = function(point) {
-    return Promise.resolve({result: point});
-  };
-
-  var echoServicePtr = new test.echo.mojom.EchoPtr();
-  var echoServiceBinding = new mojo.Binding(test.echo.mojom.Echo,
-                                            new EchoImpl(),
-                                            mojo.makeRequest(echoServicePtr));
-  var result = (await echoServicePtr.echoPoint({x: 1, y: 2})).result;
-  assert_equals(1, result.x);
-  assert_equals(2, result.y);
-}, 'Basics');
-
-</script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/module-loading.html b/third_party/blink/web_tests/http/tests/mojo/module-loading.html
deleted file mode 100644
index a09556a..0000000
--- a/third_party/blink/web_tests/http/tests/mojo/module-loading.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<title>Mojo JavaScript bindings module loading tests</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/echo.mojom.js"></script>
-<script>
-
-promise_test(async () => {
-  function EchoImpl() {}
-  EchoImpl.prototype.echoPoint = function(point) {
-    return Promise.resolve({result: point});
-  };
-
-  var echoServicePtr = new test.echo.mojom.EchoPtr();
-  var echoServiceBinding = new mojo.Binding(test.echo.mojom.Echo,
-                                            new EchoImpl(),
-                                            mojo.makeRequest(echoServicePtr));
-  var result = (await echoServicePtr.echoPoint({x: 1, y: 2})).result;
-  assert_equals(1, result.x);
-  assert_equals(2, result.y);
-}, 'Basics');
-
-</script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/resources/bind-intercepted-interface-in-worker.js b/third_party/blink/web_tests/http/tests/mojo/resources/bind-intercepted-interface-in-worker.js
index c69306391..2b96260 100644
--- a/third_party/blink/web_tests/http/tests/mojo/resources/bind-intercepted-interface-in-worker.js
+++ b/third_party/blink/web_tests/http/tests/mojo/resources/bind-intercepted-interface-in-worker.js
@@ -1,30 +1,41 @@
 importScripts('/resources/testharness.js');
-importScripts('/gen/layout_test_data/mojo/public/js/mojo_bindings.js');
-importScripts('/gen/content/test/data/mojo_web_test_helper_test.mojom.js');
-importScripts('helpers.js');
+
+async function importModuleDeps() {
+  const {kTestReply, TestHelperImpl} = await import('./helpers.js');
+  const {MojoWebTestHelper, MojoWebTestHelperRemote} = await import(
+      '/gen/content/test/data/mojo_web_test_helper_test.mojom.m.js');
+  Object.assign(
+      self,
+      {kTestReply, TestHelperImpl, MojoWebTestHelper, MojoWebTestHelperRemote});
+}
+
+const imports = importModuleDeps();
 
 promise_test(async () => {
-  let helperImpl = new TestHelperImpl;
+  await imports;
+
+  let helperImpl = new TestHelperImpl();
   let interceptor =
-      new MojoInterfaceInterceptor(content.mojom.MojoWebTestHelper.name);
+      new MojoInterfaceInterceptor(MojoWebTestHelper.$interfaceName);
   interceptor.oninterfacerequest = e => {
     helperImpl.bindRequest(e.handle);
   };
   interceptor.start();
 
-  let helper = new content.mojom.MojoWebTestHelperPtr;
-  Mojo.bindInterface(
-      content.mojom.MojoWebTestHelper.name, mojo.makeRequest(helper).handle);
+  let helper = new MojoWebTestHelperRemote();
+  helper.$.bindNewPipeAndPassReceiver().bindInBrowser();
 
-  let response = await helper.reverse('the string');
-  assert_equals(response.reversed, kTestReply);
+  const {reversed} = await helper.reverse('the string');
+  assert_equals(reversed, kTestReply);
   assert_equals(helperImpl.getLastString(), 'the string');
 }, 'Can implement a Mojo service and intercept it from a worker');
 
-test(t => {
+promise_test(async () => {
+  await imports;
+
   assert_throws_dom('NotSupportedError', () => {
     new MojoInterfaceInterceptor(
-        content.mojom.MojoWebTestHelper.name, 'process');
+        MojoWebTestHelper.$interfaceName, 'process');
   });
 }, 'Cannot create a MojoInterfaceInterceptor with process scope');
 
diff --git a/third_party/blink/web_tests/http/tests/mojo/resources/helpers.js b/third_party/blink/web_tests/http/tests/mojo/resources/helpers.js
index ed50937a..1761bc54 100644
--- a/third_party/blink/web_tests/http/tests/mojo/resources/helpers.js
+++ b/third_party/blink/web_tests/http/tests/mojo/resources/helpers.js
@@ -1,16 +1,17 @@
-const kTestReply = "hehe got ya";
+import {MojoWebTestHelperReceiver} from '/gen/content/test/data/mojo_web_test_helper_test.mojom.m.js';
+
+export const kTestReply = "hehe got ya";
 
 // An impl of the test interface which replies to reverse() with a fixed
 // message rather than the normally expected value.
-class TestHelperImpl {
+export class TestHelperImpl {
   constructor() {
-    this.binding_ =
-        new mojo.Binding(content.mojom.MojoWebTestHelper, this);
+    this.receiver_ = new MojoWebTestHelperReceiver(this);
   }
-  bindRequest(request) { this.binding_.bind(request); }
+  bindRequest(request) { this.receiver_.$.bindHandle(request); }
   getLastString() { return this.lastString_; }
   reverse(message) {
     this.lastString_ = message;
-    return Promise.resolve({ reversed: kTestReply });
+    return {reversed: kTestReply};
   }
 }
diff --git a/third_party/blink/web_tests/http/tests/mojo/sample_service.html b/third_party/blink/web_tests/http/tests/mojo/sample_service.html
index d597552..7f4a20c 100644
--- a/third_party/blink/web_tests/http/tests/mojo/sample_service.html
+++ b/third_party/blink/web_tests/http/tests/mojo/sample_service.html
@@ -1,33 +1,50 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/sample_service.mojom.js"></script>
-<script>
-'use strict';
+<script type="module">
+import {Bar_Type, DefaultsSenderCallbackRouter, DefaultsSenderRemote, PortRemote, Service_BazOptions, ServiceReceiver, ServiceRemote, TWELVE} from '/gen/mojo/public/interfaces/bindings/tests/sample_service.mojom.m.js';
+import {Shape} from '/gen/mojo/public/interfaces/bindings/tests/sample_import.mojom.m.js';
+import {Color} from '/gen/mojo/public/interfaces/bindings/tests/sample_import2.mojom.m.js';
 
-// Checks that values are set to the defaults if we don't override them.
-test(() => {
-  var bar = new sample.Bar();
+// Checks that optional fields are passed with default values if we don't set
+// them.
+promise_test(async () => {
+  const sender = new DefaultsSenderRemote();
+  const router = new DefaultsSenderCallbackRouter();
+  router.$.bindHandle(sender.$.bindNewPipeAndPassReceiver().handle);
+
+  const waitForBar = new Promise(
+      resolve => router.sendBar.addListener(resolve));
+  sender.sendBar({});
+  const bar = await waitForBar;
   assert_equals(bar.alpha, 255);
-  assert_equals(bar.type, sample.Bar.Type.VERTICAL);
+  assert_equals(bar.type, Bar_Type.VERTICAL);
 
-  var foo = new sample.Foo();
-  assert_equals(foo.name, "Fooby");
+  const waitForFoo = new Promise(
+      resolve => router.sendFoo.addListener(resolve));
+  sender.sendFoo({});
+  const foo = await waitForFoo;
+  assert_equals(foo.name, 'Fooby');
   assert_true(foo.a);
   assert_equals(foo.data, null);
 
-  var defaults = new sample.DefaultsTest();
+  const waitForDefaults = new Promise(
+      resolve => router.sendDefaultsTest.addListener(resolve));
+  sender.sendDefaultsTest({
+    a18: [],
+    a19: '',
+    a21: {x: 0, y: 0},
+    a22: {location: {x: 0, y: 0}, size: {width: 0, height: 0}},
+  });
+  const defaults = await waitForDefaults;
   assert_equals(defaults.a0, -12);
-  assert_equals(defaults.a1, sample.TWELVE);
+  assert_equals(defaults.a1, TWELVE);
   assert_equals(defaults.a2, 1234);
   assert_equals(defaults.a3, 34567);
   assert_equals(defaults.a4, 123456);
   assert_equals(defaults.a5, 3456789012);
-  assert_equals(defaults.a6, -111111111111);
-  // JS doesn't have a 64 bit integer type so this is just checking that the
-  // expected and actual values have the same closest double value.
-  assert_equals(defaults.a7, 9999999999999999999);
+  assert_equals(defaults.a6, -111111111111n);
+  assert_equals(defaults.a7, 9999999999999999999n);
   assert_equals(defaults.a8, 0x12345);
   assert_equals(defaults.a9, -0x12345);
   assert_equals(defaults.a10, 1234);
@@ -38,86 +55,72 @@
   assert_equals(defaults.a15, 1E10);
   assert_equals(defaults.a16, -1.2E+20);
   assert_equals(defaults.a17, 1.23E-20);
-  assert_equals(defaults.a20, sample.Bar.Type.BOTH);
-  assert_equals(defaults.a21, null);
+  assert_equals(defaults.a20, Bar_Type.BOTH);
   assert_true(!!defaults.a22);
-  assert_equals(defaults.a22.shape, imported.Shape.RECTANGLE);
-  assert_equals(defaults.a22.color, imported.Color.BLACK);
-  assert_equals(defaults.a23, 0xFFFFFFFFFFFFFFFF);
-  assert_equals(defaults.a24, 0x123456789);
-  assert_equals(defaults.a25, -0x123456789);
+  assert_equals(defaults.a22.shape, Shape.RECTANGLE);
+  assert_equals(defaults.a22.color, Color.BLACK);
+  assert_equals(defaults.a23, 0xFFFFFFFFFFFFFFFFn);
+  assert_equals(defaults.a24, 0x123456789n);
+  assert_equals(defaults.a25, -0x123456789n);
 }, 'default values');
 
 promise_test(async () => {
-  function ServiceImpl() {
+  class ServiceImpl {
+    frobinate(foo, baz, port) {
+      checkFoo(foo);
+      assert_equals(baz, Service_BazOptions.EXTRA);
+      assert_true(port.$.isBound());
+      return {result: 1234};
+    }
+
+    getPort(receiver) {}
   }
 
-  ServiceImpl.prototype.frobinate = function(foo, baz, port) {
-    checkFoo(foo);
-    assert_equals(baz, sample.Service.BazOptions.EXTRA);
-    assert_true(port.ptr.isBound());
-    return Promise.resolve({result: 1234});
-  };
-
-  var foo = makeFoo();
+  const foo = makeFoo();
   checkFoo(foo);
 
-  var service = new sample.ServicePtr();
-  var request = mojo.makeRequest(service);
-  var serviceBinding = new mojo.Binding(
-      sample.Service, new ServiceImpl(), request);
+  const service = new ServiceRemote();
+  const receiver = new ServiceReceiver(new ServiceImpl());
+  receiver.$.bindHandle(service.$.bindNewPipeAndPassReceiver().handle);
 
-  var port = new sample.PortPtr();
-  mojo.makeRequest(port);
-  assert_equals((await service.frobinate(foo, sample.Service.BazOptions.EXTRA,
-                                         port)).result, 1234);
-
+  const port = new PortRemote();
+  port.$.bindNewPipeAndPassReceiver().handle.close();
+  const {result} = await service.frobinate(foo, Service_BazOptions.EXTRA, port);
+  assert_equals(result, 1234);
 }, 'sample service');
 
-done();
-
 function makeFoo() {
-  var bar = new sample.Bar();
-  bar.alpha = 20;
-  bar.beta = 40;
-  bar.gamma = 60;
-  bar.type = sample.Bar.Type.VERTICAL;
+  const bar = {alpha: 20, beta: 40, gamma: 60, type: Bar_Type.VERTICAL};
 
-  var extraBars = new Array(3);
-  for (var i = 0; i < extraBars.length; ++i) {
-    var base = i * 100;
-    var type = i % 2 ? sample.Bar.Type.VERTICAL : sample.Bar.Type.HORIZONTAL;
-    extraBars[i] = new sample.Bar();
-    extraBars[i].alpha = base;
-    extraBars[i].beta = base + 20;
-    extraBars[i].gamma = base + 40;
-    extraBars[i].type = type;
+  const extraBars = new Array(3);
+  for (let i = 0; i < extraBars.length; ++i) {
+    const base = i * 100;
+    const type = i % 2 ? Bar_Type.VERTICAL : Bar_Type.HORIZONTAL;
+    extraBars[i] = {alpha: base, beta: base + 20, gamma: base + 40, type: type};
   }
 
-  var data = new Array(10);
-  for (var i = 0; i < data.length; ++i) {
+  const data = new Array(10);
+  for (let i = 0; i < data.length; ++i) {
     data[i] = data.length - i;
   }
 
-  var foo = new sample.Foo();
-  foo.name = "foopy";
-  foo.x = 1;
-  foo.y = 2;
-  foo.a = false;
-  foo.b = true;
-  foo.c = false;
-  foo.bar = bar;
-  foo.extraBars = extraBars;
-  foo.data = data;
-
-  foo.source = Mojo.createMessagePipe().handle0;
-
-  return foo;
+  return {
+    name: 'foopy',
+    x: 1,
+    y: 2,
+    a: false,
+    b: true,
+    c: false,
+    bar: bar,
+    extraBars: extraBars,
+    data: data,
+    source: Mojo.createMessagePipe().handle0,
+  };
 }
 
 // Checks that the given |Foo| is identical to the one made by |makeFoo()|.
 function checkFoo(foo) {
-  assert_equals(foo.name, "foopy");
+  assert_equals(foo.name, 'foopy');
   assert_equals(foo.x, 1);
   assert_equals(foo.y, 2);
   assert_false(foo.a);
@@ -126,12 +129,12 @@
   assert_equals(foo.bar.alpha, 20);
   assert_equals(foo.bar.beta, 40);
   assert_equals(foo.bar.gamma, 60);
-  assert_equals(foo.bar.type, sample.Bar.Type.VERTICAL);
+  assert_equals(foo.bar.type, Bar_Type.VERTICAL);
 
   assert_equals(foo.extraBars.length, 3);
   for (var i = 0; i < foo.extraBars.length; ++i) {
     var base = i * 100;
-    var type = i % 2 ?  sample.Bar.Type.VERTICAL : sample.Bar.Type.HORIZONTAL;
+    var type = i % 2 ?  Bar_Type.VERTICAL : Bar_Type.HORIZONTAL;
     assert_equals(foo.extraBars[i].alpha, base);
     assert_equals(foo.extraBars[i].beta, base + 20);
     assert_equals(foo.extraBars[i].gamma, base + 40);
@@ -144,4 +147,5 @@
 
   assert_true(foo.source instanceof MojoHandle);
 }
+
 </script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/struct.html b/third_party/blink/web_tests/http/tests/mojo/struct.html
deleted file mode 100644
index 7565a5f..0000000
--- a/third_party/blink/web_tests/http/tests/mojo/struct.html
+++ /dev/null
@@ -1,234 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/js-test-resources/testharness-helpers.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/test_structs.mojom.js"></script>
-<script>
-
-test(() => {
-  var r = new mojo.test.Rect();
-  assert_weak_equals(r, new mojo.test.Rect({x:0, y:0, width:0, height:0}));
-  assert_weak_equals(r, new mojo.test.Rect({foo:100, bar:200}));
-
-  r.x = 10;
-  r.y = 20;
-  r.width = 30;
-  r.height = 40;
-  var rp = new mojo.test.RectPair({first: r, second: r});
-  assert_weak_equals(rp.first, r);
-  assert_weak_equals(rp.second, r);
-
-  assert_equals(new mojo.test.RectPair({second: r}).first, null);
-
-  var nr = new mojo.test.NamedRegion();
-  assert_equals(nr.name, null);
-  assert_equals(nr.rects, null);
-  assert_weak_equals(nr, new mojo.test.NamedRegion({}));
-
-  nr.name = "foo";
-  nr.rects = [r, r, r];
-  assert_weak_equals(nr, new mojo.test.NamedRegion({
-    name: "foo",
-    rects: [r, r, r],
-  }));
-
-  var e = new mojo.test.EmptyStruct();
-  assert_weak_equals(e, new mojo.test.EmptyStruct({foo:123}));
-}, 'constructors');
-
-test(() => {
-  var s = new mojo.test.NoDefaultFieldValues();
-  assert_false(s.f0);
-
-  // f1 - f10, number type fields
-  for (var i = 1; i <= 10; i++)
-    assert_equals(s["f" + i], 0);
-
-  // f11,12 strings, f13-22 handles, f23-f26 arrays, f27,28 structs
-  for (var i = 11; i <= 28; i++)
-    assert_equals(s["f" + i], null);
-
-}, 'no default field values');
-
-test(() => {
-  var s = new mojo.test.DefaultFieldValues();
-  assert_true(s.f0);
-
-  // f1 - f12, number type fields
-  for (var i = 1; i <= 12; i++)
-    assert_equals(s["f" + i], 100);
-
-  // f13,14 "foo"
-  for (var i = 13; i <= 14; i++)
-    assert_equals(s["f" + i], "foo");
-
-  // f15,16 a default instance of Rect
-  var r = new mojo.test.Rect();
-  assert_weak_equals(s.f15, r);
-  assert_weak_equals(s.f16, r);
-}, 'default field values');
-
-test(() => {
-  assert_equals(mojo.test.ScopedConstants.TEN, 10);
-  assert_equals(mojo.test.ScopedConstants.ALSO_TEN, 10);
-
-  assert_equals(mojo.test.ScopedConstants.EType.E0, 0);
-  assert_equals(mojo.test.ScopedConstants.EType.E1, 1);
-  assert_equals(mojo.test.ScopedConstants.EType.E2, 10);
-  assert_equals(mojo.test.ScopedConstants.EType.E3, 10);
-  assert_equals(mojo.test.ScopedConstants.EType.E4, 11);
-
-  var s = new mojo.test.ScopedConstants();
-  assert_equals(s.f0, 0);
-  assert_equals(s.f1, 1);
-  assert_equals(s.f2, 10);
-  assert_equals(s.f3, 10);
-  assert_equals(s.f4, 11);
-  assert_equals(s.f5, 10);
-  assert_equals(s.f6, 10);
-}, 'scoped constants');
-
-function structEncodeDecode(struct) {
-  var structClass = struct.constructor;
-  var builder = new mojo.internal.MessageV0Builder(1234,
-      structClass.encodedSize);
-  builder.encodeStruct(structClass, struct);
-  var message = builder.finish();
-
-  var messageValidator = new mojo.internal.Validator(message);
-  var err = structClass.validate(messageValidator,
-                                 mojo.internal.kMessageV0HeaderSize);
-  assert_equals(err, mojo.internal.validationError.NONE);
-
-  var reader = new mojo.internal.MessageReader(message);
-  return reader.decodeStruct(structClass);
-}
-
-test(() => {
-  var mapFieldsStruct = new mojo.test.MapKeyTypes({
-    f0: new Map([[true, false], [false, true]]),  // map<bool, bool>
-    f1: new Map([[0, 0], [1, 127], [-1, -128]]),  // map<int8, int8>
-    f2: new Map([[0, 0], [1, 127], [2, 255]]),  // map<uint8, uint8>
-    f3: new Map([[0, 0], [1, 32767], [2, -32768]]),  // map<int16, int16>
-    f4: new Map([[0, 0], [1, 32768], [2, 0xFFFF]]),  // map<uint16, uint16>
-    f5: new Map([[0, 0], [1, 32767], [2, -32768]]),  // map<int32, int32>
-    f6: new Map([[0, 0], [1, 32768], [2, 0xFFFF]]),  // map<uint32, uint32>
-    f7: new Map([[0, 0], [1, 32767], [2, -32768]]),  // map<int64, int64>
-    f8: new Map([[0, 0], [1, 32768], [2, 0xFFFF]]),  // map<uint64, uint64>
-    f9: new Map([[1000.5, -50000], [100.5, 5000]]),  // map<float, float>
-    f10: new Map([[-100.5, -50000], [0, 50000000]]),  // map<double, double>
-    f11: new Map([["one", "two"], ["free", "four"]]),  // map<string, string>
-  });
-  var decodedStruct = structEncodeDecode(mapFieldsStruct);
-  assert_weak_equals(decodedStruct, mapFieldsStruct);
-}, 'map key types');
-
-test(() => {
-  var mapFieldsStruct = new mojo.test.MapValueTypes({
-    // map<string, array<string>>
-    f0: new Map([["a", ["b", "c"]], ["d", ["e"]]]),
-    // map<string, array<string>?>
-    f1: new Map([["a", null], ["b", ["c", "d"]]]),
-    // map<string, array<string?>>
-    f2: new Map([["a", [null]], ["b", [null, "d"]]]),
-    // map<string, array<string,2>>
-    f3: new Map([["a", ["1", "2"]], ["b", ["1", "2"]]]),
-    // map<string, array<array<string, 2>?>>
-    f4: new Map([["a", [["1", "2"]]], ["b", [null]]]),
-    // map<string, array<array<string, 2>, 1>>
-    f5: new Map([["a", [["1", "2"]]]]),
-    // map<string, Rect?>
-    f6: new Map([["a", null]]),
-    // map<string, map<string, string>>
-    f7: new Map([["a", new Map([["b", "c"]])]]),
-    // map<string, array<map<string, string>>>
-    f8: new Map([["a", [new Map([["b", "c"]])]]]),
-    // map<string, handle>
-    f9: new Map([["a", 1234]]),
-    // map<string, array<handle>>
-    f10: new Map([["a", [1234, 5678]]]),
-    // map<string, map<string, handle>>
-    f11: new Map([["a", new Map([["b", 1234]])]]),
-  });
-  var decodedStruct = structEncodeDecode(mapFieldsStruct);
-  assert_weak_equals(decodedStruct, mapFieldsStruct);
-}, 'map value types');
-
-test(() => {
-  var decodedStruct = structEncodeDecode(new mojo.test.FloatNumberValues);
-  assert_equals(decodedStruct.f0, mojo.test.FloatNumberValues.V0);
-  assert_equals(decodedStruct.f1, mojo.test.FloatNumberValues.V1);
-  assert_equals(decodedStruct.f2, mojo.test.FloatNumberValues.V2);
-  assert_equals(decodedStruct.f3, mojo.test.FloatNumberValues.V3);
-  assert_equals(decodedStruct.f4, mojo.test.FloatNumberValues.V4);
-  assert_equals(decodedStruct.f5, mojo.test.FloatNumberValues.V5);
-  assert_equals(decodedStruct.f6, mojo.test.FloatNumberValues.V6);
-  assert_equals(decodedStruct.f7, mojo.test.FloatNumberValues.V7);
-  assert_equals(decodedStruct.f8, mojo.test.FloatNumberValues.V8);
-  assert_equals(decodedStruct.f9, mojo.test.FloatNumberValues.V9);
-}, 'float number values');
-
-test(() => {
-  var decodedStruct = structEncodeDecode(new mojo.test.IntegerNumberValues);
-  assert_equals(decodedStruct.f0, mojo.test.IntegerNumberValues.V0);
-  assert_equals(decodedStruct.f1, mojo.test.IntegerNumberValues.V1);
-  assert_equals(decodedStruct.f2, mojo.test.IntegerNumberValues.V2);
-  assert_equals(decodedStruct.f3, mojo.test.IntegerNumberValues.V3);
-  assert_equals(decodedStruct.f4, mojo.test.IntegerNumberValues.V4);
-  assert_equals(decodedStruct.f5, mojo.test.IntegerNumberValues.V5);
-  assert_equals(decodedStruct.f6, mojo.test.IntegerNumberValues.V6);
-  assert_equals(decodedStruct.f7, mojo.test.IntegerNumberValues.V7);
-  assert_equals(decodedStruct.f8, mojo.test.IntegerNumberValues.V8);
-  assert_equals(decodedStruct.f9, mojo.test.IntegerNumberValues.V9);
-  assert_equals(decodedStruct.f10, mojo.test.IntegerNumberValues.V10);
-  assert_equals(decodedStruct.f11, mojo.test.IntegerNumberValues.V11);
-  assert_equals(decodedStruct.f12, mojo.test.IntegerNumberValues.V12);
-  assert_equals(decodedStruct.f13, mojo.test.IntegerNumberValues.V13);
-  assert_equals(decodedStruct.f14, mojo.test.IntegerNumberValues.V14);
-  assert_equals(decodedStruct.f15, mojo.test.IntegerNumberValues.V15);
-  assert_equals(decodedStruct.f16, mojo.test.IntegerNumberValues.V16);
-  assert_equals(decodedStruct.f17, mojo.test.IntegerNumberValues.V17);
-  assert_equals(decodedStruct.f18, mojo.test.IntegerNumberValues.V18);
-  assert_equals(decodedStruct.f19, mojo.test.IntegerNumberValues.V19);
-}, 'integer number values');
-
-test(() => {
-  var decodedStruct =
-      structEncodeDecode(new mojo.test.UnsignedNumberValues);
-  assert_equals(decodedStruct.f0, mojo.test.UnsignedNumberValues.V0);
-  assert_equals(decodedStruct.f1, mojo.test.UnsignedNumberValues.V1);
-  assert_equals(decodedStruct.f2, mojo.test.UnsignedNumberValues.V2);
-  assert_equals(decodedStruct.f3, mojo.test.UnsignedNumberValues.V3);
-  assert_equals(decodedStruct.f4, mojo.test.UnsignedNumberValues.V4);
-  assert_equals(decodedStruct.f5, mojo.test.UnsignedNumberValues.V5);
-  assert_equals(decodedStruct.f6, mojo.test.UnsignedNumberValues.V6);
-  assert_equals(decodedStruct.f7, mojo.test.UnsignedNumberValues.V7);
-  assert_equals(decodedStruct.f8, mojo.test.UnsignedNumberValues.V8);
-  assert_equals(decodedStruct.f9, mojo.test.UnsignedNumberValues.V9);
-  assert_equals(decodedStruct.f10, mojo.test.UnsignedNumberValues.V10);
-  assert_equals(decodedStruct.f11, mojo.test.UnsignedNumberValues.V11);
-}, 'unsigned number values');
-
-test(() => {
-  var bitArraysStruct = new mojo.test.BitArrayValues({
-    // array<bool, 1> f0;
-    f0: [true],
-    // array<bool, 7> f1;
-    f1: [true, false, true, false, true, false, true],
-    // array<bool, 9> f2;
-    f2: [true, false, true, false, true, false, true, false, true],
-    // array<bool> f3;
-    f3: [true, false, true, false, true, false, true, false],
-    // array<array<bool>> f4;
-    f4: [[true], [false], [true, false], [true, false, true, false]],
-    // array<array<bool>?> f5;
-    f5: [[true], null, null, [true, false, true, false]],
-    // array<array<bool, 2>?> f6;
-    f6: [[true, false], [true, false], [true, false]],
-  });
-  var decodedStruct = structEncodeDecode(bitArraysStruct);
-  assert_weak_equals(decodedStruct, bitArraysStruct);
-}, 'bit array values');
-
-</script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/union.html b/third_party/blink/web_tests/http/tests/mojo/union.html
deleted file mode 100644
index 522f0133..0000000
--- a/third_party/blink/web_tests/http/tests/mojo/union.html
+++ /dev/null
@@ -1,189 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/js-test-resources/testharness-helpers.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/test_unions.mojom.js"></script>
-<script>
-'use strict';
-
-test(() => {
-  var u = new mojo.test.PodUnion();
-  assert_equals(u.$data, null);
-  assert_equals(u.$tag, undefined);
-
-  u.fUint32 = 32;
-
-  assert_equals(u.fUint32, 32);
-  assert_equals(u.$tag, mojo.test.PodUnion.Tags.fUint32);
-
-  var u = new mojo.test.PodUnion({fUint64: 64});
-  assert_equals(u.fUint64, 64);
-  assert_equals(u.$tag, mojo.test.PodUnion.Tags.fUint64);
-  assert_throws_js(ReferenceError, function() {var v = u.fUint32;});
-
-  assert_throws_js(TypeError, function() {
-    var u = new mojo.test.PodUnion({
-      fUint64: 64,
-      fUint32: 32,
-    });
-  });
-
-  assert_throws_js(ReferenceError, function() {
-    var u = new mojo.test.PodUnion({ foo: 64 });
-  });
-
-  assert_throws_js(TypeError, function() {
-    var u = new mojo.test.PodUnion([1,2,3,4]);
-  });
-}, 'constructors');
-
-function structEncodeDecode(struct) {
-  var structClass = struct.constructor;
-  var builder = new mojo.internal.MessageV0Builder(1234,
-                                                   structClass.encodedSize);
-  builder.encodeStruct(structClass, struct);
-
-  var message = builder.finish();
-
-  var messageValidator = new mojo.internal.Validator(message);
-  var err = structClass.validate(messageValidator,
-                                 mojo.internal.kMessageV0HeaderSize);
-  assert_equals(err, mojo.internal.validationError.NONE);
-
-  var reader = new mojo.internal.MessageReader(message);
-  var view = reader.decoder.buffer.dataView;
-
-  return reader.decodeStruct(structClass);
-}
-
-test(() => {
-  var s = new mojo.test.WrapperStruct({
-    podUnion: new mojo.test.PodUnion({fUint64: 64})
-  });
-
-  var decoded = structEncodeDecode(s);
-  assert_weak_equals(decoded, s);
-
-  var s = new mojo.test.WrapperStruct({
-    podUnion: new mojo.test.PodUnion({fBool : true})
-  });
-
-  var decoded = structEncodeDecode(s);
-  assert_equals(decoded.podUnion.$tag, mojo.test.PodUnion.Tags.fBool);
-  assert_true(decoded.podUnion.fBool);
-
-  var s = new mojo.test.WrapperStruct({
-    objectUnion: new mojo.test.ObjectUnion({
-      fDummy: new mojo.test.DummyStruct({fInt8: 8})
-    })
-  });
-
-  var decoded = structEncodeDecode(s);
-  assert_weak_equals(decoded, s);
-
-  var s = new mojo.test.WrapperStruct({
-    objectUnion: new mojo.test.ObjectUnion({fArrayInt8: [1, 2, 3]})
-  });
-
-  var decoded = structEncodeDecode(s);
-  assert_weak_equals(decoded, s);
-
-  var s = new mojo.test.WrapperStruct({
-    objectUnion: new mojo.test.ObjectUnion({
-      fMapInt8: new Map([
-        ["first", 1],
-        ["second", 2],
-      ])
-    })
-  });
-
-  var decoded = structEncodeDecode(s);
-  assert_weak_equals(decoded, s);
-
-  // Encoding a union with no member set is an error.
-  var s = new mojo.test.WrapperStruct({
-    objectUnion: new mojo.test.ObjectUnion()});
-  assert_throws_js(TypeError, function() {
-    structEncodeDecode(s);
-  });
-}, 'basic encoding');
-
-test(() => {
-  var s = new mojo.test.SmallStruct({
-    podUnionArray: [
-      new mojo.test.PodUnion({fUint32: 32}),
-      new mojo.test.PodUnion({fUint64: 64}),
-    ]
-  });
-
-  var decoded = structEncodeDecode(s);
-  assert_weak_equals(decoded, s);
-}, 'unions in array encoding');
-
-test(() => {
-  var s = new mojo.test.SmallStruct({
-    podUnionMap: new Map([
-      ["thirty-two", new mojo.test.PodUnion({fUint32: 32})],
-      ["sixty-four", new mojo.test.PodUnion({fUint64: 64})],
-    ])
-  });
-
-  var decoded = structEncodeDecode(s);
-  assert_weak_equals(decoded, s);
-}, 'unions in map encoding');
-
-test(() => {
-  var s = new mojo.test.WrapperStruct({
-    objectUnion: new mojo.test.ObjectUnion({
-      fPodUnion: new mojo.test.PodUnion({fUint32: 32})
-    })
-  });
-  var decoded = structEncodeDecode(s);
-  assert_weak_equals(decoded, s);
-}, 'nested unions encoding');
-
-function structValidate(struct) {
-  var structClass = struct.constructor;
-  var builder = new mojo.internal.MessageV0Builder(1234,
-                                                   structClass.encodedSize);
-  builder.encodeStruct(structClass, struct);
-
-  var message = builder.finish();
-
-  var messageValidator = new mojo.internal.Validator(message);
-  return structClass.validate(messageValidator,
-                              mojo.internal.kMessageV0HeaderSize);
-}
-
-test(() => {
-  var s = new mojo.test.WrapperStruct({
-    objectUnion: new mojo.test.ObjectUnion({fDummy: null})
-  });
-
-  var err = structValidate(s);
-  assert_equals(err, mojo.internal.validationError.UNEXPECTED_NULL_POINTER);
-
-  var s = new mojo.test.WrapperStruct({
-    objectUnion: new mojo.test.ObjectUnion({fNullable: null})
-  });
-
-  var err = structValidate(s);
-  assert_equals(err, mojo.internal.validationError.NONE);
-}, 'null union member validation');
-
-test(() => {
-  var s = new mojo.test.SmallStructNonNullableUnion({podUnion: null});
-
-  var err = structValidate(s);
-  assert_equals(err, mojo.internal.validationError.UNEXPECTED_NULL_UNION);
-
-  var s = new mojo.test.WrapperStruct({
-    objectUnion: new mojo.test.ObjectUnion({fPodUnion: null})
-  });
-
-  var err = structValidate(s);
-  assert_equals(err, mojo.internal.validationError.UNEXPECTED_NULL_UNION);
-}, 'null union validation');
-
-</script>
diff --git a/third_party/blink/web_tests/http/tests/mojo/validation.html b/third_party/blink/web_tests/http/tests/mojo/validation.html
deleted file mode 100644
index 8014b2a..0000000
--- a/third_party/blink/web_tests/http/tests/mojo/validation.html
+++ /dev/null
@@ -1,297 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom.js"></script>
-<script src="resources/validation_test_input_parser.js"></script>
-<script>
-'use strict';
-
-var noError = mojo.internal.validationError.NONE;
-
-function checkData(data, expectedData, input) {
-  assert_equals(data.byteLength, expectedData.byteLength,
-      'message length (' + data.byteLength + ') doesn\'t match ' +
-      'expected length: ' + expectedData.byteLength + ' for ' + input);
-
-  for (var i = 0; i < data.byteLength; i++) {
-    assert_equals(data.getUint8(i), expectedData.getUint8(i),
-        'message data mismatch at byte offset ' + i + 'for' + input);
-  }
-}
-
-test(() => {
-  var input = '[f]+.3e9 [d]-10.03';
-  var msg = mojo.test.parseTestMessage(input);
-  var expectedData = new mojo.internal.Buffer(12);
-  expectedData.setFloat32(0, +.3e9);
-  expectedData.setFloat64(4, -10.03);
-  checkData(msg.buffer, expectedData, input);
-}, 'message parser: float items');
-
-test(() => {
-  var input = '[u1]0x10// hello world !! \n\r  \t [u2]65535 \n' +
-      '[u4]65536 [u8]0xFFFFFFFFFFFFF 0 0Xff';
-  var msg = mojo.test.parseTestMessage(input);
-  var expectedData = new mojo.internal.Buffer(17);
-  expectedData.setUint8(0, 0x10);
-  expectedData.setUint16(1, 65535);
-  expectedData.setUint32(3, 65536);
-  expectedData.setUint64(7, 0xFFFFFFFFFFFFF);
-  expectedData.setUint8(15, 0);
-  expectedData.setUint8(16, 0xff);
-  checkData(msg.buffer, expectedData, input);
-}, 'message parser: unsigned integer items');
-
-test(() => {
-  var input = '[s8]-0x800 [s1]-128\t[s2]+0 [s4]-40';
-  var msg = mojo.test.parseTestMessage(input);
-  var expectedData = new mojo.internal.Buffer(15);
-  expectedData.setInt64(0, -0x800);
-  expectedData.setInt8(8, -128);
-  expectedData.setInt16(9, 0);
-  expectedData.setInt32(11, -40);
-  checkData(msg.buffer, expectedData, input);
-}, 'message parser: signed integer items');
-
-test(() => {
-  var input = '[b]00001011 [b]10000000  // hello world\n [b]00000000';
-  var msg = mojo.test.parseTestMessage(input);
-  var expectedData = new mojo.internal.Buffer(3);
-  expectedData.setUint8(0, 11);
-  expectedData.setUint8(1, 128);
-  expectedData.setUint8(2, 0);
-  checkData(msg.buffer, expectedData, input);
-}, 'message parser: byte items');
-
-test(() => {
-  var input = '[dist4]foo 0 [dist8]bar 0 [anchr]foo [anchr]bar';
-  var msg = mojo.test.parseTestMessage(input);
-  var expectedData = new mojo.internal.Buffer(14);
-  expectedData.setUint32(0, 14);
-  expectedData.setUint8(4, 0);
-  expectedData.setUint64(5, 9);
-  expectedData.setUint8(13, 0);
-  checkData(msg.buffer, expectedData, input);
-}, 'message parser: anchors');
-
-test(() => {
-  var input = '// This message has handles! \n[handles]50 [u8]2';
-  var msg = mojo.test.parseTestMessage(input);
-  var expectedData = new mojo.internal.Buffer(8);
-  expectedData.setUint64(0, 2);
-
-  assert_equals(msg.handleCount, 50,
-      'wrong handle count (' + msg.handleConut + ') for ' + input);
-  checkData(msg.buffer, expectedData, input);
-}, 'message parser: handles');
-
-test(() => {
-  var msg = mojo.test.parseTestMessage('');
-  assert_equals(msg.buffer.byteLength, 0, 'expected empty message for ');
-}, 'message parser: empty input');
-
-test(() => {
-  var input = '    \t  // hello world \n\r \t// the answer is 42   ';
-  var msg = mojo.test.parseTestMessage(input);
-  assert_equals(msg.buffer.byteLength, 0,
-      'expected empty message for ' + input);
-}, 'message parser: blank input');
-
-test(() => {
-  function parserShouldFail(input) {
-    assert_throws_js(mojo.test.InputError, function() {
-      mojo.test.parseTestMessage(input);
-    });
-  }
-
-  ['/ hello world',
-   '[u1]x',
-   '[u2]-1000',
-   '[u1]0x100',
-   '[s2]-0x8001',
-   '[b]1',
-   '[b]1111111k',
-   '[dist4]unmatched',
-   '[anchr]hello [dist8]hello',
-   '[dist4]a [dist4]a [anchr]a',
-   // '[dist4]a [anchr]a [dist4]a [anchr]a',
-   '0 [handles]50'
-  ].forEach(parserShouldFail);
-}, 'message parser: invalid input');
-
-function fetchLite(url) {
-  return new Promise((resolve, reject) => {
-    var xhr = new XMLHttpRequest();
-    xhr.open('GET', url);
-    xhr.onreadystatechange = () => {
-      if (xhr.readyState != 4) return;
-      resolve(xhr.responseText);
-    };
-    xhr.send();
-  });
-}
-
-function getMessageTestFiles(prefix) {
-  let dataDirectory =
-      '/gen/layout_test_data/mojo/public/interfaces/bindings/tests/data/validation';
-  return fetchLite(dataDirectory + '_index.txt').then((response) => {
-    assert_not_equals(response, null);
-    var testFiles = response.split(/\s+/);
-    assert_greater_than(testFiles.length, 0);
-    return testFiles.filter(function(s) {
-      return s.substr(-5) == '.data' && s.indexOf(prefix) == 0;
-    }).map(function(s) {
-      return dataDirectory + '/' + s.slice(0, -5);
-    });
-  });
-}
-
-function readTestMessage(filename) {
-  return fetchLite(filename + '.data').then((response) => {
-    assert_not_equals(response, null);
-    return mojo.test.parseTestMessage(response);
-  });
-}
-
-function readTestExpected(filename) {
-  return fetchLite(filename + '.expected').then((response) => {
-    assert_not_equals(response, null);
-    return response.trim();
-  });
-}
-
-async function checkValidationResult(testFile, err) {
-  var actualResult = (err === noError) ? 'PASS' : err;
-  var expectedResult = await readTestExpected(testFile);
-  assert_equals(actualResult, expectedResult,
-      '[Test message validation failed: ' + testFile + ' ]');
-}
-
-async function testMessageValidation(prefix, filters) {
-  var testFiles = await getMessageTestFiles(prefix);
-  assert_greater_than(testFiles.length, 0);
-
-  for (var i = 0; i < testFiles.length; i++) {
-    // TODO(hansmuller) Temporarily skipping array pointer overflow tests
-    // because JS numbers are limited to 53 bits.
-    // TODO(rudominer): Temporarily skipping 'no-such-method',
-    // 'invalid_request_flags', and 'invalid_response_flags' until additional
-    // logic in *RequestValidator and *ResponseValidator is ported from
-    // cpp to js.
-    // TODO(crbug/640298): Implement max recursion depth for JS.
-    // TODO(crbug/628104): Support struct map keys for JS.
-    if (testFiles[i].indexOf('overflow') != -1 ||
-        testFiles[i].indexOf('conformance_mthd19') != -1 ||
-        testFiles[i].indexOf('conformance_mthd20') != -1 ||
-        testFiles[i].indexOf('no_such_method') != -1 ||
-        testFiles[i].indexOf('invalid_request_flags') != -1 ||
-        testFiles[i].indexOf('invalid_response_flags') != -1) {
-      console.log('[Skipping ' + testFiles[i] + ']');
-      continue;
-    }
-
-    var testMessage = await readTestMessage(testFiles[i]);
-    var handles = new Array(testMessage.handleCount);
-    var message = new mojo.internal.Message(testMessage.buffer, handles);
-    var messageValidator = new mojo.internal.Validator(message);
-
-    var err = messageValidator.validateMessageHeader();
-    for (var j = 0; err === noError && j < filters.length; ++j)
-      err = filters[j](messageValidator);
-
-    await checkValidationResult(testFiles[i], err);
-  }
-}
-
-promise_test(() => {
-  return testMessageValidation('conformance_', [
-      mojo.test.ConformanceTestInterface.validateRequest]);
-}, 'conformance message validation');
-
-promise_test(() => {
-  return testMessageValidation('boundscheck_', [
-      mojo.test.BoundsCheckTestInterface.validateRequest]);
-}, 'bounds check message validation');
-
-promise_test(() => {
-  return testMessageValidation('resp_conformance_', [
-      mojo.test.ConformanceTestInterface.validateResponse]);
-}, 'response conformance message validation');
-
-promise_test(() => {
-  return testMessageValidation('resp_boundscheck_', [
-      mojo.test.BoundsCheckTestInterface.validateResponse]);
-}, 'response bounds check message validation');
-
-async function testIntegratedMessageValidation(testFilesPattern, endpoint) {
-  var testFiles = await getMessageTestFiles(testFilesPattern);
-  assert_greater_than(testFiles.length, 0);
-
-  var testMessagePipe = Mojo.createMessagePipe();
-  assert_equals(testMessagePipe.result, Mojo.RESULT_OK);
-
-  endpoint.bind(testMessagePipe.handle1);
-  if (endpoint instanceof mojo.InterfacePtrController) {
-    // Make sure the router and connector are initialized.
-    endpoint.getProxy();
-  }
-
-  var originalReceiver = endpoint.router_.connector_.incomingReceiver_.accept;
-  var nextMessageCallback = null;
-  endpoint.router_.connector_.incomingReceiver_.accept = function(message) {
-    var result = originalReceiver(message);
-    if (nextMessageCallback) {
-      setTimeout(() => {
-        nextMessageCallback();
-        nextMessageCallback = null;
-      }, 0);
-    }
-    return result;
-  }
-
-  var observer = mojo.internal.ValidationErrorObserverForTesting.getInstance();
-
-  for (var i = 0; i < testFiles.length; i++) {
-    var testMessage = await readTestMessage(testFiles[i]);
-    var handles = new Array(testMessage.handleCount);
-
-    await new Promise((resolve, reject) => {
-      nextMessageCallback = resolve;
-
-      var writeMessageValue = testMessagePipe.handle0.writeMessage(
-          new Uint8Array(testMessage.buffer.arrayBuffer),
-          new Array(testMessage.handleCount));
-      assert_equals(writeMessageValue, Mojo.RESULT_OK);
-    });
-    await checkValidationResult(testFiles[i], observer.lastError);
-    observer.reset();
-  }
-
-  testMessagePipe.handle0.close();
-}
-
-promise_test(() => {
-  return testIntegratedMessageValidation(
-      'integration_msghdr',
-      new mojo.Binding(mojo.test.IntegrationTestInterface, {}))
-    .then(() => {
-      return testIntegratedMessageValidation(
-          'integration_msghdr',
-          new mojo.test.IntegrationTestInterfacePtr().ptr);
-    });
-}, 'integrated message header validation');
-
-promise_test(() => {
-  return testIntegratedMessageValidation(
-      'integration_intf_rqst',
-      new mojo.Binding(mojo.test.IntegrationTestInterface, {}));
-}, 'integrated request message validation');
-
-promise_test(() => {
-  return testIntegratedMessageValidation(
-      'integration_intf_resp',
-      new mojo.test.IntegrationTestInterfacePtr().ptr);
-}, 'integrated response message validation');
-
-</script>
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/stable/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/stable/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt
new file mode 100644
index 0000000..16ea11b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/stable/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt
@@ -0,0 +1,28 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='composited-parent'",
+      "position": [-100, -100],
+      "bounds": [200, 200],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [330, 330, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/virtual/stable/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt b/third_party/blink/web_tests/virtual/stable/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt
index 16ea11b..ce951477 100644
--- a/third_party/blink/web_tests/virtual/stable/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt
@@ -11,6 +11,19 @@
       "position": [-100, -100],
       "bounds": [200, 200],
       "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='software-parent'",
+      "bounds": [100, 100],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='software-child'",
+      "position": [100, 100],
+      "bounds": [50, 50],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF"
     }
   ],
   "transforms": [
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 2e3fedc6..2f16e22 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-10-4-142-g0636dc8af
-Revision: 0636dc8af1e502c343b126b50f3a0dbec8f3fc26
+Version: VER-2-10-4-143-gfd7f92b6f
+Revision: fd7f92b6f008e0684c3eb8308aca92e20382506e
 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/tools/accessibility/inspect/ax_event_server.cc b/tools/accessibility/inspect/ax_event_server.cc
index 34912311..a5cb9ff5 100644
--- a/tools/accessibility/inspect/ax_event_server.cc
+++ b/tools/accessibility/inspect/ax_event_server.cc
@@ -5,13 +5,15 @@
 #include "tools/accessibility/inspect/ax_event_server.h"
 
 #include "base/bind.h"
+#include "content/public/browser/ax_inspect_factory.h"
 
 namespace tools {
 
 AXEventServer::AXEventServer(base::ProcessId pid,
                              const ui::AXTreeSelector& selector)
-    : recorder_(
-          content::AccessibilityEventRecorder::Create(nullptr, pid, selector)) {
+    : recorder_(content::AXInspectFactory::CreatePlatformRecorder(nullptr,
+                                                                  pid,
+                                                                  selector)) {
   recorder_->ListenToEvents(
       base::BindRepeating(&AXEventServer::OnEvent, base::Unretained(this)));
 }
diff --git a/tools/accessibility/inspect/ax_event_server.h b/tools/accessibility/inspect/ax_event_server.h
index f6d8074..996a3ae 100644
--- a/tools/accessibility/inspect/ax_event_server.h
+++ b/tools/accessibility/inspect/ax_event_server.h
@@ -7,7 +7,8 @@
 
 #include "base/process/process_handle.h"
 #include "build/build_config.h"
-#include "content/browser/accessibility/accessibility_event_recorder.h"
+#include "ui/accessibility/platform/inspect/ax_event_recorder.h"
+#include "ui/accessibility/platform/inspect/ax_inspect.h"
 
 #if defined(OS_WIN)
 #include "base/win/scoped_com_initializer.h"
@@ -30,7 +31,7 @@
   // Only one COM initializer per thread is permitted.
   base::win::ScopedCOMInitializer com_initializer_;
 #endif
-  std::unique_ptr<content::AccessibilityEventRecorder> recorder_;
+  std::unique_ptr<ui::AXEventRecorder> recorder_;
 
   DISALLOW_COPY_AND_ASSIGN(AXEventServer);
 };
diff --git a/tools/accessibility/inspect/ax_tree_server.cc b/tools/accessibility/inspect/ax_tree_server.cc
index 745e217..59390517 100644
--- a/tools/accessibility/inspect/ax_tree_server.cc
+++ b/tools/accessibility/inspect/ax_tree_server.cc
@@ -19,6 +19,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
+#include "content/public/browser/ax_inspect_factory.h"
 
 using ui::AXTreeFormatter;
 using ui::AXTreeSelector;
diff --git a/tools/accessibility/inspect/ax_tree_server.h b/tools/accessibility/inspect/ax_tree_server.h
index 38926aac..be96184 100644
--- a/tools/accessibility/inspect/ax_tree_server.h
+++ b/tools/accessibility/inspect/ax_tree_server.h
@@ -10,7 +10,7 @@
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "build/build_config.h"
-#include "content/public/browser/ax_inspect_factory.h"
+#include "ui/accessibility/platform/inspect/ax_tree_formatter.h"
 
 #if defined(OS_WIN)
 #include "base/win/scoped_com_initializer.h"
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index a0455fb..2664dbf6 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -152,6 +152,10 @@
     "META": {"sizes": {"includes": [100]}},
     "includes": [1640],
   },
+  "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/memories/resources.grd": {
+    "META": {"sizes": {"includes": [40]}},
+    "includes": [1660],
+  },
   "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/new_tab_page/resources.grd": {
     "META": {"sizes": {"includes": [200]}},
     "includes": [1680],
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 811d2ae2..9a33257 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -896,6 +896,7 @@
       'lacros-amd64-generic-rel': 'chromeos_amd64-generic_lacros_rel',
       'linux-chromeos-inverse-fieldtrials-fyi-rel': 'chromeos_with_codecs_release_trybot_invert_fieldtrials',
       'linux-chromeos-rel': 'chromeos_with_codecs_release_trybot_code_coverage',
+      'linux-chromeos-js-code-coverage': 'chromeos_with_codecs_release_trybot_js_cpp_code_coverage',
       'linux-chromeos-compile-dbg': 'chromeos_with_codecs_debug_bot',
       'linux-chromeos-dbg': 'chromeos_with_codecs_debug_bot',
       'linux-lacros-rel': 'lacros_on_linux_release_trybot',
@@ -1741,6 +1742,12 @@
       'use_clang_coverage', 'partial_code_coverage_instrumentation',
     ],
 
+    'chromeos_with_codecs_release_trybot_js_cpp_code_coverage': [
+      'chromeos_with_codecs', 'release_trybot', 'no_symbols',
+      'use_clang_coverage', 'partial_code_coverage_instrumentation',
+      'use_javascript_coverage', 'no_webui_optimize',
+    ],
+
     'chromeos_with_codecs_release_trybot_invert_fieldtrials': [
       'chromeos_with_codecs', 'release_trybot', 'no_symbols', 'invert_fieldtrials',
     ],
@@ -3148,6 +3155,10 @@
       'gn_args': 'enable_keystone_registration_framework=false',
     },
 
+    'no_webui_optimize': {
+      'gn_args': 'optimize_webui=false',
+    },
+
     'no_resource_whitelisting': {
       'gn_args': 'enable_resource_allowlist_generation=false',
     },
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json b/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json
index 2846c18..241a516 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json
@@ -164,6 +164,22 @@
       "use_goma": true
     }
   },
+  "linux-chromeos-js-code-coverage": {
+    "gn_args": {
+      "coverage_instrumentation_input_file": "//.code-coverage/files_to_instrument.txt",
+      "dcheck_always_on": true,
+      "ffmpeg_branding": "ChromeOS",
+      "is_component_build": false,
+      "is_debug": false,
+      "optimize_webui": false,
+      "proprietary_codecs": true,
+      "symbol_level": 0,
+      "target_os": "chromeos",
+      "use_clang_coverage": true,
+      "use_goma": true,
+      "use_javascript_coverage": true
+    }
+  },
   "linux-chromeos-rel": {
     "gn_args": {
       "coverage_instrumentation_input_file": "//.code-coverage/files_to_instrument.txt",
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 16a6a5b..f614568 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -43442,6 +43442,7 @@
   <int value="-1480926949" label="MaterialDesignBookmarks:enabled"/>
   <int value="-1480866718" label="ash-disable-login-dim-and-blur"/>
   <int value="-1480606359" label="AssistantIntentPageUrl:enabled"/>
+  <int value="-1478929417" label="MojoLinuxChannelSharedMem:enabled"/>
   <int value="-1478876902" label="disable-permission-action-reporting"/>
   <int value="-1478137998" label="lite-video-default-downlink-bandwidth-kbps"/>
   <int value="-1477686864" label="OmniboxRichAutocompletion:enabled"/>
@@ -43906,6 +43907,7 @@
       label="SupervisedUserCommittedInterstitials:enabled"/>
   <int value="-1096595907" label="disable-new-virtual-keyboard-behavior"/>
   <int value="-1095947169" label="ModalPermissionDialogView:disabled"/>
+  <int value="-1093135462" label="DesktopPWAsAttentionBadgingCrOS:disabled"/>
   <int value="-1092211161" label="BluetoothWbsDogfood:disabled"/>
   <int value="-1088804127" label="DuetTabStripIntegrationAndroid:disabled"/>
   <int value="-1086728979" label="kids-management-url-classification:enabled"/>
@@ -44284,6 +44286,8 @@
   <int value="-747072690" label="NtpRepeatableQueries:disabled"/>
   <int value="-746328467" label="ExpensiveBackgroundTimerThrottling:disabled"/>
   <int value="-745082968" label="SyncDeviceInfoInTransportMode:disabled"/>
+  <int value="-745005043"
+      label="enable-experimental-accessibility-switch-access-setup-guide"/>
   <int value="-744159181" label="disable-spdy-proxy-dev-auth-origin"/>
   <int value="-743590125" label="TabEngagementReportingAndroid:enabled"/>
   <int value="-743103250" label="enable-linkable-ephemeral-apps"/>
@@ -44388,6 +44392,7 @@
   <int value="-648925189" label="ExploreSites:enabled"/>
   <int value="-645455405" label="MacViewsNativeDialogs:enabled"/>
   <int value="-643217597" label="EduCoexistenceConsentLog:enabled"/>
+  <int value="-642346675" label="DesktopPWAsAttentionBadgingCrOS:enabled"/>
   <int value="-641820371" label="EnableCustomMacPaperSizes:enabled"/>
   <int value="-641719457" label="disable-compositor-touch-hit-testing"/>
   <int value="-640191786" label="DesktopPWAsWithoutExtensions:enabled"/>
@@ -45997,7 +46002,6 @@
   <int value="887011602" label="enable-spelling-auto-correct"/>
   <int value="889837286" label="EnableHostnameSetting:enabled"/>
   <int value="892899792" label="MaterialDesignIncognitoNTP:disabled"/>
-  <int value="895622710" label="desktop-pwas-attention-badging-cros"/>
   <int value="898311758" label="ReaderMode:disabled"/>
   <int value="900614020" label="ContentSuggestionsShowSummary:disabled"/>
   <int value="902209599" label="ShelfHotseat:enabled"/>
@@ -46922,6 +46926,7 @@
       label="OmniboxUIExperimentVerticalMarginLimitToNonTouchOnly:disabled"/>
   <int value="1760946944" label="MacViewsAutofillPopup:disabled"/>
   <int value="1762320532" label="AutofillKeyboardAccessory:enabled"/>
+  <int value="1764618580" label="MojoLinuxChannelSharedMem:disabled"/>
   <int value="1766676896" label="affiliation-based-matching:disabled"/>
   <int value="1767411597" label="DisallowUnsafeHttpDownloads:enabled"/>
   <int value="1768759000" label="AutofillProfileServerValidation:disabled"/>
@@ -75986,6 +75991,9 @@
 </enum>
 
 <enum name="UpdateAppBadgeMacResult">
+  <obsolete>
+    Removed in M88 as it's no longer needed.
+  </obsolete>
   <summary>The result from updating App Badge on macOS.</summary>
   <int value="0" label="success"/>
   <int value="1" label="No app shim manager"/>
diff --git a/tools/metrics/histograms/histograms_xml/apps/histograms.xml b/tools/metrics/histograms/histograms_xml/apps/histograms.xml
index 07406b37..508d6fb 100644
--- a/tools/metrics/histograms/histograms_xml/apps/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/apps/histograms.xml
@@ -1207,7 +1207,7 @@
 </histogram>
 
 <histogram name="Apps.CreateShortcutIcon.Linux.Result"
-    enum="WebAppCreateShortcutIconLinuxResult" expires_after="M90">
+    enum="WebAppCreateShortcutIconLinuxResult" expires_after="M95">
   <owner>phillis@chromium.org</owner>
   <owner>cmumford@chromium.org</owner>
   <summary>
@@ -1216,7 +1216,7 @@
 </histogram>
 
 <histogram name="Apps.CreateShortcuts.Linux.Result"
-    enum="WebAppCreateShortcutLinuxResult" expires_after="M90">
+    enum="WebAppCreateShortcutLinuxResult" expires_after="M95">
   <owner>phillis@chromium.org</owner>
   <owner>cmumford@chromium.org</owner>
   <summary>
@@ -1225,7 +1225,7 @@
 </histogram>
 
 <histogram name="Apps.CreateShortcuts.Mac.Result"
-    enum="WebAppCreateShortcutMacResult" expires_after="M90">
+    enum="WebAppCreateShortcutMacResult" expires_after="M95">
   <owner>phillis@chromium.org</owner>
   <owner>cmumford@chromium.org</owner>
   <summary>
@@ -1247,7 +1247,7 @@
 
 <histogram name="Apps.FileHandler.Registration.Linux.RecreateShortcut.Result"
     enum="FileHandlerRegistrationLinuxRecreateShortcutResult"
-    expires_after="M90">
+    expires_after="M95">
   <owner>phillis@chromium.org</owner>
   <owner>cmumford@chromium.org</owner>
   <summary>
@@ -1257,7 +1257,7 @@
 </histogram>
 
 <histogram name="Apps.FileHandler.Registration.Linux.Result"
-    enum="FileHandlerRegistrationLinuxResult" expires_after="M90">
+    enum="FileHandlerRegistrationLinuxResult" expires_after="M95">
   <owner>phillis@chromium.org</owner>
   <owner>cmumford@chromium.org</owner>
   <summary>
@@ -1266,7 +1266,7 @@
 </histogram>
 
 <histogram name="Apps.FileHandler.Registration.Win.Result"
-    enum="FileHandlerRegistrationWinResult" expires_after="M90">
+    enum="FileHandlerRegistrationWinResult" expires_after="M95">
   <owner>phillis@chromium.org</owner>
   <owner>cmumford@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
index 32fc5801..45326fa 100644
--- a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
@@ -357,7 +357,7 @@
   </summary>
 </histogram>
 
-<histogram name="Chromeos.DiagnosticsUi.{RoutineType}Result"
+<histogram name="ChromeOS.DiagnosticsUi.{RoutineType}Result"
     enum="CrosDiagnosticsRoutineResult" expires_after="2021-07-15">
   <owner>baileyberro@chromium.org</owner>
   <owner>cros-peripherals@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml b/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml
index a8c51a51..dc3ea3e 100644
--- a/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml
@@ -105,6 +105,9 @@
 
 <histogram name="DataReductionProxy.ConfigService.AuthExpired"
     enum="BooleanExpired" expires_after="M90">
+  <obsolete>
+    Obsoleted Jan 2021.
+  </obsolete>
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
@@ -120,6 +123,9 @@
 
 <histogram name="DataReductionProxy.ConfigService.ConnectionSetupTime"
     units="ms" expires_after="M90">
+  <obsolete>
+    Obsoleted Jan 2021.
+  </obsolete>
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
@@ -132,6 +138,9 @@
 <histogram
     name="DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess"
     units="units" expires_after="M90">
+  <obsolete>
+    Obsoleted Jan 2021.
+  </obsolete>
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
@@ -146,6 +155,9 @@
 
 <histogram name="DataReductionProxy.ConfigService.FetchLatency" units="ms"
     expires_after="M90">
+  <obsolete>
+    Obsoleted Jan 2021.
+  </obsolete>
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
@@ -158,6 +170,9 @@
 
 <histogram name="DataReductionProxy.ConfigService.FetchResponseCode"
     enum="HttpResponseCode" expires_after="M90">
+  <obsolete>
+    Obsoleted Jan 2021.
+  </obsolete>
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
@@ -168,6 +183,9 @@
 
 <histogram name="DataReductionProxy.ConfigService.HttpRequestRTT" units="ms"
     expires_after="2021-06-20">
+  <obsolete>
+    Obsoleted Jan 2021.
+  </obsolete>
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
@@ -178,6 +196,9 @@
 
 <histogram name="DataReductionProxy.ConfigService.HTTPRequests"
     enum="DataReductionProxyConfigServiceHTTPRequests" expires_after="M90">
+  <obsolete>
+    Obsoleted Jan 2021.
+  </obsolete>
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
@@ -193,6 +214,9 @@
 
 <histogram name="DataReductionProxy.ConfigService.MainFrames"
     enum="DataReductionProxyConfigServiceMainFrames" expires_after="M90">
+  <obsolete>
+    Obsoleted Jan 2021.
+  </obsolete>
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml
index b7a9b532..e12d809b 100644
--- a/tools/metrics/histograms/histograms_xml/others/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -1217,6 +1217,9 @@
 
 <histogram name="Badging.AppBadgeUpdate.Mac.Result"
     enum="UpdateAppBadgeMacResult" expires_after="M88">
+  <obsolete>
+    Removed in M88 as it's no longer needed.
+  </obsolete>
   <owner>phillis@chromium.org</owner>
   <owner>cmumford@chromium.org</owner>
   <summary>The result from updating the app badge on macOS.</summary>
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 93edd0d..31b9ccb6 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -197,13 +197,18 @@
         },
     },
     'fuchsia-perf-fyi': {
+        # TODO(rohpavone): Temporarily using telemetry_gpu_tests until custom
+        # test is created to run telemetry benchmarks, as this gets infra up.
         'tests': [{
             'isolate':
-            'performance_test_suite',
+            'fuchsia_telemetry_gpu_integration_test',
             'extra_args': [
-                '--output-format=histograms',
-                '--experimental-tbmv3-metrics',
+                'hardware_accelerated_feature', '--show-stdout',
+                '--browser=web-engine-shell', '--passthrough', '-v',
+                '--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc'
             ],
+            'type':
+            TEST_TYPES.GENERIC,
         }],
         'platform':
         'fuchsia',
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index d4b0e4a..b971d287 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,16 +1,16 @@
 {
     "trace_processor_shell": {
         "win": {
-            "hash": "aac95837855df9eceed9a744c92b1a23ea1dd901",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/b998b78079b8d83e83cce03d5033ac7611d5d204/trace_processor_shell.exe"
+            "hash": "7995b43f2e8f135027d99cb7fe8100e9f7e7171d",
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/52852a8ec96d2db2a97fffd2ea9a62e58d65845d/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "37b00e2fc21cfba0ba2cc81d4f314598400c0715",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/b998b78079b8d83e83cce03d5033ac7611d5d204/trace_processor_shell"
+            "hash": "7961eef6b83b7d5b2c867cc4b2494c6c1d94f6c4",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/52852a8ec96d2db2a97fffd2ea9a62e58d65845d/trace_processor_shell"
         },
         "linux": {
-            "hash": "c3abde49b5a533310318cb7348f16cf8ab065ec2",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/f5271e869bde5d7b034fea10cbcc95266a2c3b43/trace_processor_shell"
+            "hash": "9a68a5070bda85da38a566f8dbc59ca3da01aac4",
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/7cb370fb0a2f055e7781a0924e3a275d7adedf6b/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 2f920ad..441678fa 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -70,7 +70,7 @@
  <item id="cryptauth_find_eligible_unlock_devices" added_in_milestone="62" hash_code="120000562" type="1" second_id="29188932" deprecated="2018-04-04" content_hash_code="46773475" file_path=""/>
  <item id="cryptauth_get_my_devices" added_in_milestone="62" hash_code="136498680" type="1" second_id="29188932" deprecated="2018-04-04" content_hash_code="73842435" file_path=""/>
  <item id="cryptauth_toggle_easyunlock" added_in_milestone="62" hash_code="25204343" type="1" second_id="29188932" deprecated="2018-04-04" content_hash_code="13570943" file_path=""/>
- <item id="data_reduction_proxy_config" added_in_milestone="62" hash_code="485305" type="0" content_hash_code="134075813" os_list="linux,windows" file_path="components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc"/>
+ <item id="data_reduction_proxy_config" added_in_milestone="62" hash_code="485305" type="0" deprecated="2021-01-25" content_hash_code="134075813" file_path=""/>
  <item id="data_reduction_proxy_pingback" added_in_milestone="62" hash_code="68561428" type="0" deprecated="2019-09-17" content_hash_code="78407792" file_path=""/>
  <item id="data_reduction_proxy_secure_proxy_check" added_in_milestone="62" hash_code="131236802" type="0" deprecated="2020-03-13" content_hash_code="122297136" file_path=""/>
  <item id="data_reduction_proxy_warmup" added_in_milestone="62" hash_code="8250451" type="0" deprecated="2020-03-13" content_hash_code="6321249" file_path=""/>
@@ -167,7 +167,7 @@
  <item id="interest_feedv2_send" added_in_milestone="83" hash_code="85742023" type="0" content_hash_code="49706671" os_list="linux,windows" file_path="components/feed/core/v2/feed_network_impl.cc"/>
  <item id="intranet_redirect_detector" added_in_milestone="62" hash_code="21785164" type="0" content_hash_code="62025595" os_list="linux,windows" file_path="chrome/browser/intranet_redirect_detector.cc"/>
  <item id="invalidation_service" added_in_milestone="62" hash_code="72354423" type="0" deprecated="2020-01-23" content_hash_code="78425687" file_path=""/>
- <item id="javascript_report_error" added_in_milestone="87" hash_code="109607776" type="0" content_hash_code="7229012" os_list="linux" file_path="chrome/browser/error_reporting/chrome_js_error_report_processor.cc"/>
+ <item id="javascript_report_error" added_in_milestone="87" hash_code="109607776" type="0" content_hash_code="7229012" os_list="linux" file_path="chrome/browser/error_reporting/chrome_js_error_report_processor_nonchromeos.cc"/>
  <item id="kids_chrome_management_client_classify_url" added_in_milestone="77" hash_code="109987793" type="0" deprecated="2019-07-30" content_hash_code="112740597" file_path=""/>
  <item id="lib_address_input" added_in_milestone="62" hash_code="50816767" type="0" content_hash_code="57977576" os_list="linux,windows" file_path="third_party/libaddressinput/chromium/chrome_metadata_source.cc"/>
  <item id="litepages_robots_rules" added_in_milestone="89" hash_code="50910588" type="0" content_hash_code="72567080" os_list="linux,windows" file_path="chrome/browser/subresource_redirect/origin_robots_rules.cc"/>
diff --git a/ui/accessibility/accessibility_switches.cc b/ui/accessibility/accessibility_switches.cc
index eefe07b..d71cf27 100644
--- a/ui/accessibility/accessibility_switches.cc
+++ b/ui/accessibility/accessibility_switches.cc
@@ -48,6 +48,10 @@
 const char kEnableSwitchAccessPointScanning[] =
     "enable-switch-access-point-scanning";
 
+// Enables the Switch Access setup guide that hasn't launched yet.
+const char kEnableExperimentalAccessibilitySwitchAccessSetupGuide[] =
+    "enable-experimental-accessibility-switch-access-setup-guide";
+
 bool IsExperimentalAccessibilityDictationExtensionEnabled() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
       ::switches::kEnableExperimentalAccessibilityDictationExtension);
diff --git a/ui/accessibility/accessibility_switches.h b/ui/accessibility/accessibility_switches.h
index dd73b0c..56c8203 100644
--- a/ui/accessibility/accessibility_switches.h
+++ b/ui/accessibility/accessibility_switches.h
@@ -27,6 +27,8 @@
 AX_BASE_EXPORT extern const char
     kEnableExperimentalAccessibilityChromeVoxAnnotations[];
 AX_BASE_EXPORT extern const char kEnableSwitchAccessPointScanning[];
+AX_BASE_EXPORT extern const char
+    kEnableExperimentalAccessibilitySwitchAccessSetupGuide[];
 
 // Returns true if experimental accessibility dictation extension is enabled.
 AX_BASE_EXPORT bool IsExperimentalAccessibilityDictationExtensionEnabled();
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
index 2c7f0f9f..3a79fcf 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
@@ -1261,6 +1261,26 @@
 }
 
 // static
+void AXPlatformNodeTextRangeProviderWin::NormalizeAsUnignoredPosition(
+    AXPositionInstance& position) {
+  if (!position->IsValid())
+    return;
+
+  if (position->IsIgnored()) {
+    AXPositionInstance normalized_position = position->AsUnignoredPosition(
+        AXPositionAdjustmentBehavior::kMoveForward);
+    if (normalized_position->IsNullPosition()) {
+      normalized_position = position->AsUnignoredPosition(
+          AXPositionAdjustmentBehavior::kMoveBackward);
+    }
+
+    if (!normalized_position->IsNullPosition())
+      position = std::move(normalized_position);
+  }
+  DCHECK(!position->IsNullPosition());
+}
+
+// static
 void AXPlatformNodeTextRangeProviderWin::NormalizeAsUnignoredTextRange(
     AXPositionInstance& start,
     AXPositionInstance& end) {
@@ -1269,29 +1289,8 @@
 
   if (!start->IsIgnored() && !end->IsIgnored())
     return;
-
-  if (start->IsIgnored()) {
-    AXPositionInstance normalized_start =
-        start->AsUnignoredPosition(AXPositionAdjustmentBehavior::kMoveForward);
-    if (normalized_start->IsNullPosition()) {
-      normalized_start = start->AsUnignoredPosition(
-          AXPositionAdjustmentBehavior::kMoveBackward);
-    }
-    if (!normalized_start->IsNullPosition())
-      start = std::move(normalized_start);
-  }
-
-  if (end->IsIgnored()) {
-    AXPositionInstance normalized_end =
-        end->AsUnignoredPosition(AXPositionAdjustmentBehavior::kMoveForward);
-    if (normalized_end->IsNullPosition()) {
-      normalized_end =
-          end->AsUnignoredPosition(AXPositionAdjustmentBehavior::kMoveBackward);
-    }
-    if (!normalized_end->IsNullPosition())
-      end = std::move(normalized_end);
-  }
-
+  NormalizeAsUnignoredPosition(start);
+  NormalizeAsUnignoredPosition(end);
   DCHECK_LE(*start, *end);
 }
 
@@ -1524,20 +1523,38 @@
   if (tree->GetAXTreeID() == start_->tree_id() &&
       node->id() == start_->anchor_id()) {
     AXPositionInstance new_start = start_->CreateParentPosition();
+    AXPositionInstance end_for_comparison = end_->Clone();
+
+    // Convert |new_start| and |end_for_comparison| to unignored positions to
+    // avoid AXPosition::SlowCompareTo in the < operator below.
+    NormalizeAsUnignoredPosition(new_start);
+    NormalizeAsUnignoredPosition(end_for_comparison);
+    DCHECK(!new_start->IsIgnored());
+    DCHECK(!end_for_comparison->IsIgnored());
+
     // Create a degenerate range at |end_| if we have an inverted range -
     // which occurs when the |end_| comes before the |start_|. However, if the
     // |end_| is positioned on the deleted node, don't create a degenerate range
     // yet as that position will be updated below.
-    if (node->id() != end_->anchor_id() && *end_ < *new_start)
+    if (node->id() != end_->anchor_id() && *end_for_comparison < *new_start)
       new_start = end_->Clone();
     SetStart(std::move(new_start));
   }
   if (tree->GetAXTreeID() == end_->tree_id() &&
       node->id() == end_->anchor_id()) {
     AXPositionInstance new_end = end_->CreateParentPosition();
+    AXPositionInstance start_for_comparison = start_->Clone();
+
+    // Convert |new_end| and |start_for_comparison| to unignored positions to
+    // avoid AXPosition::SlowCompareTo in the < operator below.
+    NormalizeAsUnignoredPosition(new_end);
+    NormalizeAsUnignoredPosition(start_for_comparison);
+    DCHECK(!new_end->IsIgnored());
+    DCHECK(!start_for_comparison->IsIgnored());
+
     // Create a degenerate range at |start_| if we have an inverted range -
     // which occurs when the |end_| comes before the |start_|.
-    if (*new_end < *start_)
+    if (*new_end < *start_for_comparison)
       new_end = start_->Clone();
     SetEnd(std::move(new_end));
   }
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h
index b25cba8..e7f3f15 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h
@@ -169,6 +169,7 @@
   // normalizes the endpoints passed by parameter.
   // TODO(vicfei): Make static.
   void NormalizeTextRange(AXPositionInstance& start, AXPositionInstance& end);
+  static void NormalizeAsUnignoredPosition(AXPositionInstance& position);
   static void NormalizeAsUnignoredTextRange(AXPositionInstance& start,
                                             AXPositionInstance& end);
 
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
index 157669c..5e07fac 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -5868,43 +5868,50 @@
   // thus generating a tree update.
   //
   // ++1 kRootWebArea
-  // ++++2 kStaticText/++++3 kStaticText (replacement node)
-  // ++++4 kStaticText/++++5 kStaticText (replacement node)
+  // ++++2 kGroup (ignored)
+  // ++++++3 kStaticText/++++4 kStaticText (replacement node)
+  // ++++5 kStaticText/++++6 kStaticText (replacement node)
   AXNodeData root_1;
-  AXNodeData text_2;
+  AXNodeData group_2;
   AXNodeData text_3;
   AXNodeData text_4;
   AXNodeData text_5;
+  AXNodeData text_6;
 
   root_1.id = 1;
-  text_2.id = 2;
+  group_2.id = 2;
   text_3.id = 3;
   text_4.id = 4;
   text_5.id = 5;
+  text_6.id = 6;
 
   root_1.role = ax::mojom::Role::kRootWebArea;
-  root_1.child_ids = {text_2.id, text_4.id};
+  root_1.child_ids = {text_3.id, text_5.id};
 
-  text_2.role = ax::mojom::Role::kStaticText;
-  text_2.SetName("some text");
+  group_2.role = ax::mojom::Role::kGroup;
+  group_2.AddState(ax::mojom::State::kIgnored);
+  group_2.child_ids = {text_3.id};
 
-  // Replacement node of |text_2|.
   text_3.role = ax::mojom::Role::kStaticText;
   text_3.SetName("some text");
 
+  // Replacement node of |text_3|.
   text_4.role = ax::mojom::Role::kStaticText;
-  text_4.SetName("more text");
+  text_4.SetName("some text");
 
-  // Replacement node of |text_4|.
   text_5.role = ax::mojom::Role::kStaticText;
   text_5.SetName("more text");
 
+  // Replacement node of |text_5|.
+  text_6.role = ax::mojom::Role::kStaticText;
+  text_6.SetName("more text");
+
   ui::AXTreeUpdate update;
   ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID();
   update.root_id = root_1.id;
   update.tree_data.tree_id = tree_id;
   update.has_tree_data = true;
-  update.nodes = {root_1, text_2, text_4};
+  update.nodes = {root_1, text_3, text_5};
   Init(update);
 
   // Create a position at MaxTextOffset.
@@ -5913,14 +5920,14 @@
   AXPlatformNodeWin* owner = static_cast<AXPlatformNodeWin*>(
       AXPlatformNodeFromNode(GetNodeFromTree(tree_id, 1)));
 
-  // start: TextPosition, anchor_id=2, text_offset=0, annotated_text=<s>ome text
-  // end  : TextPosition, anchor_id=4, text_offset=9, annotated_text=more text<>
+  // start: TextPosition, anchor_id=3, text_offset=0, annotated_text=<s>ome text
+  // end  : TextPosition, anchor_id=5, text_offset=9, annotated_text=more text<>
   ComPtr<AXPlatformNodeTextRangeProviderWin> range;
   CreateTextRangeProviderWin(
       range, owner, tree_id,
-      /*start_anchor_id*/ 2, /*start_offset*/ 0,
+      /*start_anchor_id*/ text_3.id, /*start_offset*/ 0,
       /*start_affinity*/ ax::mojom::TextAffinity::kDownstream,
-      /*end_anchor_id*/ 4, /*end_offset*/ 9,
+      /*end_anchor_id*/ text_5.id, /*end_offset*/ 9,
       /*end_affinity*/ ax::mojom::TextAffinity::kDownstream);
 
   EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"some textmore text");
@@ -5928,9 +5935,9 @@
   // 1. Replace the node on which |start_| is.
   {
     // Replace node |text_2| with |text_3|.
-    root_1.child_ids = {text_3.id, text_4.id};
+    root_1.child_ids = {text_4.id, text_5.id};
     AXTreeUpdate test_update;
-    test_update.nodes = {root_1, text_3};
+    test_update.nodes = {root_1, text_4};
     ASSERT_TRUE(GetTree()->Unserialize(test_update));
 
     // Replacing that node shouldn't impact the range.
@@ -5938,21 +5945,22 @@
     range->GetChildren(children.Receive());
     EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"some textmore text");
 
-    // The |start_| endpoint should have moved to its parent.
-    EXPECT_EQ(1, GetStart(range.Get())->anchor_id());
+    // The |start_| endpoint should have moved to the root, skipping its ignored
+    // parent.
+    EXPECT_EQ(root_1.id, GetStart(range.Get())->anchor_id());
     EXPECT_EQ(0, GetStart(range.Get())->text_offset());
 
     // The |end_| endpoint should not have moved.
-    EXPECT_EQ(4, GetEnd(range.Get())->anchor_id());
+    EXPECT_EQ(text_5.id, GetEnd(range.Get())->anchor_id());
     EXPECT_EQ(9, GetEnd(range.Get())->text_offset());
   }
 
   // 2. Replace the node on which |end_| is.
   {
     // Replace node |text_4| with |text_5|.
-    root_1.child_ids = {text_3.id, text_5.id};
+    root_1.child_ids = {text_4.id, text_6.id};
     AXTreeUpdate test_update;
-    test_update.nodes = {root_1, text_5};
+    test_update.nodes = {root_1, text_6};
     ASSERT_TRUE(GetTree()->Unserialize(test_update));
 
     // Replacing that node shouldn't impact the range.
@@ -5961,32 +5969,32 @@
     EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"some textmore text");
 
     // The |start_| endpoint should still be on its parent.
-    EXPECT_EQ(1, GetStart(range.Get())->anchor_id());
+    EXPECT_EQ(root_1.id, GetStart(range.Get())->anchor_id());
     EXPECT_EQ(0, GetStart(range.Get())->text_offset());
 
     // The |end_| endpoint should have moved to its parent.
-    EXPECT_EQ(1, GetEnd(range.Get())->anchor_id());
+    EXPECT_EQ(root_1.id, GetEnd(range.Get())->anchor_id());
     EXPECT_EQ(18, GetEnd(range.Get())->text_offset());
   }
 
   // 3. Replace the node on which |end_| is.
   {
-    // start: TextPosition, anchor_id=3, text_offset=0, annotated_text=<s>ome
-    // end  : TextPosition, anchor_id=3, text_offset=4, annotated_text=some<>
+    // start: TextPosition, anchor_id=4, text_offset=0, annotated_text=<s>ome
+    // end  : TextPosition, anchor_id=4, text_offset=4, annotated_text=some<>
     ComPtr<AXPlatformNodeTextRangeProviderWin> range_2;
     CreateTextRangeProviderWin(
         range_2, owner, tree_id,
-        /*start_anchor_id*/ 3, /*start_offset*/ 0,
+        /*start_anchor_id*/ text_4.id, /*start_offset*/ 0,
         /*start_affinity*/ ax::mojom::TextAffinity::kDownstream,
-        /*end_anchor_id*/ 3, /*end_offset*/ 4,
+        /*end_anchor_id*/ text_4.id, /*end_offset*/ 4,
         /*end_affinity*/ ax::mojom::TextAffinity::kDownstream);
 
     EXPECT_UIA_TEXTRANGE_EQ(range_2, /*expected_text*/ L"some");
 
-    // Replace node |text_3| with |text_2|.
-    root_1.child_ids = {text_2.id, text_5.id};
+    // Replace node |text_4| with |text_3|.
+    root_1.child_ids = {text_3.id, text_6.id};
     AXTreeUpdate test_update;
-    test_update.nodes = {root_1, text_2};
+    test_update.nodes = {root_1, text_3};
     ASSERT_TRUE(GetTree()->Unserialize(test_update));
 
     // Replacing that node shouldn't impact the range.
@@ -5995,13 +6003,117 @@
     EXPECT_UIA_TEXTRANGE_EQ(range_2, /*expected_text*/ L"some");
 
     // The |start_| endpoint should have moved to its parent.
-    EXPECT_EQ(1, GetStart(range_2.Get())->anchor_id());
+    EXPECT_EQ(root_1.id, GetStart(range_2.Get())->anchor_id());
     EXPECT_EQ(0, GetStart(range_2.Get())->text_offset());
 
     // The |end_| endpoint should have moved to its parent.
-    EXPECT_EQ(1, GetEnd(range_2.Get())->anchor_id());
+    EXPECT_EQ(root_1.id, GetEnd(range_2.Get())->anchor_id());
     EXPECT_EQ(4, GetEnd(range_2.Get())->text_offset());
   }
 }
 
+TEST_F(AXPlatformNodeTextRangeProviderTest,
+       TestReplaceStartAndEndEndpointRepeatRemoval) {
+  // This test updates the tree structure to ensure that the text range is still
+  // valid after text nodes get removed repeatedly.
+  //
+  // ++1 kRootWebArea
+  // ++++2 kStaticText
+  // ++++3 kGroup (ignored)
+  // ++++++4 kStaticText
+  // ++++5 kStaticText
+  AXNodeData root_1;
+  AXNodeData text_2;
+  AXNodeData group_3;
+  AXNodeData text_4;
+  AXNodeData text_5;
+
+  root_1.id = 1;
+  text_2.id = 2;
+  group_3.id = 3;
+  text_4.id = 4;
+  text_5.id = 5;
+
+  root_1.role = ax::mojom::Role::kRootWebArea;
+  root_1.child_ids = {text_2.id, group_3.id, text_5.id};
+
+  text_2.role = ax::mojom::Role::kStaticText;
+  text_2.SetName("text 2");
+
+  group_3.role = ax::mojom::Role::kGroup;
+  group_3.AddState(ax::mojom::State::kIgnored);
+  group_3.child_ids = {text_4.id};
+
+  text_4.role = ax::mojom::Role::kStaticText;
+  text_4.SetName("text 4");
+
+  text_5.role = ax::mojom::Role::kStaticText;
+  text_5.SetName("text 5");
+
+  ui::AXTreeUpdate update;
+  ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID();
+  update.root_id = root_1.id;
+  update.tree_data.tree_id = tree_id;
+  update.has_tree_data = true;
+  update.nodes = {root_1, text_2, group_3, text_4, text_5};
+  Init(update);
+
+  // Making |owner| AXID:1 so that |TestAXNodeWrapper::BuildAllWrappers|
+  // will build the entire tree.
+  AXPlatformNodeWin* owner = static_cast<AXPlatformNodeWin*>(
+      AXPlatformNodeFromNode(GetNodeFromTree(tree_id, 1)));
+
+  ComPtr<AXPlatformNodeTextRangeProviderWin> range;
+  CreateTextRangeProviderWin(
+      range, owner, tree_id,
+      /*start_anchor_id*/ text_2.id, /*start_offset*/ 0,
+      /*start_affinity*/ ax::mojom::TextAffinity::kDownstream,
+      /*end_anchor_id*/ text_4.id, /*end_offset*/ 0,
+      /*end_affinity*/ ax::mojom::TextAffinity::kDownstream);
+
+  EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"text 2");
+
+  // start: TextPosition, anchor_id=2, text_offset=0, annotated_text=<t>ext2
+  // end  : TextPosition, anchor_id=4, text_offset=0, annotated_text=<>text4
+  // 1. Remove |text_4| which |end_| is anchored on.
+  {
+    // Remove node |text_4|.
+    group_3.child_ids = {};
+    AXTreeUpdate test_update;
+    test_update.nodes = {root_1, group_3};
+    ASSERT_TRUE(GetTree()->Unserialize(test_update));
+
+    // Replacing that node should not impact the range.
+    EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"text 2");
+  }
+
+  // start: TextPosition, anchor_id=2, text_offset=0, annotated_text=<>text2
+  // end  : TextPosition, anchor_id=2, text_offset=5, annotated_text=text2<>
+  // 2. Remove |text_2|, which both |start_| and |end_| are anchored to and
+  //  replace with |text_5|.
+  {
+    root_1.child_ids = {group_3.id, text_5.id};
+    AXTreeUpdate test_update;
+    test_update.nodes = {root_1, group_3};
+    ASSERT_TRUE(GetTree()->Unserialize(test_update));
+
+    // Removing that node should adjust the range to the |text_5|, as it took
+    // |text_2|'s position.
+    EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"text 5");
+  }
+
+  // start: TextPosition, anchor_id=5, text_offset=0, annotated_text=<>text5
+  // end  : TextPosition, anchor_id=5, text_offset=5, annotated_text=text5<>
+  // 3. Remove |text_5|, which both |start_| and |end_| are pointing to.
+  {
+    root_1.child_ids = {group_3.id};
+    AXTreeUpdate test_update;
+    test_update.nodes = {root_1, group_3};
+    ASSERT_TRUE(GetTree()->Unserialize(test_update));
+
+    // Removing the last text node should leave a degenerate range.
+    EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"");
+  }
+}
+
 }  // namespace ui
diff --git a/ui/aura/native_window_occlusion_tracker_win.cc b/ui/aura/native_window_occlusion_tracker_win.cc
index 8bab2747..4f4d491 100644
--- a/ui/aura/native_window_occlusion_tracker_win.cc
+++ b/ui/aura/native_window_occlusion_tracker_win.cc
@@ -22,59 +22,8 @@
 #include "base/win/scoped_gdi_object.h"
 #include "base/win/windows_version.h"
 #include "ui/aura/window_tree_host.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/gfx/win/hwnd_util.h"
 
-const CLSID CLSID_ImmersiveShell = {
-    0xC2F03A33,
-    0x21F5,
-    0x47FA,
-    {0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39}};
-
-const CLSID CLSID_VirtualDesktopAPI_Unknown = {
-    0xC5E0CDCA,
-    0x7B6E,
-    0x41B2,
-    {0x9F, 0xC4, 0xD9, 0x39, 0x75, 0xCC, 0x46, 0x7B}};
-
-struct IApplicationView : public IUnknown {
- public:
-};
-
-MIDL_INTERFACE("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4")
-IVirtualDesktop : public IUnknown {
- public:
-  virtual HRESULT STDMETHODCALLTYPE IsViewVisible(IApplicationView * pView,
-                                                  int* pfVisible) = 0;
-  virtual HRESULT STDMETHODCALLTYPE GetID(GUID * pGuid) = 0;
-};
-
-enum AdjacentDesktop { LeftDirection = 3, RightDirection = 4 };
-
-MIDL_INTERFACE("F31574D6-B682-4cdc-BD56-1827860ABEC6")
-IVirtualDesktopManagerInternal : public IUnknown {
- public:
-  virtual HRESULT STDMETHODCALLTYPE GetCount(UINT * pCount) = 0;
-  virtual HRESULT STDMETHODCALLTYPE MoveViewToDesktop(
-      IApplicationView * pView, IVirtualDesktop * pDesktop) = 0;
-  virtual HRESULT STDMETHODCALLTYPE CanViewMoveDesktops(
-      IApplicationView * pView, int* pfCanViewMoveDesktops) = 0;
-  virtual HRESULT STDMETHODCALLTYPE GetCurrentDesktop(IVirtualDesktop *
-                                                      *desktop) = 0;
-  virtual HRESULT STDMETHODCALLTYPE GetDesktops(IObjectArray * *ppDesktops) = 0;
-  virtual HRESULT STDMETHODCALLTYPE GetAdjacentDesktop(
-      IVirtualDesktop * pDesktopReference, AdjacentDesktop uDirection,
-      IVirtualDesktop * *ppAdjacentDesktop) = 0;
-  virtual HRESULT STDMETHODCALLTYPE SwitchDesktop(IVirtualDesktop *
-                                                  pDesktop) = 0;
-  virtual HRESULT STDMETHODCALLTYPE CreateDesktopW(IVirtualDesktop *
-                                                   *ppNewDesktop) = 0;
-  virtual HRESULT STDMETHODCALLTYPE RemoveDesktop(
-      IVirtualDesktop * pRemove, IVirtualDesktop * pFallbackDesktop) = 0;
-  virtual HRESULT STDMETHODCALLTYPE FindDesktop(
-      GUID * desktopId, IVirtualDesktop * *ppDesktop) = 0;
-};
-
 namespace aura {
 
 namespace {
@@ -83,9 +32,6 @@
 const base::TimeDelta kUpdateOcclusionDelay =
     base::TimeDelta::FromMilliseconds(16);
 
-const base::TimeDelta kUpdateVirtualDesktopDelay =
-    base::TimeDelta::FromMilliseconds(1000);
-
 // This global variable can be accessed only on main thread.
 NativeWindowOcclusionTrackerWin* g_tracker = nullptr;
 
@@ -367,19 +313,6 @@
   if (base::win::GetVersion() >= base::win::Version::WIN10) {
     ::CoCreateInstance(__uuidof(VirtualDesktopManager), nullptr, CLSCTX_ALL,
                        IID_PPV_ARGS(&virtual_desktop_manager_));
-
-    Microsoft::WRL::ComPtr<IServiceProvider> service_provider;
-    if (base::FeatureList::IsEnabled(
-            features::kCalculateNativeWinOcclusionCheckVirtualDesktopUsed) &&
-        SUCCEEDED(::CoCreateInstance(CLSID_ImmersiveShell, NULL,
-                                     CLSCTX_LOCAL_SERVER,
-                                     IID_PPV_ARGS(&service_provider)))) {
-      service_provider->QueryService(
-          CLSID_VirtualDesktopAPI_Unknown,
-          IID_PPV_ARGS(&virtual_desktop_manager_internal_));
-      if (virtual_desktop_manager_internal_)
-        ComputeVirtualDesktopUsed();
-    }
   }
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
@@ -429,8 +362,6 @@
     UnregisterEventHooks();
     if (occlusion_update_timer_.IsRunning())
       occlusion_update_timer_.Stop();
-    if (virtual_desktop_update_timer_.IsRunning())
-      virtual_desktop_update_timer_.Stop();
   }
 }
 
@@ -577,25 +508,12 @@
 }
 
 void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
-    ComputeVirtualDesktopUsed() {
-  UINT count = 0;
-  if (SUCCEEDED(virtual_desktop_manager_internal_->GetCount(&count)))
-    virtual_desktops_used_ = count > 1;
-}
-
-void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
     ScheduleOcclusionCalculationIfNeeded() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (!occlusion_update_timer_.IsRunning()) {
+  if (!occlusion_update_timer_.IsRunning())
     occlusion_update_timer_.Start(
         FROM_HERE, kUpdateOcclusionDelay, this,
         &WindowOcclusionCalculator::ComputeNativeWindowOcclusionStatus);
-    if (virtual_desktop_manager_internal_) {
-      virtual_desktop_update_timer_.Start(
-          FROM_HERE, kUpdateVirtualDesktopDelay, this,
-          &WindowOcclusionCalculator::ComputeVirtualDesktopUsed);
-    }
-  }
 }
 
 void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
@@ -851,7 +769,7 @@
 
 base::Optional<bool> NativeWindowOcclusionTrackerWin::
     WindowOcclusionCalculator::IsWindowOnCurrentVirtualDesktop(HWND hwnd) {
-  if (!virtual_desktop_manager_ || !virtual_desktops_used_)
+  if (!virtual_desktop_manager_)
     return true;
 
   BOOL on_current_desktop;
diff --git a/ui/aura/native_window_occlusion_tracker_win.h b/ui/aura/native_window_occlusion_tracker_win.h
index 7c64593..4934e8b 100644
--- a/ui/aura/native_window_occlusion_tracker_win.h
+++ b/ui/aura/native_window_occlusion_tracker_win.h
@@ -34,8 +34,6 @@
 class Rect;
 }
 
-struct IVirtualDesktopManagerInternal;
-
 namespace aura {
 
 // This class keeps track of whether any HWNDs are occluding any app windows.
@@ -136,10 +134,6 @@
     // their occlusion status has changed.
     void ComputeNativeWindowOcclusionStatus();
 
-    // Computes if virtual desktops are used. This is used as an optimization
-    // since IsWindowOnCurrentVirtualDesktop is a slow call.
-    void ComputeVirtualDesktopUsed();
-
     // Schedules an occlusion calculation |update_occlusion_delay_| time in the
     // future, if one isn't already scheduled.
     void ScheduleOcclusionCalculationIfNeeded();
@@ -223,9 +217,6 @@
     // Timer to delay occlusion update.
     base::OneShotTimer occlusion_update_timer_;
 
-    // Timer to check how many virtual desktops are present.
-    base::OneShotTimer virtual_desktop_update_timer_;
-
     // Used to keep track of whether we're in the middle of getting window move
     // events, in order to wait until the window move is complete before
     // calculating window occlusion.
@@ -253,18 +244,9 @@
     // ignore windows occluded by the dragged window.
     HWND moving_window_ = 0;
 
-    // By caching if virtual desktops are in use or not we can avoid calling
-    // IsWindowOnCurrentVirtualDesktop which is slow. Start with an initial
-    // value of true so that we only optimize after we get confirmation that
-    // there are no virtual desktops.
-    bool virtual_desktops_used_ = true;
-
     // Only used on Win10+.
     Microsoft::WRL::ComPtr<IVirtualDesktopManager> virtual_desktop_manager_;
 
-    Microsoft::WRL::ComPtr<IVirtualDesktopManagerInternal>
-        virtual_desktop_manager_internal_;
-
     SEQUENCE_CHECKER(sequence_checker_);
 
     base::WeakPtrFactory<WindowOcclusionCalculator> weak_factory_{this};
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc
index 9ccd5d41..4a3dd49 100644
--- a/ui/base/ui_base_features.cc
+++ b/ui/base/ui_base_features.cc
@@ -24,10 +24,6 @@
 // If enabled, calculate native window occlusion - Windows-only.
 const base::Feature kCalculateNativeWinOcclusion{
     "CalculateNativeWinOcclusion", base::FEATURE_ENABLED_BY_DEFAULT};
-
-const base::Feature kCalculateNativeWinOcclusionCheckVirtualDesktopUsed{
-    "CalculateNativeWinOcclusionCheckVirtualDesktopUsed",
-    base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // OW_WIN
 
 // Whether or not to delegate color queries to the color provider.
diff --git a/ui/base/ui_base_features.h b/ui/base/ui_base_features.h
index be3003d..a8c348f 100644
--- a/ui/base/ui_base_features.h
+++ b/ui/base/ui_base_features.h
@@ -48,8 +48,6 @@
 COMPONENT_EXPORT(UI_BASE_FEATURES)
 extern const base::Feature kCalculateNativeWinOcclusion;
 COMPONENT_EXPORT(UI_BASE_FEATURES)
-extern const base::Feature kCalculateNativeWinOcclusionCheckVirtualDesktopUsed;
-COMPONENT_EXPORT(UI_BASE_FEATURES)
 extern const base::Feature kElasticOverscrollWin;
 COMPONENT_EXPORT(UI_BASE_FEATURES)
 extern const base::Feature kInputPaneOnScreenKeyboard;
diff --git a/ui/chromeos/DEPS b/ui/chromeos/DEPS
index d2d41de..f0833c4 100644
--- a/ui/chromeos/DEPS
+++ b/ui/chromeos/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+ash/constants",
   "+chromeos",
   "+components/device_event_log",
   "+device/udev_linux",
diff --git a/ui/chromeos/events/event_rewriter_chromeos.cc b/ui/chromeos/events/event_rewriter_chromeos.cc
index 9811a44..4dfea93 100644
--- a/ui/chromeos/events/event_rewriter_chromeos.cc
+++ b/ui/chromeos/events/event_rewriter_chromeos.cc
@@ -7,6 +7,7 @@
 #include <fcntl.h>
 #include <stddef.h>
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_file.h"
@@ -17,7 +18,6 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/system/sys_info.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "device/udev_linux/scoped_udev.h"
 #include "ui/base/ime/chromeos/ime_keyboard.h"
diff --git a/ui/compositor/transform_animation_curve_adapter.cc b/ui/compositor/transform_animation_curve_adapter.cc
index 7a8f53c..a3718e7 100644
--- a/ui/compositor/transform_animation_curve_adapter.cc
+++ b/ui/compositor/transform_animation_curve_adapter.cc
@@ -5,14 +5,13 @@
 #include "ui/compositor/transform_animation_curve_adapter.h"
 
 #include "base/memory/ptr_util.h"
-#include "cc/base/math_util.h"
 
 namespace ui {
 
 namespace {
 
-static cc::TransformOperations WrapTransform(const gfx::Transform& transform) {
-  cc::TransformOperations operations;
+static gfx::TransformOperations WrapTransform(const gfx::Transform& transform) {
+  gfx::TransformOperations operations;
   operations.AppendMatrix(transform);
   return operations;
 }
@@ -50,7 +49,7 @@
       tween_type_, initial_value_, target_value_, duration_));
 }
 
-cc::TransformOperations TransformAnimationCurveAdapter::GetValue(
+gfx::TransformOperations TransformAnimationCurveAdapter::GetValue(
     base::TimeDelta t) const {
   if (t >= duration_)
     return target_wrapped_value_;
@@ -72,11 +71,9 @@
 bool TransformAnimationCurveAdapter::MaximumScale(float* max_scale) const {
   constexpr float kInvalidScale = 0.f;
   gfx::Vector2dF initial_scales =
-      cc::MathUtil::ComputeTransform2dScaleComponents(initial_value_,
-                                                      kInvalidScale);
+      gfx::ComputeTransform2dScaleComponents(initial_value_, kInvalidScale);
   gfx::Vector2dF target_scales =
-      cc::MathUtil::ComputeTransform2dScaleComponents(target_value_,
-                                                      kInvalidScale);
+      gfx::ComputeTransform2dScaleComponents(target_value_, kInvalidScale);
   *max_scale = std::max({initial_scales.x(), initial_scales.y(),
                          target_scales.x(), target_scales.y()});
   return *max_scale != kInvalidScale;
diff --git a/ui/compositor/transform_animation_curve_adapter.h b/ui/compositor/transform_animation_curve_adapter.h
index 42424ca6..dd8fa100 100644
--- a/ui/compositor/transform_animation_curve_adapter.h
+++ b/ui/compositor/transform_animation_curve_adapter.h
@@ -10,10 +10,10 @@
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "cc/animation/animation_curve.h"
-#include "cc/animation/transform_operations.h"
 #include "ui/compositor/compositor_export.h"
 #include "ui/gfx/animation/tween.h"
 #include "ui/gfx/transform.h"
+#include "ui/gfx/transform_operations.h"
 #include "ui/gfx/transform_util.h"
 
 namespace ui {
@@ -33,16 +33,16 @@
   // TransformAnimationCurve implementation.
   base::TimeDelta Duration() const override;
   std::unique_ptr<AnimationCurve> Clone() const override;
-  cc::TransformOperations GetValue(base::TimeDelta t) const override;
+  gfx::TransformOperations GetValue(base::TimeDelta t) const override;
   bool PreservesAxisAlignment() const override;
   bool MaximumScale(float* max_scale) const override;
 
  private:
   gfx::Tween::Type tween_type_;
   gfx::Transform initial_value_;
-  cc::TransformOperations initial_wrapped_value_;
+  gfx::TransformOperations initial_wrapped_value_;
   gfx::Transform target_value_;
-  cc::TransformOperations target_wrapped_value_;
+  gfx::TransformOperations target_wrapped_value_;
   gfx::DecomposedTransform decomposed_initial_value_;
   gfx::DecomposedTransform decomposed_target_value_;
   base::TimeDelta duration_;
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index 0b3a3db..de97bf6 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -50,6 +50,10 @@
     "skia_util.h",
     "transform.cc",
     "transform.h",
+    "transform_operation.cc",
+    "transform_operation.h",
+    "transform_operations.cc",
+    "transform_operations.h",
     "transform_util.cc",
     "transform_util.h",
   ]
@@ -640,6 +644,8 @@
     "animation/test_animation_delegate.h",
     "geometry/test/rect_test_util.cc",
     "geometry/test/rect_test_util.h",
+    "geometry/test/transform_test_util.cc",
+    "geometry/test/transform_test_util.h",
     "image/image_unittest_util.cc",
     "image/image_unittest_util.h",
     "test/font_fallback_test_data.cc",
@@ -703,10 +709,13 @@
     "image/image_family_unittest.cc",
     "image/image_skia_unittest.cc",
     "image/image_unittest.cc",
+    "interpolated_transform_unittest.cc",
     "rrect_f_unittest.cc",
     "test/run_all_unittests.cc",
     "text_elider_unittest.cc",
     "text_utils_unittest.cc",
+    "transform_operations_unittest.cc",
+    "transform_unittest.cc",
   ]
   if (is_linux || is_chromeos) {
     sources += [
@@ -840,13 +849,6 @@
     deps += [ ":gfx_io_surface_hdr_metadata" ]
   }
 
-  if (!is_apple) {
-    sources += [
-      "interpolated_transform_unittest.cc",
-      "transform_unittest.cc",
-    ]
-  }
-
   if (is_android) {
     deps += [ "//ui/android:ui_java" ]
   }
diff --git a/cc/test/geometry_test_utils.cc b/ui/gfx/geometry/test/transform_test_util.cc
similarity index 66%
rename from cc/test/geometry_test_utils.cc
rename to ui/gfx/geometry/test/transform_test_util.cc
index af0b44a..41c6980 100644
--- a/cc/test/geometry_test_utils.cc
+++ b/ui/gfx/geometry/test/transform_test_util.cc
@@ -1,22 +1,21 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/test/geometry_test_utils.h"
+#include "ui/gfx/geometry/test/transform_test_util.h"
 
 #include "base/check.h"
 #include "base/strings/stringprintf.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/transform.h"
 
-namespace cc {
+namespace gfx {
 
 // NOTE: even though transform data types use double precision, we only check
 // for equality within single-precision error bounds because many transforms
 // originate from single-precision data types such as quads/rects/etc.
 
-void ExpectTransformationMatrixEq(const gfx::Transform& expected,
-                                  const gfx::Transform& actual) {
+void ExpectTransformationMatrixEq(const Transform& expected,
+                                  const Transform& actual) {
   for (int row = 0; row < 4; ++row) {
     for (int col = 0; col < 4; ++col) {
       EXPECT_FLOAT_EQ(expected.matrix().get(row, col),
@@ -26,8 +25,8 @@
   }
 }
 
-void ExpectTransformationMatrixNear(const gfx::Transform& expected,
-                                    const gfx::Transform& actual,
+void ExpectTransformationMatrixNear(const Transform& expected,
+                                    const Transform& actual,
                                     float abs_error) {
   for (int row = 0; row < 4; ++row) {
     for (int col = 0; col < 4; ++col) {
@@ -38,11 +37,11 @@
   }
 }
 
-gfx::Transform Inverse(const gfx::Transform& transform) {
-  gfx::Transform result(gfx::Transform::kSkipInitialization);
+Transform InvertAndCheck(const Transform& transform) {
+  Transform result(Transform::kSkipInitialization);
   bool inverted_successfully = transform.GetInverse(&result);
   DCHECK(inverted_successfully);
   return result;
 }
 
-}  // namespace cc
+}  // namespace gfx
diff --git a/ui/gfx/geometry/test/transform_test_util.h b/ui/gfx/geometry/test/transform_test_util.h
new file mode 100644
index 0000000..0f27218
--- /dev/null
+++ b/ui/gfx/geometry/test/transform_test_util.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 UI_GFX_GEOMETRY_TEST_TRANSFORM_TEST_UTIL_H_
+#define UI_GFX_GEOMETRY_TEST_TRANSFORM_TEST_UTIL_H_
+
+#include "ui/gfx/transform.h"
+
+namespace gfx {
+
+// This is a function rather than a macro because when this is included as a
+// macro in bulk, it causes a significant slow-down in compilation time. This
+// problem exists with both gcc and clang, and bugs have been filed at
+// http://llvm.org/bugs/show_bug.cgi?id=13651
+// and http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54337
+void ExpectTransformationMatrixEq(const Transform& expected,
+                                  const Transform& actual);
+
+void ExpectTransformationMatrixNear(const Transform& expected,
+                                    const Transform& actual,
+                                    float abs_error);
+
+// Should be used in test code only, for convenience. Production code should use
+// the gfx::Transform::GetInverse() API.
+Transform InvertAndCheck(const Transform& transform);
+
+}  // namespace gfx
+
+#endif  // UI_GFX_GEOMETRY_TEST_TRANSFORM_TEST_UTIL_H_
diff --git a/cc/animation/transform_operation.cc b/ui/gfx/transform_operation.cc
similarity index 95%
rename from cc/animation/transform_operation.cc
rename to ui/gfx/transform_operation.cc
index cbc222b..8d12cd2 100644
--- a/cc/animation/transform_operation.cc
+++ b/ui/gfx/transform_operation.cc
@@ -5,22 +5,23 @@
 #include <limits>
 #include <utility>
 
+#include "ui/gfx/transform_operation.h"
+
 #include "base/check_op.h"
 #include "base/notreached.h"
 #include "base/numerics/math_constants.h"
 #include "base/numerics/ranges.h"
-#include "cc/animation/transform_operation.h"
-#include "cc/animation/transform_operations.h"
 #include "ui/gfx/geometry/angle_conversions.h"
 #include "ui/gfx/geometry/box_f.h"
 #include "ui/gfx/geometry/vector3d_f.h"
+#include "ui/gfx/transform_operations.h"
 #include "ui/gfx/transform_util.h"
 
 namespace {
 const SkScalar kAngleEpsilon = 1e-4f;
 }
 
-namespace cc {
+namespace gfx {
 
 bool TransformOperation::IsIdentity() const {
   return matrix.IsIdentity();
@@ -308,8 +309,7 @@
                               SkScalar max_progress,
                               gfx::BoxF* box) {
   const TransformOperation* exemplar = from ? from : to;
-  gfx::Vector3dF axis(exemplar->rotate.axis.x,
-                      exemplar->rotate.axis.y,
+  gfx::Vector3dF axis(exemplar->rotate.axis.x, exemplar->rotate.axis.y,
                       exemplar->rotate.axis.z);
 
   const bool x_is_zero = axis.x() == 0.f;
@@ -332,8 +332,8 @@
   // flip one of the angles. Note, if both |from| and |to| exist, then axis will
   // correspond to |from|.
   if (from && to) {
-    gfx::Vector3dF other_axis(
-        to->rotate.axis.x, to->rotate.axis.y, to->rotate.axis.z);
+    gfx::Vector3dF other_axis(to->rotate.axis.x, to->rotate.axis.y,
+                              to->rotate.axis.z);
     if (gfx::DotProduct(axis, other_axis) < 0.f)
       to_angle *= -1.f;
   }
@@ -361,14 +361,14 @@
   box->ExpandTo(point_rotated_to);
 
   if (x_is_zero && y_is_zero) {
-    FindCandidatesInPlane(
-        point.x(), point.y(), axis.z(), candidates, &num_candidates);
+    FindCandidatesInPlane(point.x(), point.y(), axis.z(), candidates,
+                          &num_candidates);
   } else if (x_is_zero && z_is_zero) {
-    FindCandidatesInPlane(
-        point.z(), point.x(), axis.y(), candidates, &num_candidates);
+    FindCandidatesInPlane(point.z(), point.x(), axis.y(), candidates,
+                          &num_candidates);
   } else if (y_is_zero && z_is_zero) {
-    FindCandidatesInPlane(
-        point.y(), point.z(), axis.x(), candidates, &num_candidates);
+    FindCandidatesInPlane(point.y(), point.z(), axis.x(), candidates,
+                          &num_candidates);
   } else {
     gfx::Vector3dF normal = axis;
     normal.Scale(1.f / normal.Length());
@@ -494,8 +494,8 @@
                                  i & 2 ? box.height() : 0.f,
                                  i & 4 ? box.depth() : 0.f);
         gfx::BoxF box_for_arc;
-        BoundingBoxForArc(
-            corner, from, to, min_progress, max_progress, &box_for_arc);
+        BoundingBoxForArc(corner, from, to, min_progress, max_progress,
+                          &box_for_arc);
         if (first_point)
           *bounds = box_for_arc;
         else
@@ -511,4 +511,4 @@
   return false;
 }
 
-}  // namespace cc
+}  // namespace gfx
diff --git a/cc/animation/transform_operation.h b/ui/gfx/transform_operation.h
similarity index 86%
rename from cc/animation/transform_operation.h
rename to ui/gfx/transform_operation.h
index b09accd..5bb0734 100644
--- a/cc/animation/transform_operation.h
+++ b/ui/gfx/transform_operation.h
@@ -2,19 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_ANIMATION_TRANSFORM_OPERATION_H_
-#define CC_ANIMATION_TRANSFORM_OPERATION_H_
+#ifndef UI_GFX_TRANSFORM_OPERATION_H_
+#define UI_GFX_TRANSFORM_OPERATION_H_
 
-#include "cc/animation/animation_export.h"
+#include "ui/gfx/geometry_skia_export.h"
 #include "ui/gfx/transform.h"
 
 namespace gfx {
 class BoxF;
-}
 
-namespace cc {
-
-struct CC_ANIMATION_EXPORT TransformOperation {
+struct GEOMETRY_SKIA_EXPORT TransformOperation {
   enum Type {
     TRANSFORM_OPERATION_TRANSLATE,
     TRANSFORM_OPERATION_ROTATE,
@@ -77,6 +74,6 @@
                                   gfx::BoxF* bounds);
 };
 
-}  // namespace cc
+}  // namespace gfx
 
-#endif  // CC_ANIMATION_TRANSFORM_OPERATION_H_
+#endif  // UI_GFX_TRANSFORM_OPERATION_H_
diff --git a/cc/animation/transform_operations.cc b/ui/gfx/transform_operations.cc
similarity index 90%
rename from cc/animation/transform_operations.cc
rename to ui/gfx/transform_operations.cc
index 2f627f5..849979e 100644
--- a/cc/animation/transform_operations.cc
+++ b/ui/gfx/transform_operations.cc
@@ -2,21 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/animation/transform_operations.h"
+#include "ui/gfx/transform_operations.h"
 
 #include <stddef.h>
 
 #include <algorithm>
 #include <utility>
 
-#include "cc/base/math_util.h"
-#include "ui/gfx/animation/tween.h"
 #include "ui/gfx/geometry/angle_conversions.h"
 #include "ui/gfx/geometry/box_f.h"
 #include "ui/gfx/geometry/vector3d_f.h"
 #include "ui/gfx/transform_util.h"
 
-namespace cc {
+namespace gfx {
 
 TransformOperations::TransformOperations() {}
 
@@ -32,12 +30,12 @@
   return *this;
 }
 
-gfx::Transform TransformOperations::Apply() const {
+Transform TransformOperations::Apply() const {
   return ApplyRemaining(0);
 }
 
-gfx::Transform TransformOperations::ApplyRemaining(size_t start) const {
-  gfx::Transform to_return;
+Transform TransformOperations::ApplyRemaining(size_t start) const {
+  Transform to_return;
   for (size_t i = start; i < operations_.size(); i++) {
     to_return.PreconcatTransform(operations_[i].matrix);
   }
@@ -57,11 +55,11 @@
   return to_return;
 }
 
-bool TransformOperations::BlendedBoundsForBox(const gfx::BoxF& box,
+bool TransformOperations::BlendedBoundsForBox(const BoxF& box,
                                               const TransformOperations& from,
                                               SkScalar min_progress,
                                               SkScalar max_progress,
-                                              gfx::BoxF* bounds) const {
+                                              BoxF* bounds) const {
   *bounds = box;
 
   bool from_identity = from.IsIdentity();
@@ -80,7 +78,7 @@
   // not squashing them.
   for (size_t i = 0; i < num_operations; ++i) {
     size_t operation_index = num_operations - 1 - i;
-    gfx::BoxF bounds_for_operation;
+    BoxF bounds_for_operation;
     const TransformOperation* from_op =
         from_identity ? nullptr : &from.operations_[operation_index];
     const TransformOperation* to_op =
@@ -142,7 +140,7 @@
 }
 
 static SkScalar TanDegrees(double degrees) {
-  return SkDoubleToScalar(std::tan(gfx::DegToRad(degrees)));
+  return SkDoubleToScalar(std::tan(DegToRad(degrees)));
 }
 
 bool TransformOperations::ScaleComponent(SkScalar* scale) const {
@@ -156,8 +154,8 @@
       case TransformOperation::TRANSFORM_OPERATION_MATRIX: {
         if (operation.matrix.HasPerspective())
           return false;
-        gfx::Vector2dF scale_components =
-            MathUtil::ComputeTransform2dScaleComponents(operation.matrix, 1.f);
+        Vector2dF scale_components =
+            ComputeTransform2dScaleComponents(operation.matrix, 1.f);
         operations_scale *=
             std::max(scale_components.x(), scale_components.y());
         break;
@@ -216,8 +214,7 @@
   return std::max(operations_.size(), other.operations_.size());
 }
 
-bool TransformOperations::CanBlendWith(
-    const TransformOperations& other) const {
+bool TransformOperations::CanBlendWith(const TransformOperations& other) const {
   TransformOperations dummy;
   return BlendInternal(other, 0.5, &dummy);
 }
@@ -298,7 +295,7 @@
   decomposed_transforms_.clear();
 }
 
-void TransformOperations::AppendMatrix(const gfx::Transform& matrix) {
+void TransformOperations::AppendMatrix(const Transform& matrix) {
   TransformOperation to_add;
   to_add.matrix = matrix;
   to_add.type = TransformOperation::TRANSFORM_OPERATION_MATRIX;
@@ -362,7 +359,7 @@
         !from.ComputeDecomposedTransform(matching_prefix_length)) {
       return false;
     }
-    gfx::DecomposedTransform matrix_transform = gfx::BlendDecomposedTransforms(
+    DecomposedTransform matrix_transform = BlendDecomposedTransforms(
         *decomposed_transforms_[matching_prefix_length].get(),
         *from.decomposed_transforms_[matching_prefix_length].get(), progress);
     result->AppendMatrix(ComposeTransform(matrix_transform));
@@ -374,14 +371,14 @@
     size_t start_offset) const {
   auto it = decomposed_transforms_.find(start_offset);
   if (it == decomposed_transforms_.end()) {
-    std::unique_ptr<gfx::DecomposedTransform> decomposed_transform =
-        std::make_unique<gfx::DecomposedTransform>();
-    gfx::Transform transform = ApplyRemaining(start_offset);
-    if (!gfx::DecomposeTransform(decomposed_transform.get(), transform))
+    std::unique_ptr<DecomposedTransform> decomposed_transform =
+        std::make_unique<DecomposedTransform>();
+    Transform transform = ApplyRemaining(start_offset);
+    if (!DecomposeTransform(decomposed_transform.get(), transform))
       return false;
     decomposed_transforms_[start_offset] = std::move(decomposed_transform);
   }
   return true;
 }
 
-}  // namespace cc
+}  // namespace gfx
diff --git a/cc/animation/transform_operations.h b/ui/gfx/transform_operations.h
similarity index 87%
rename from cc/animation/transform_operations.h
rename to ui/gfx/transform_operations.h
index 31d50342..d85242ab 100644
--- a/cc/animation/transform_operations.h
+++ b/ui/gfx/transform_operations.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 CC_ANIMATION_TRANSFORM_OPERATIONS_H_
-#define CC_ANIMATION_TRANSFORM_OPERATIONS_H_
+#ifndef UI_GFX_TRANSFORM_OPERATIONS_H_
+#define UI_GFX_TRANSFORM_OPERATIONS_H_
 
 #include <memory>
 #include <unordered_map>
@@ -11,19 +11,17 @@
 
 #include "base/check_op.h"
 #include "base/gtest_prod_util.h"
-#include "cc/animation/animation_export.h"
-#include "cc/animation/transform_operation.h"
+#include "ui/gfx/geometry_skia_export.h"
 #include "ui/gfx/transform.h"
+#include "ui/gfx/transform_operation.h"
 
 namespace gfx {
+
 class BoxF;
 struct DecomposedTransform;
-}
-
-namespace cc {
 
 // Transform operations are a decomposed transformation matrix. It can be
-// applied to obtain a gfx::Transform at any time, and can be blended
+// applied to obtain a Transform at any time, and can be blended
 // intelligently with other transform operations, so long as they represent the
 // same decomposition. For example, if we have a transform that is made up of
 // a rotation followed by skew, it can be blended intelligently with another
@@ -31,7 +29,7 @@
 // we have two dissimilar sets of transform operations, but the effect may not
 // be what was intended. For more information, see the comments for the blend
 // function below.
-class CC_ANIMATION_EXPORT TransformOperations {
+class GEOMETRY_SKIA_EXPORT TransformOperations {
  public:
   TransformOperations();
   TransformOperations(const TransformOperations& other);
@@ -40,11 +38,11 @@
   TransformOperations& operator=(const TransformOperations& other);
 
   // Returns a transformation matrix representing these transform operations.
-  gfx::Transform Apply() const;
+  Transform Apply() const;
 
   // Returns a transformation matrix representing the set of transform
   // operations from index |start| to the end of the list.
-  gfx::Transform ApplyRemaining(size_t start) const;
+  Transform ApplyRemaining(size_t start) const;
 
   // Given another set of transform operations and a progress in the range
   // [0, 1], returns a transformation matrix representing the intermediate
@@ -63,11 +61,11 @@
   // exist when it is transformed by the result of calling Blend on |from| and
   // with progress in the range [min_progress, max_progress]. If this region
   // cannot be computed, returns false.
-  bool BlendedBoundsForBox(const gfx::BoxF& box,
+  bool BlendedBoundsForBox(const BoxF& box,
                            const TransformOperations& from,
                            SkScalar min_progress,
                            SkScalar max_progress,
-                           gfx::BoxF* bounds) const;
+                           BoxF* bounds) const;
 
   // Returns true if these operations are only translations.
   bool IsTranslation() const;
@@ -102,7 +100,7 @@
   void AppendSkewY(SkScalar y);
   void AppendSkew(SkScalar x, SkScalar y);
   void AppendPerspective(SkScalar depth);
-  void AppendMatrix(const gfx::Transform& matrix);
+  void AppendMatrix(const Transform& matrix);
   void AppendIdentity();
   void Append(const TransformOperation& operation);
   bool IsIdentity() const;
@@ -133,10 +131,10 @@
   bool ComputeDecomposedTransform(size_t start_offset) const;
 
   // For efficiency, we cache the decomposed transforms.
-  mutable std::unordered_map<size_t, std::unique_ptr<gfx::DecomposedTransform>>
+  mutable std::unordered_map<size_t, std::unique_ptr<DecomposedTransform>>
       decomposed_transforms_;
 };
 
-}  // namespace cc
+}  // namespace gfx
 
-#endif  // CC_ANIMATION_TRANSFORM_OPERATIONS_H_
+#endif  // UI_GFX_TRANSFORM_OPERATIONS_H_
diff --git a/cc/animation/transform_operations_unittest.cc b/ui/gfx/transform_operations_unittest.cc
similarity index 88%
rename from cc/animation/transform_operations_unittest.cc
rename to ui/gfx/transform_operations_unittest.cc
index bdebd3c4..5a432b6 100644
--- a/cc/animation/transform_operations_unittest.cc
+++ b/ui/gfx/transform_operations_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/animation/transform_operations.h"
+#include "ui/gfx/transform_operations.h"
 
 #include <stddef.h>
 
@@ -11,20 +11,20 @@
 #include <vector>
 
 #include "base/stl_util.h"
-#include "cc/test/geometry_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/animation/tween.h"
 #include "ui/gfx/geometry/box_f.h"
 #include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/test/transform_test_util.h"
 #include "ui/gfx/geometry/vector3d_f.h"
 
-namespace cc {
+namespace gfx {
 namespace {
 
 void ExpectTransformOperationEqual(const TransformOperation& lhs,
                                    const TransformOperation& rhs) {
   EXPECT_EQ(lhs.type, rhs.type);
-  EXPECT_TRANSFORMATION_MATRIX_EQ(lhs.matrix, rhs.matrix);
+  ExpectTransformationMatrixEq(lhs.matrix, rhs.matrix);
   switch (lhs.type) {
     case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
       EXPECT_FLOAT_EQ(lhs.translate.x, rhs.translate.x);
@@ -235,7 +235,7 @@
   operations.AppendTranslate(x, y, z);
   gfx::Transform expected;
   expected.Translate3d(x, y, z);
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply());
+  ExpectTransformationMatrixEq(expected, operations.Apply());
 }
 
 TEST(TransformOperationTest, ApplyRotate) {
@@ -247,7 +247,7 @@
   operations.AppendRotate(x, y, z, degrees);
   gfx::Transform expected;
   expected.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply());
+  ExpectTransformationMatrixEq(expected, operations.Apply());
 }
 
 TEST(TransformOperationTest, ApplyScale) {
@@ -258,7 +258,7 @@
   operations.AppendScale(x, y, z);
   gfx::Transform expected;
   expected.Scale3d(x, y, z);
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply());
+  ExpectTransformationMatrixEq(expected, operations.Apply());
 }
 
 TEST(TransformOperationTest, ApplySkew) {
@@ -268,7 +268,7 @@
   operations.AppendSkew(x, y);
   gfx::Transform expected;
   expected.Skew(x, y);
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply());
+  ExpectTransformationMatrixEq(expected, operations.Apply());
 }
 
 TEST(TransformOperationTest, ApplyPerspective) {
@@ -277,7 +277,7 @@
   operations.AppendPerspective(depth);
   gfx::Transform expected;
   expected.ApplyPerspectiveDepth(depth);
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply());
+  ExpectTransformationMatrixEq(expected, operations.Apply());
 }
 
 TEST(TransformOperationTest, ApplyMatrix) {
@@ -288,7 +288,7 @@
   expected_matrix.Translate3d(dx, dy, dz);
   TransformOperations matrix_transform;
   matrix_transform.AppendMatrix(expected_matrix);
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected_matrix, matrix_transform.Apply());
+  ExpectTransformationMatrixEq(expected_matrix, matrix_transform.Apply());
 }
 
 TEST(TransformOperationTest, ApplyOrder) {
@@ -313,7 +313,7 @@
   gfx::Transform expected_combined_matrix = expected_scale_matrix;
   expected_combined_matrix.PreconcatTransform(expected_translate_matrix);
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected_combined_matrix, operations.Apply());
+  ExpectTransformationMatrixEq(expected_combined_matrix, operations.Apply());
 }
 
 TEST(TransformOperationTest, BlendOrder) {
@@ -379,8 +379,8 @@
 
   TransformOperations blended = operations_to.Blend(operations_from, progress);
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected, blended.Apply());
-  EXPECT_TRANSFORMATION_MATRIX_EQ(operations_expected.Apply(), blended.Apply());
+  ExpectTransformationMatrixEq(expected, blended.Apply());
+  ExpectTransformationMatrixEq(operations_expected.Apply(), blended.Apply());
   EXPECT_EQ(operations_expected.size(), blended.size());
   for (size_t i = 0; i < operations_expected.size(); ++i) {
     TransformOperation expected_op = operations_expected.at(i);
@@ -409,8 +409,8 @@
 
   blended = operations_to.Blend(operations_from, progress);
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected, blended.Apply());
-  EXPECT_TRANSFORMATION_MATRIX_EQ(operations_expected.Apply(), blended.Apply());
+  ExpectTransformationMatrixEq(expected, blended.Apply());
+  ExpectTransformationMatrixEq(operations_expected.Apply(), blended.Apply());
   EXPECT_EQ(operations_expected.size(), blended.size());
   for (size_t i = 0; i < operations_expected.size(); ++i) {
     TransformOperation expected_op = operations_expected.at(i);
@@ -438,8 +438,8 @@
   operations_expected = base_operations_expected;
   operations_expected.AppendMatrix(blended_matrix);
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected, blended.Apply());
-  EXPECT_TRANSFORMATION_MATRIX_EQ(operations_expected.Apply(), blended.Apply());
+  ExpectTransformationMatrixEq(expected, blended.Apply());
+  ExpectTransformationMatrixEq(operations_expected.Apply(), blended.Apply());
   EXPECT_EQ(operations_expected.size(), blended.size());
   for (size_t i = 0; i < operations_expected.size(); ++i) {
     TransformOperation expected_op = operations_expected.at(i);
@@ -456,7 +456,7 @@
                           const TransformOperations& to_transform) {
   gfx::Transform expected_matrix = to_matrix;
   expected_matrix.Blend(from_matrix, progress);
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       expected_matrix, to_transform.Blend(from_transform, progress).Apply());
 }
 
@@ -525,7 +525,7 @@
   gfx::Transform expected = to;
   expected.Blend(from, progress);
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       expected, operations_to.Blend(operations_from, progress).Apply());
 }
 
@@ -541,7 +541,7 @@
   gfx::Transform expected;
   expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 180);
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       expected, operations_to.Blend(operations_from, progress).Apply());
 }
 
@@ -556,7 +556,7 @@
 
   gfx::Transform expected;
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       expected, operations_to.Blend(operations_from, progress).Apply());
 }
 
@@ -577,7 +577,7 @@
   gfx::Transform expected = matrix_to;
   expected.Blend(matrix_from, progress);
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       expected, operations_to.Blend(operations_from, progress).Apply());
 }
 
@@ -591,7 +591,7 @@
   SkScalar progress = 0.5f;
   gfx::Transform expected;
   expected.RotateAbout(gfx::Vector3dF(0, 1, 0), 225);
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       expected, operations_to.Blend(operations_from, progress).Apply());
 }
 
@@ -605,7 +605,7 @@
   SkScalar progress = 0.5f;
   gfx::Transform expected;
   expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 225);
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       expected, operations_to.Blend(operations_from, progress).Apply());
 }
 
@@ -619,7 +619,7 @@
   SkScalar progress = 0.5f;
   gfx::Transform expected;
   expected.RotateAbout(gfx::Vector3dF(0, 1, 0), 225);
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       expected, operations_to.Blend(operations_from, progress).Apply());
 }
 
@@ -633,7 +633,7 @@
   SkScalar progress = 0.5f;
   gfx::Transform expected;
   expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 225);
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       expected, operations_to.Blend(operations_from, progress).Apply());
 }
 
@@ -650,7 +650,7 @@
     gfx::Transform expected;
     expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 45);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, operations.Blend(*identity_operations[i], progress).Apply());
 
     progress = -0.5f;
@@ -658,7 +658,7 @@
     expected.MakeIdentity();
     expected.RotateAbout(gfx::Vector3dF(0, 0, 1), -45);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, operations.Blend(*identity_operations[i], progress).Apply());
 
     progress = 1.5f;
@@ -666,7 +666,7 @@
     expected.MakeIdentity();
     expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 135);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, operations.Blend(*identity_operations[i], progress).Apply());
   }
 }
@@ -684,7 +684,7 @@
     gfx::Transform expected;
     expected.Translate3d(1, 1, 1);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, operations.Blend(*identity_operations[i], progress).Apply());
 
     progress = -0.5f;
@@ -692,7 +692,7 @@
     expected.MakeIdentity();
     expected.Translate3d(-1, -1, -1);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, operations.Blend(*identity_operations[i], progress).Apply());
 
     progress = 1.5f;
@@ -700,7 +700,7 @@
     expected.MakeIdentity();
     expected.Translate3d(3, 3, 3);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, operations.Blend(*identity_operations[i], progress).Apply());
   }
 }
@@ -718,7 +718,7 @@
     gfx::Transform expected;
     expected.Scale3d(2, 2, 2);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, operations.Blend(*identity_operations[i], progress).Apply());
 
     progress = -0.5f;
@@ -726,7 +726,7 @@
     expected.MakeIdentity();
     expected.Scale3d(0, 0, 0);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, operations.Blend(*identity_operations[i], progress).Apply());
 
     progress = 1.5f;
@@ -734,7 +734,7 @@
     expected.MakeIdentity();
     expected.Scale3d(4, 4, 4);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, operations.Blend(*identity_operations[i], progress).Apply());
   }
 }
@@ -750,7 +750,7 @@
   gfx::Transform expected;
   expected.Skew(1, 1);
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       expected, operations.Blend(empty_operation, progress).Apply());
 
   progress = -0.5f;
@@ -758,7 +758,7 @@
   expected.MakeIdentity();
   expected.Skew(-1, -1);
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       expected, operations.Blend(empty_operation, progress).Apply());
 
   progress = 1.5f;
@@ -766,7 +766,7 @@
   expected.MakeIdentity();
   expected.Skew(3, 3);
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       expected, operations.Blend(empty_operation, progress).Apply());
 }
 
@@ -783,7 +783,7 @@
     gfx::Transform expected;
     expected.ApplyPerspectiveDepth(2000);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, operations.Blend(*identity_operations[i], progress).Apply());
   }
 }
@@ -801,7 +801,7 @@
     gfx::Transform expected;
     expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 45);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, identity_operations[i]->Blend(operations, progress).Apply());
   }
 }
@@ -819,7 +819,7 @@
     gfx::Transform expected;
     expected.Translate3d(1, 1, 1);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, identity_operations[i]->Blend(operations, progress).Apply());
   }
 }
@@ -837,7 +837,7 @@
     gfx::Transform expected;
     expected.Scale3d(2, 2, 2);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, identity_operations[i]->Blend(operations, progress).Apply());
   }
 }
@@ -853,7 +853,7 @@
   gfx::Transform expected;
   expected.Skew(1, 1);
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       expected, empty_operation.Blend(operations, progress).Apply());
 }
 
@@ -870,7 +870,7 @@
     gfx::Transform expected;
     expected.ApplyPerspectiveDepth(2000);
 
-    EXPECT_TRANSFORMATION_MATRIX_EQ(
+    ExpectTransformationMatrixEq(
         expected, identity_operations[i]->Blend(operations, progress).Apply());
   }
 }
@@ -885,14 +885,14 @@
   gfx::Transform expected;
   expected.ApplyPerspectiveDepth(400);
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected,
-                                  operations1.Blend(operations2, -0.5).Apply());
+  ExpectTransformationMatrixEq(expected,
+                               operations1.Blend(operations2, -0.5).Apply());
 
   expected.MakeIdentity();
   expected.ApplyPerspectiveDepth(2000);
 
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected,
-                                  operations1.Blend(operations2, 1.5).Apply());
+  ExpectTransformationMatrixEq(expected,
+                               operations1.Blend(operations2, 1.5).Apply());
 }
 
 TEST(TransformOperationTest, ExtrapolateMatrixBlending) {
@@ -907,12 +907,12 @@
   operations2.AppendMatrix(transform2);
 
   gfx::Transform expected;
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected,
-                                  operations1.Blend(operations2, 1.5).Apply());
+  ExpectTransformationMatrixEq(expected,
+                               operations1.Blend(operations2, 1.5).Apply());
 
   expected.Translate3d(4, 4, 4);
-  EXPECT_TRANSFORMATION_MATRIX_EQ(expected,
-                                  operations1.Blend(operations2, -0.5).Apply());
+  ExpectTransformationMatrixEq(expected,
+                               operations1.Blend(operations2, -0.5).Apply());
 }
 
 TEST(TransformOperationTest, NonDecomposableBlend) {
@@ -925,18 +925,18 @@
   identity_transform.AppendMatrix(identity_matrix);
 
   // Before the half-way point, we should return the 'from' matrix.
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       non_decomposible_matrix,
       identity_transform.Blend(non_decomposible_transform, 0.0f).Apply());
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       non_decomposible_matrix,
       identity_transform.Blend(non_decomposible_transform, 0.49f).Apply());
 
   // After the half-way point, we should return the 'to' matrix.
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       identity_matrix,
       identity_transform.Blend(non_decomposible_transform, 0.5f).Apply());
-  EXPECT_TRANSFORMATION_MATRIX_EQ(
+  ExpectTransformationMatrixEq(
       identity_matrix,
       identity_transform.Blend(non_decomposible_transform, 1.0f).Apply());
 }
@@ -1001,13 +1001,13 @@
             bounds.ToString());
 
   TransformOperations identity;
-  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
-        box, identity, min_progress, max_progress, &bounds));
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(box, identity, min_progress,
+                                                max_progress, &bounds));
   EXPECT_EQ(gfx::BoxF(1.f, 2.f, 1.f, 11.f, 8.f, 6.f).ToString(),
             bounds.ToString());
 
-  EXPECT_TRUE(identity.BlendedBoundsForBox(
-        box, operations_from, min_progress, max_progress, &bounds));
+  EXPECT_TRUE(identity.BlendedBoundsForBox(box, operations_from, min_progress,
+                                           max_progress, &bounds));
   EXPECT_EQ(gfx::BoxF(1.f, -2.f, 3.f, 7.f, 8.f, 6.f).ToString(),
             bounds.ToString());
 }
@@ -1036,13 +1036,13 @@
             bounds.ToString());
 
   TransformOperations identity;
-  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
-        box, identity, min_progress, max_progress, &bounds));
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(box, identity, min_progress,
+                                                max_progress, &bounds));
   EXPECT_EQ(gfx::BoxF(1.f, 2.f, -14.f, 34.f, 22.f, 21.f).ToString(),
             bounds.ToString());
 
-  EXPECT_TRUE(identity.BlendedBoundsForBox(
-        box, operations_from, min_progress, max_progress, &bounds));
+  EXPECT_TRUE(identity.BlendedBoundsForBox(box, operations_from, min_progress,
+                                           max_progress, &bounds));
   EXPECT_EQ(gfx::BoxF(1.f, 1.f, 3.f, 14.f, 5.f, 11.f).ToString(),
             bounds.ToString());
 }
@@ -1058,18 +1058,18 @@
 
   SkScalar min_progress = 0.f;
   SkScalar max_progress = 1.f;
-  EXPECT_TRUE(zero_scale.BlendedBoundsForBox(
-      box, non_zero_scale, min_progress, max_progress, &bounds));
+  EXPECT_TRUE(zero_scale.BlendedBoundsForBox(box, non_zero_scale, min_progress,
+                                             max_progress, &bounds));
   EXPECT_EQ(gfx::BoxF(0.f, -24.f, 0.f, 10.f, 24.f, 35.f).ToString(),
             bounds.ToString());
 
-  EXPECT_TRUE(non_zero_scale.BlendedBoundsForBox(
-      box, zero_scale, min_progress, max_progress, &bounds));
+  EXPECT_TRUE(non_zero_scale.BlendedBoundsForBox(box, zero_scale, min_progress,
+                                                 max_progress, &bounds));
   EXPECT_EQ(gfx::BoxF(0.f, -24.f, 0.f, 10.f, 24.f, 35.f).ToString(),
             bounds.ToString());
 
-  EXPECT_TRUE(zero_scale.BlendedBoundsForBox(
-      box, zero_scale, min_progress, max_progress, &bounds));
+  EXPECT_TRUE(zero_scale.BlendedBoundsForBox(box, zero_scale, min_progress,
+                                             max_progress, &bounds));
   EXPECT_EQ(gfx::BoxF().ToString(), bounds.ToString());
 }
 
@@ -1080,13 +1080,12 @@
   operations_to.AppendRotate(0.f, 0.f, 1.f, 360.f);
 
   float sqrt_2 = sqrt(2.f);
-  gfx::BoxF box(
-      -sqrt_2, -sqrt_2, 0.f, sqrt_2, sqrt_2, 0.f);
+  gfx::BoxF box(-sqrt_2, -sqrt_2, 0.f, sqrt_2, sqrt_2, 0.f);
   gfx::BoxF bounds;
 
   // Since we're rotating 360 degrees, any box with dimensions between 0 and
   // 2 * sqrt(2) should give the same result.
-  float sizes[] = { 0.f, 0.1f, sqrt_2, 2.f * sqrt_2 };
+  float sizes[] = {0.f, 0.1f, sqrt_2, 2.f * sqrt_2};
   for (size_t i = 0; i < base::size(sizes); ++i) {
     box.set_size(sizes[i], sizes[i], 0.f);
     SkScalar min_progress = 0.f;
@@ -1113,8 +1112,8 @@
   float min = -1.f / 3.f;
   float max = 1.f;
   float size = max - min;
-  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
-      box, operations_from, 0.f, 1.f, &bounds));
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(box, operations_from, 0.f, 1.f,
+                                                &bounds));
   EXPECT_EQ(gfx::BoxF(min, min, min, size, size, size).ToString(),
             bounds.ToString());
 }
@@ -1135,12 +1134,12 @@
   gfx::BoxF box(1.f, 0.f, 0.f, 0.f, 0.f, 0.f);
   gfx::BoxF bounds;
 
-  EXPECT_TRUE(operations_to_same.BlendedBoundsForBox(
-      box, operations_from, 0.f, 1.f, &bounds));
-  EXPECT_TRUE(operations_to_opposite.BlendedBoundsForBox(
-      box, operations_from, 0.f, 1.f, &bounds));
-  EXPECT_FALSE(operations_to_different.BlendedBoundsForBox(
-      box, operations_from, 0.f, 1.f, &bounds));
+  EXPECT_TRUE(operations_to_same.BlendedBoundsForBox(box, operations_from, 0.f,
+                                                     1.f, &bounds));
+  EXPECT_TRUE(operations_to_opposite.BlendedBoundsForBox(box, operations_from,
+                                                         0.f, 1.f, &bounds));
+  EXPECT_FALSE(operations_to_different.BlendedBoundsForBox(box, operations_from,
+                                                           0.f, 1.f, &bounds));
 }
 
 TEST(TransformOperationTest, BlendedBoundsForRotationPointOnAxis) {
@@ -1154,8 +1153,8 @@
   gfx::BoxF box(1.f, 1.f, 1.f, 0.f, 0.f, 0.f);
   gfx::BoxF bounds;
 
-  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
-      box, operations_from, 0.f, 1.f, &bounds));
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(box, operations_from, 0.f, 1.f,
+                                                &bounds));
   EXPECT_EQ(box.ToString(), bounds.ToString());
 }
 
@@ -1193,8 +1192,8 @@
     gfx::BoxF box(1.f, 1.f, 1.f, 0.f, 0.f, 0.f);
     gfx::BoxF bounds;
 
-    EXPECT_TRUE(operations_to.BlendedBoundsForBox(
-        box, operations_from, 0.f, 1.f, &bounds));
+    EXPECT_TRUE(operations_to.BlendedBoundsForBox(box, operations_from, 0.f,
+                                                  1.f, &bounds));
     EXPECT_EQ(tests[i].expected.ToString(), bounds.ToString());
   }
 }
@@ -1244,11 +1243,9 @@
     // Convert to the screen space rects these boxes represent.
     gfx::Rect bounds_rect = ToEnclosingRect(
         gfx::RectF(bounds.x(), bounds.y(), bounds.width(), bounds.height()));
-    gfx::Rect unified_bounds_rect =
-        ToEnclosingRect(gfx::RectF(unified_bounds.x(),
-                                   unified_bounds.y(),
-                                   unified_bounds.width(),
-                                   unified_bounds.height()));
+    gfx::Rect unified_bounds_rect = ToEnclosingRect(
+        gfx::RectF(unified_bounds.x(), unified_bounds.y(),
+                   unified_bounds.width(), unified_bounds.height()));
     EXPECT_EQ(bounds_rect.ToString(), unified_bounds_rect.ToString());
   } else {
     // Our empirical estimate will be a little rough since we're only doing
@@ -1281,35 +1278,18 @@
     float x;
     float y;
     float z;
-  } axes[] = {{1.f, 1.f, 1.f},
-              {-1.f, -1.f, -1.f},
-              {-1.f, 2.f, 3.f},
-              {1.f, -2.f, 3.f},
-              {1.f, 2.f, -3.f},
-              {0.f, 0.f, 0.f},
-              {1.f, 0.f, 0.f},
-              {0.f, 1.f, 0.f},
-              {0.f, 0.f, 1.f},
-              {1.f, 1.f, 0.f},
-              {0.f, 1.f, 1.f},
-              {1.f, 0.f, 1.f},
-              {-1.f, 0.f, 0.f},
-              {0.f, -1.f, 0.f},
-              {0.f, 0.f, -1.f},
-              {-1.f, -1.f, 0.f},
-              {0.f, -1.f, -1.f},
-              {-1.f, 0.f, -1.f}};
+  } axes[] = {{1.f, 1.f, 1.f},   {-1.f, -1.f, -1.f}, {-1.f, 2.f, 3.f},
+              {1.f, -2.f, 3.f},  {1.f, 2.f, -3.f},   {0.f, 0.f, 0.f},
+              {1.f, 0.f, 0.f},   {0.f, 1.f, 0.f},    {0.f, 0.f, 1.f},
+              {1.f, 1.f, 0.f},   {0.f, 1.f, 1.f},    {1.f, 0.f, 1.f},
+              {-1.f, 0.f, 0.f},  {0.f, -1.f, 0.f},   {0.f, 0.f, -1.f},
+              {-1.f, -1.f, 0.f}, {0.f, -1.f, -1.f},  {-1.f, 0.f, -1.f}};
 
   struct {
     float theta_from;
     float theta_to;
-  } angles[] = {{5.f, 10.f},
-                {10.f, 5.f},
-                {0.f, 360.f},
-                {20.f, 180.f},
-                {-20.f, -180.f},
-                {180.f, -220.f},
-                {220.f, 320.f}};
+  } angles[] = {{5.f, 10.f},     {10.f, 5.f},     {0.f, 360.f},  {20.f, 180.f},
+                {-20.f, -180.f}, {180.f, -220.f}, {220.f, 320.f}};
 
   // We can go beyond the range [0, 1] (the bezier might slide out of this range
   // at either end), but since the first and last knots are at (0, 0) and (1, 1)
@@ -1318,8 +1298,9 @@
     float min_progress;
     float max_progress;
   } progress[] = {
-        {0.f, 1.f}, {-.25f, 1.25f},
-    };
+      {0.f, 1.f},
+      {-.25f, 1.25f},
+  };
 
   for (size_t i = 0; i < base::size(axes); ++i) {
     for (size_t j = 0; j < base::size(angles); ++j) {
@@ -1331,8 +1312,7 @@
         operations_from.AppendRotate(x, y, z, angles[j].theta_from);
         TransformOperations operations_to;
         operations_to.AppendRotate(x, y, z, angles[j].theta_to);
-        EmpiricallyTestBoundsContainment(operations_from,
-                                         operations_to,
+        EmpiricallyTestBoundsContainment(operations_from, operations_to,
                                          progress[k].min_progress,
                                          progress[k].max_progress);
       }
@@ -1341,30 +1321,30 @@
 }
 
 TEST(TransformOperationTest, PerspectiveMatrixAndTransformBlendingEquivalency) {
-    TransformOperations from_operations;
-    from_operations.AppendPerspective(200);
+  TransformOperations from_operations;
+  from_operations.AppendPerspective(200);
 
-    TransformOperations to_operations;
-    to_operations.AppendPerspective(1000);
+  TransformOperations to_operations;
+  to_operations.AppendPerspective(1000);
 
-    gfx::Transform from_transform;
-    from_transform.ApplyPerspectiveDepth(200);
+  gfx::Transform from_transform;
+  from_transform.ApplyPerspectiveDepth(200);
 
-    gfx::Transform to_transform;
-    to_transform.ApplyPerspectiveDepth(1000);
+  gfx::Transform to_transform;
+  to_transform.ApplyPerspectiveDepth(1000);
 
-    static const int steps = 20;
-    for (int i = 0; i < steps; ++i) {
-      double progress = static_cast<double>(i) / (steps - 1);
+  static const int steps = 20;
+  for (int i = 0; i < steps; ++i) {
+    double progress = static_cast<double>(i) / (steps - 1);
 
-      gfx::Transform blended_matrix = to_transform;
-      EXPECT_TRUE(blended_matrix.Blend(from_transform, progress));
+    gfx::Transform blended_matrix = to_transform;
+    EXPECT_TRUE(blended_matrix.Blend(from_transform, progress));
 
-      gfx::Transform blended_transform =
-          to_operations.Blend(from_operations, progress).Apply();
+    gfx::Transform blended_transform =
+        to_operations.Blend(from_operations, progress).Apply();
 
-      EXPECT_TRANSFORMATION_MATRIX_EQ(blended_matrix, blended_transform);
-    }
+    ExpectTransformationMatrixEq(blended_matrix, blended_transform);
+  }
 }
 
 TEST(TransformOperationTest, BlendedBoundsForPerspective) {
@@ -1372,17 +1352,18 @@
     float from_depth;
     float to_depth;
   } perspective_depths[] = {
-        {600.f, 400.f},
-        {800.f, 1000.f},
-        {800.f, std::numeric_limits<float>::infinity()},
-    };
+      {600.f, 400.f},
+      {800.f, 1000.f},
+      {800.f, std::numeric_limits<float>::infinity()},
+  };
 
   struct {
     float min_progress;
     float max_progress;
   } progress[] = {
-        {0.f, 1.f}, {-0.1f, 1.1f},
-    };
+      {0.f, 1.f},
+      {-0.1f, 1.1f},
+  };
 
   for (size_t i = 0; i < base::size(perspective_depths); ++i) {
     for (size_t j = 0; j < base::size(progress); ++j) {
@@ -1390,8 +1371,7 @@
       operations_from.AppendPerspective(perspective_depths[i].from_depth);
       TransformOperations operations_to;
       operations_to.AppendPerspective(perspective_depths[i].to_depth);
-      EmpiricallyTestBoundsEquality(operations_from,
-                                    operations_to,
+      EmpiricallyTestBoundsEquality(operations_from, operations_to,
                                     progress[j].min_progress,
                                     progress[j].max_progress);
     }
@@ -1405,15 +1385,17 @@
     float to_x;
     float to_y;
   } skews[] = {
-        {1.f, 0.5f, 0.5f, 1.f}, {2.f, 1.f, 0.5f, 0.5f},
-    };
+      {1.f, 0.5f, 0.5f, 1.f},
+      {2.f, 1.f, 0.5f, 0.5f},
+  };
 
   struct {
     float min_progress;
     float max_progress;
   } progress[] = {
-        {0.f, 1.f}, {-0.1f, 1.1f},
-    };
+      {0.f, 1.f},
+      {-0.1f, 1.1f},
+  };
 
   for (size_t i = 0; i < base::size(skews); ++i) {
     for (size_t j = 0; j < base::size(progress); ++j) {
@@ -1421,8 +1403,7 @@
       operations_from.AppendSkew(skews[i].from_x, skews[i].from_y);
       TransformOperations operations_to;
       operations_to.AppendSkew(skews[i].to_x, skews[i].to_y);
-      EmpiricallyTestBoundsEquality(operations_from,
-                                    operations_to,
+      EmpiricallyTestBoundsEquality(operations_from, operations_to,
                                     progress[j].min_progress,
                                     progress[j].max_progress);
     }
@@ -1481,13 +1462,13 @@
             bounds.ToString());
 
   TransformOperations identity;
-  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
-        box, identity, min_progress, max_progress, &bounds));
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(box, identity, min_progress,
+                                                max_progress, &bounds));
   EXPECT_EQ(gfx::BoxF(-33.f, -13.f, 3.f, 57.f, 19.f, 52.f).ToString(),
             bounds.ToString());
 
-  EXPECT_TRUE(identity.BlendedBoundsForBox(
-        box, operations_from, min_progress, max_progress, &bounds));
+  EXPECT_TRUE(identity.BlendedBoundsForBox(box, operations_from, min_progress,
+                                           max_progress, &bounds));
   EXPECT_EQ(gfx::BoxF(-7.f, -3.f, 2.f, 15.f, 23.f, 20.f).ToString(),
             bounds.ToString());
 }
@@ -1828,4 +1809,4 @@
   ExpectTransformOperationEqual(blended_ops.at(1), expected_ops.at(1));
 }
 
-}  // namespace cc
+}  // namespace gfx
diff --git a/ui/gfx/transform_util.cc b/ui/gfx/transform_util.cc
index 97ddcbf3..77ffa108 100644
--- a/ui/gfx/transform_util.cc
+++ b/ui/gfx/transform_util.cc
@@ -633,4 +633,39 @@
   return canvas;
 }
 
+static inline bool NearlyZero(double value) {
+  return std::abs(value) < std::numeric_limits<double>::epsilon();
+}
+
+static inline float ScaleOnAxis(double a, double b, double c) {
+  if (NearlyZero(b) && NearlyZero(c))
+    return std::abs(a);
+  if (NearlyZero(a) && NearlyZero(c))
+    return std::abs(b);
+  if (NearlyZero(a) && NearlyZero(b))
+    return std::abs(c);
+
+  // Do the sqrt as a double to not lose precision.
+  return static_cast<float>(std::sqrt(a * a + b * b + c * c));
+}
+
+Vector2dF ComputeTransform2dScaleComponents(const Transform& transform,
+                                            float fallback_value) {
+  if (transform.HasPerspective())
+    return Vector2dF(fallback_value, fallback_value);
+  float x_scale = ScaleOnAxis(transform.matrix().getDouble(0, 0),
+                              transform.matrix().getDouble(1, 0),
+                              transform.matrix().getDouble(2, 0));
+  float y_scale = ScaleOnAxis(transform.matrix().getDouble(0, 1),
+                              transform.matrix().getDouble(1, 1),
+                              transform.matrix().getDouble(2, 1));
+  return Vector2dF(x_scale, y_scale);
+}
+
+float ComputeApproximateMaxScale(const Transform& transform) {
+  RectF unit(0.f, 0.f, 1.f, 1.f);
+  transform.TransformRect(&unit);
+  return std::max(unit.width(), unit.height());
+}
+
 }  // namespace gfx
diff --git a/ui/gfx/transform_util.h b/ui/gfx/transform_util.h
index 59d91b7..af40987 100644
--- a/ui/gfx/transform_util.h
+++ b/ui/gfx/transform_util.h
@@ -84,6 +84,16 @@
                                             int width,
                                             int height);
 
+GEOMETRY_SKIA_EXPORT Vector2dF
+ComputeTransform2dScaleComponents(const Transform& transform,
+                                  float fallback_value);
+
+// Returns an approximate max scale value of the transform even if it has
+// perspective. Prefer to use ComputeTransform2dScaleComponents if there is no
+// perspective, since it can produce more accurate results.
+GEOMETRY_SKIA_EXPORT
+float ComputeApproximateMaxScale(const Transform& transform);
+
 }  // namespace gfx
 
 #endif  // UI_GFX_TRANSFORM_UTIL_H_
diff --git a/ui/webui/resources/cr_components/chromeos/BUILD.gn b/ui/webui/resources/cr_components/chromeos/BUILD.gn
index 12583695..1e2602d 100644
--- a/ui/webui/resources/cr_components/chromeos/BUILD.gn
+++ b/ui/webui/resources/cr_components/chromeos/BUILD.gn
@@ -13,6 +13,8 @@
     "cellular_setup:closure_compile",
     "cellular_setup:closure_compile_module",
     "multidevice_setup:closure_compile",
+
+    # "multidevice_setup:closure_compile_module",
     "network:closure_compile",
     "network:closure_compile_module",
     "network_health:closure_compile",
@@ -28,6 +30,7 @@
   public_deps = [
     "bluetooth:polymer3_elements",
     "cellular_setup:polymer3_elements",
+    "multidevice_setup:polymer3_elements",
     "network:polymer3_elements",
     "network_health:polymer3_elements",
     "quick_unlock:polymer3_elements",
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn b/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn
index 63fd8b3..95b4f87 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn
@@ -3,6 +3,9 @@
 # found in the LICENSE file.
 
 import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/polymer/polymer.gni")
+import("//ui/webui/resources/tools/js_modulizer.gni")
+import("../os_cr_components.gni")
 
 assert(is_chromeos, "MultiDevice UI is Chrome OS only.")
 
@@ -92,3 +95,147 @@
     "//ui/webui/resources/js:i18n_behavior",
   ]
 }
+
+# Polymer 3 files
+
+# TODO: Uncomment as the Polymer3 migration makes progress.
+# js_type_check("closure_compile_module") {
+#   is_polymer3 = true
+#   deps = [
+#     ":button_bar.m",
+#     ":fake_mojo_service.m",
+#     ":mojo_api.m",
+#     ":multidevice_setup.m",
+#     ":multidevice_setup_browser_proxy.m",
+#     ":multidevice_setup_delegate.m",
+#     ":setup_succeeded_page.m",
+#     ":start_setup_page.m",
+#     ":ui_page_container_behavior.m",
+#     "//ui/webui/resources/js:web_ui_listener_behavior.m",
+#   ]
+# }
+
+js_library("button_bar.m") {
+  sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.m.js" ]
+  deps = []
+  extra_deps = [ ":button_bar_module" ]
+}
+
+js_library("fake_mojo_service.m") {
+  sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("mojo_api.m") {
+  sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("multidevice_setup.m") {
+  sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.m.js" ]
+  deps = []
+  extra_deps = [ ":multidevice_setup_module" ]
+}
+
+js_library("multidevice_setup_browser_proxy.m") {
+  sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("multidevice_setup_delegate.m") {
+  sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("password_page.m") {
+  sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.m.js" ]
+  deps = []
+  extra_deps = [ ":password_page_module" ]
+  externs_list = chrome_extension_public_externs +
+                 [ "$externs_path/quick_unlock_private.js" ]
+  extra_sources = [ "$interfaces_path/quick_unlock_private_interface.js" ]
+}
+
+js_library("setup_succeeded_page.m") {
+  sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.m.js" ]
+  deps = []
+  extra_deps = [ ":setup_succeeded_page_module" ]
+}
+
+js_library("start_setup_page.m") {
+  sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.m.js" ]
+  deps = []
+  extra_deps = [ ":start_setup_page_module" ]
+}
+
+js_library("ui_page_container_behavior.m") {
+  sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+group("polymer3_elements") {
+  public_deps = [
+    ":button_bar_module",
+    ":modulize",
+    ":multidevice_setup_module",
+    ":password_page_module",
+    ":setup_succeeded_page_module",
+    ":start_setup_page_module",
+  ]
+}
+
+polymer_modulizer("button_bar") {
+  js_file = "button_bar.js"
+  html_file = "button_bar.html"
+  html_type = "dom-module"
+  namespace_rewrites = cr_components_chromeos_namespace_rewrites
+  auto_imports = cr_components_chromeos_auto_imports
+}
+
+polymer_modulizer("multidevice_setup") {
+  js_file = "multidevice_setup.js"
+  html_file = "multidevice_setup.html"
+  html_type = "dom-module"
+  namespace_rewrites = cr_components_chromeos_namespace_rewrites
+  auto_imports = cr_components_chromeos_auto_imports
+}
+
+polymer_modulizer("password_page") {
+  js_file = "password_page.js"
+  html_file = "password_page.html"
+  html_type = "dom-module"
+  namespace_rewrites = cr_components_chromeos_namespace_rewrites
+  auto_imports = cr_components_chromeos_auto_imports
+}
+
+polymer_modulizer("setup_succeeded_page") {
+  js_file = "setup_succeeded_page.js"
+  html_file = "setup_succeeded_page.html"
+  html_type = "dom-module"
+  namespace_rewrites = cr_components_chromeos_namespace_rewrites
+  auto_imports = cr_components_chromeos_auto_imports
+}
+
+polymer_modulizer("start_setup_page") {
+  js_file = "start_setup_page.js"
+  html_file = "start_setup_page.html"
+  html_type = "dom-module"
+  namespace_rewrites = cr_components_chromeos_namespace_rewrites
+  auto_imports = cr_components_chromeos_auto_imports
+}
+
+js_modulizer("modulize") {
+  input_files = [
+    "fake_mojo_service.js",
+    "mojo_api.js",
+    "multidevice_setup_browser_proxy.js",
+    "multidevice_setup_delegate.js",
+    "ui_page_container_behavior.js",
+  ]
+  namespace_rewrites = cr_components_chromeos_namespace_rewrites
+}
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.html b/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.html
index b448b29..69ee219 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.html
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.html
@@ -47,6 +47,5 @@
       </div>
     </div>
   </template>
-  <script src="button_bar.js">
-  </script>
+  <script src="button_bar.js"></script>
 </dom-module>
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.html b/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.html
index a2c17b6..55f5b15 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.html
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.html
@@ -1,4 +1,3 @@
 <link rel="import" href="../../../html/cr.html">
 
-<script src="fake_mojo_service.js">
-</script>
+<script src="fake_mojo_service.js"></script>
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js b/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js
index c344992..7bdd6b9 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js
@@ -31,6 +31,7 @@
 
   cr.addSingletonGetter(MojoInterfaceProviderImpl);
 
+  // #cr_define_end
   return {
     MojoInterfaceProvider: MojoInterfaceProvider,
     MojoInterfaceProviderImpl: MojoInterfaceProviderImpl,
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html
index 6e61d099..8c97425 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html
@@ -105,6 +105,5 @@
       </button-bar>
     </div>
   </template>
-  <script src="multidevice_setup.js">
-  </script>
+  <script src="multidevice_setup.js"></script>
 </dom-module>
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js
index a565031..f4eea9c 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js
@@ -368,6 +368,7 @@
     },
   });
 
+  // #cr_define_end
   return {
     MultiDeviceSetup: MultiDeviceSetup,
     PageName: PageName,
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html
index 38c23fd..29e0582c 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html
@@ -1,3 +1,2 @@
 <link rel="import" href="../../../html/cr.html">
-<script src="multidevice_setup_browser_proxy.js">
-</script>
+<script src="multidevice_setup_browser_proxy.js"></script>
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.js b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.js
index be88d746..dfa9dc6 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.js
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.js
@@ -34,6 +34,7 @@
 
   cr.addSingletonGetter(BrowserProxyImpl);
 
+  // #cr_define_end
   return {
     BrowserProxy: BrowserProxy,
     BrowserProxyImpl: BrowserProxyImpl,
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html
index 22e3eb3..6995dda 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html
@@ -1,4 +1,3 @@
 <link rel="import" href="../../../html/cr.html">
-<script src="multidevice_setup_delegate.js">
-</script>
+<script src="multidevice_setup_delegate.js"></script>
 
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.js b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.js
index 448de24..1b4828d 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.js
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.js
@@ -29,6 +29,7 @@
     getStartSetupCancelButtonTextId() {}
   }
 
+  // #cr_define_end
   return {
     MultiDeviceSetupDelegate: MultiDeviceSetupDelegate,
   };
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html b/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html
index 1d1b634..48ab163 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html
@@ -46,6 +46,5 @@
       </div>
     </ui-page>
   </template>
-  <script src="password_page.js">
-  </script>
+  <script src="password_page.js"></script>
 </dom-module>
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html b/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html
index fefc1dc6..37f85df 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html
@@ -31,6 +31,5 @@
       </div>
     </ui-page>
   </template>
-  <script src="setup_succeeded_page.js">
-  </script>
+  <script src="setup_succeeded_page.js"></script>
 </dom-module>
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html b/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html
index 6ed75f5..301acafb2 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html
@@ -189,6 +189,5 @@
       </div>
     </ui-page>
   </template>
-  <script src="start_setup_page.js">
-  </script>
+  <script src="start_setup_page.js"></script>
 </dom-module>
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.html b/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.html
index 1bdfe7b6..5d4d3be6 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.html
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.html
@@ -37,6 +37,5 @@
       <slot name="additional-content"></slot>
     </div>
   </template>
-  <script src="ui_page.js">
-  </script>
+  <script src="ui_page.js"></script>
 </dom-module>
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html b/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html
index 3485a995..020f0507 100644
--- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html
+++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html
@@ -1,5 +1,4 @@
 <link rel="import" href="../../../html/cr.html">
 <link rel="import" href="../../../html/i18n_behavior.html">
 
-<script src="ui_page_container_behavior.js">
-</script>
+<script src="ui_page_container_behavior.js"></script>