diff --git a/BUILD.gn b/BUILD.gn
index 853a7fd..082b2830 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -592,13 +592,6 @@
       if (is_linux || is_chromeos) {
         # TODO(dpranke): Figure out what platforms should actually have this.
         deps += [ "//components/nacl/loader:nacl_helper" ]
-
-        if (enable_nacl_nonsfi) {
-          deps += [
-            "//components/nacl/loader:helper_nonsfi",
-            "//components/nacl/loader:nacl_helper_nonsfi_unittests",
-          ]
-        }
       }
     }
 
diff --git a/DEPS b/DEPS
index 058ec761..f00970c 100644
--- a/DEPS
+++ b/DEPS
@@ -202,7 +202,7 @@
   # luci-go CIPD package version.
   # Make sure the revision is uploaded by infra-packagers builder.
   # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
-  'luci_go': 'git_revision:7422359d33c606e8adb0e9cf461837eb9b49431f',
+  'luci_go': 'git_revision:e4c95e4e4cdc987f1860e4111589606bcd3a8f32',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -234,15 +234,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '15949beef238deddc21194f13df6e5849f815872',
+  'skia_revision': '0ed19771c38ceda8fabb2ffcb0a6b687fcf65302',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'b2d7879f825d93c8554c51ce57f2c502c504c2ee',
+  'v8_revision': '10ed64a372e70c27ab0dd770ccf3ca3b93e3eda1',
   # 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': 'ef65edf2f2e58cfe02c371c7a73745de8afa8a18',
+  'angle_revision': '739c414f77c83a0772f6b0e67b7a09f91b35b100',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -265,7 +265,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling googletest
   # and whatever else without interference from each other.
-  'googletest_revision': 'e2f3978937c0244508135f126e2617a7734a68be',
+  'googletest_revision': 'bb9216085fbbf193408653ced9e73c61e7766e80',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling lighttpd
   # and whatever else without interference from each other.
@@ -309,7 +309,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'e0f092e9082bfc45692ffebed7cc53639f5cc9b6',
+  'devtools_frontend_revision': 'f7a1e3a4947323b1dda0cf6d2f1909922a3e9766',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -349,7 +349,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '633d40bd0fbb88b39e0ea76d94c02fd665086c8a',
+  'dawn_revision': '6e83e6284eb6a83e3ffce3e1d7d78cfee3130833',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -603,7 +603,7 @@
     Var('chromium_git') + '/external/github.com/toji/webvr.info.git' + '@' + 'c58ae99b9ff9e2aa4c524633519570bf33536248',
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + '9308f80e507f48b9b8216f81291020f6c945b326',
+    'url': Var('chromium_git') + '/website.git' + '@' + '014a07e35d739e5dd71be9905ac1d589a8a392e8',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -791,7 +791,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'XSHrYFNYVHl0vna-Qi6iVbg-_eXSr31_Z04UJ-zVc1YC',
+          'version': 'fLKT6t1QfUqOQR_DsCtVlubXz-ud0Hwfsmzy21I9rToC',
       },
     ],
     'condition': 'checkout_android',
@@ -1595,7 +1595,7 @@
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '62d7d0c928c9a040dce96aa2f16c00e7e67d59cb',
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@4282fc920603a3a5574693e5c241534799e7e30b',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@cb8be59599df8d3d36115e4164946d58fceb40f8',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '5e49f57a6e71a026a54eb42e366de09a4142d24e',
@@ -1692,7 +1692,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@656a623fee4d746b62e645bb766cb3c74b45d35d',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ae53e3e15f319f49946af9137bae7048528dd7bc',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 1ffbe52..646b3ed 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -5514,3 +5514,28 @@
               'section in //base/memory/raw_ptr.md)'.format(
                   path=f.LocalPath(), line=line_num)))
   return errors
+
+
+def CheckPythonShebang(input_api, output_api):
+    """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
+    system-wide python.
+    """
+    errors = []
+    sources = lambda affected_file: input_api.FilterSourceFile(
+        affected_file,
+        files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
+                        r'third_party/blink/web_tests/external/') + input_api.
+                       DEFAULT_FILES_TO_SKIP),
+        files_to_check=[r'.*\.py$'])
+    for f in input_api.AffectedSourceFiles(sources):
+        [line_num, line] = f.ChangedContents()[0]
+        if line_num == 1 and line.startswith('#!/usr/bin/python'):
+            errors.append(f.LocalPath())
+
+    result = []
+    for file in errors:
+        result.append(
+            output_api.PresubmitError(
+                "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
+                file))
+    return result
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index 2eba3ae..799a49fb 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -4057,5 +4057,28 @@
           error.message)
 
 
+class AssertPythonShebangTest(unittest.TestCase):
+    def testError(self):
+        input_api = MockInputApi()
+        input_api.files = [
+            MockFile('ash/test.py', ['#!/usr/bin/python']),
+            MockFile('chrome/test.py', ['#!/usr/bin/python2']),
+            MockFile('third_party/blink/test.py', ['#!/usr/bin/python3']),
+        ]
+        errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
+        self.assertEqual(3, len(errors))
+
+    def testNonError(self):
+        input_api = MockInputApi()
+        input_api.files = [
+            MockFile('chrome/browser/BUILD.gn', ['#!/usr/bin/python']),
+            MockFile('third_party/blink/web_tests/external/test.py',
+                     ['#!/usr/bin/python2']),
+            MockFile('third_party/test/test.py', ['#!/usr/bin/python3']),
+        ]
+        errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
+        self.assertEqual(0, len(errors))
+
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc
index 2e7e6357..0cb2f1c 100644
--- a/android_webview/browser/aw_contents.cc
+++ b/android_webview/browser/aw_contents.cc
@@ -882,8 +882,9 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   content::NavigationEntry* entry =
       web_contents_->GetController().GetLastCommittedEntry();
-  if (!entry || !entry->GetSSL().certificate)
+  if (entry->IsInitialEntry() || !entry->GetSSL().certificate) {
     return ScopedJavaLocalRef<jbyteArray>();
+  }
 
   // Convert the certificate and return it
   base::StringPiece der_string = net::x509_util::CryptoBufferAsStringPiece(
@@ -1031,7 +1032,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Required optimization in WebViewClassic to not save any state if
   // there has been no navigations.
-  if (!web_contents_->GetController().GetEntryCount())
+  if (web_contents_->GetController().GetLastCommittedEntry()->IsInitialEntry())
     return ScopedJavaLocalRef<jbyteArray>();
 
   base::Pickle pickle;
diff --git a/android_webview/browser/state_serializer.cc b/android_webview/browser/state_serializer.cc
index fea444f5..3a172cd 100644
--- a/android_webview/browser/state_serializer.cc
+++ b/android_webview/browser/state_serializer.cc
@@ -47,8 +47,8 @@
   content::NavigationController& controller = web_contents.GetController();
   const int entry_count = controller.GetEntryCount();
   const int selected_entry = controller.GetLastCommittedEntryIndex();
-  DCHECK_GE(entry_count, 0);
-  DCHECK_GE(selected_entry, -1);  // -1 is valid
+  DCHECK_GE(entry_count, 1);
+  DCHECK_GE(selected_entry, 0);
   DCHECK_LT(selected_entry, entry_count);
 
   pickle->WriteInt(entry_count);
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebBackForwardListChromium.java b/android_webview/glue/java/src/com/android/webview/chromium/WebBackForwardListChromium.java
index 8350780..e819055 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebBackForwardListChromium.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebBackForwardListChromium.java
@@ -18,14 +18,22 @@
  */
 @SuppressWarnings("NoSynchronizedMethodCheck")
 public class WebBackForwardListChromium extends WebBackForwardList {
-    private final List<WebHistoryItemChromium> mHistroryItemList;
+    private final List<WebHistoryItemChromium> mHistoryItemList;
     private final int mCurrentIndex;
 
     /* package */ WebBackForwardListChromium(NavigationHistory navHistory) {
+        boolean onInitialEntry =
+                (navHistory.getEntryCount() == 1 && navHistory.getEntryAtIndex(0).isInitialEntry());
+        if (onInitialEntry) {
+            // The initial NavigationEntry should not be exposed in the WebBackForwardList.
+            mCurrentIndex = -1;
+            mHistoryItemList = new ArrayList<WebHistoryItemChromium>(0);
+            return;
+        }
         mCurrentIndex = navHistory.getCurrentEntryIndex();
-        mHistroryItemList = new ArrayList<WebHistoryItemChromium>(navHistory.getEntryCount());
+        mHistoryItemList = new ArrayList<WebHistoryItemChromium>(navHistory.getEntryCount());
         for (int i = 0; i < navHistory.getEntryCount(); ++i) {
-            mHistroryItemList.add(new WebHistoryItemChromium(navHistory.getEntryAtIndex(i)));
+            mHistoryItemList.add(new WebHistoryItemChromium(navHistory.getEntryAtIndex(i)));
         }
     }
 
@@ -57,7 +65,7 @@
         if (index < 0 || index >= getSize()) {
             return null;
         } else {
-            return mHistroryItemList.get(index);
+            return mHistoryItemList.get(index);
         }
     }
 
@@ -66,12 +74,12 @@
      */
     @Override
     public synchronized int getSize() {
-        return mHistroryItemList.size();
+        return mHistoryItemList.size();
     }
 
     // Clone constructor.
     private WebBackForwardListChromium(List<WebHistoryItemChromium> list, int currentIndex) {
-        mHistroryItemList = list;
+        mHistoryItemList = list;
         mCurrentIndex = currentIndex;
     }
 
@@ -82,7 +90,7 @@
     protected synchronized WebBackForwardListChromium clone() {
         List<WebHistoryItemChromium> list = new ArrayList<WebHistoryItemChromium>(getSize());
         for (int i = 0; i < getSize(); ++i) {
-            list.add(mHistroryItemList.get(i).clone());
+            list.add(mHistoryItemList.get(i).clone());
         }
         return new WebBackForwardListChromium(list, mCurrentIndex);
     }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 9ea6cfe9..5ed6a54 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -2622,11 +2622,12 @@
     public String getOriginalUrl() {
         if (TRACE) Log.i(TAG, "%s getOriginalUrl", this);
         if (isDestroyed(WARN)) return null;
-        NavigationHistory history = mNavigationController.getNavigationHistory();
+        NavigationHistory history = getNavigationHistory();
         int currentIndex = history.getCurrentEntryIndex();
-        if (currentIndex >= 0 && currentIndex < history.getEntryCount()) {
+        if (!history.getEntryAtIndex(currentIndex).isInitialEntry()) {
             return history.getEntryAtIndex(currentIndex).getOriginalUrl().getSpec();
         }
+        // When there is no committed navigation, return null.
         return null;
     }
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java
index 3ffc756..c5fd001b 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java
@@ -112,7 +112,7 @@
     @SmallTest
     public void testNavigateOneUrl() throws Throwable {
         NavigationHistory history = getNavigationHistory(mAwContents);
-        Assert.assertEquals(0, history.getEntryCount());
+        Assert.assertEquals(1, history.getEntryCount());
 
         final String pageWithHashTagRedirectUrl = addPageWithHashTagRedirectToServer(mWebServer);
         AwActivityTestRule.enableJavaScriptOnUiThread(mAwContents);
@@ -134,7 +134,7 @@
     @SmallTest
     public void testNavigateBackForwardWithIntervention() throws Throwable {
         NavigationHistory history = getNavigationHistory(mAwContents);
-        Assert.assertEquals(0, history.getEntryCount());
+        Assert.assertEquals(1, history.getEntryCount());
 
         final String page1Url = addPage1ToServer(mWebServer);
         final String pageWithSameDocumentUrl = addPageWithSameDocumentToServer(mWebServer);
@@ -161,7 +161,7 @@
     @SmallTest
     public void testNavigateTwoUrls() throws Throwable {
         NavigationHistory list = getNavigationHistory(mAwContents);
-        Assert.assertEquals(0, list.getEntryCount());
+        Assert.assertEquals(1, list.getEntryCount());
 
         final TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
                 mContentsClient.getOnPageFinishedHelper();
@@ -199,7 +199,7 @@
         final TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
                 mContentsClient.getOnPageFinishedHelper();
         NavigationHistory list = getNavigationHistory(mAwContents);
-        Assert.assertEquals(0, list.getEntryCount());
+        Assert.assertEquals(1, list.getEntryCount());
 
         final String page1Url = addPage1ToServer(mWebServer);
         final String page2Url = addPage2ToServer(mWebServer);
@@ -238,7 +238,7 @@
                 CommonResources.FAVICON_STATIC_HTML, null);
 
         NavigationHistory list = getNavigationHistory(mAwContents);
-        Assert.assertEquals(0, list.getEntryCount());
+        Assert.assertEquals(1, list.getEntryCount());
         mActivityTestRule.getAwSettingsOnUiThread(mAwContents).setImagesEnabled(true);
         int faviconLoadCount = mContentsClient.getFaviconHelper().getCallCount();
         mActivityTestRule.loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), url);
@@ -256,7 +256,7 @@
         final TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
                 mContentsClient.getOnPageFinishedHelper();
         NavigationHistory list = getNavigationHistory(mAwContents);
-        Assert.assertEquals(0, list.getEntryCount());
+        Assert.assertEquals(1, list.getEntryCount());
 
         final String page1Url = addPage1ToServer(mWebServer);
         final String page2Url = addPage2ToServer(mWebServer);
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/SaveRestoreStateTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/SaveRestoreStateTest.java
index 095f473..b83f7df7 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/SaveRestoreStateTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/SaveRestoreStateTest.java
@@ -147,6 +147,11 @@
     public void testSaveRestoreStateWithHistoryItemList() throws Throwable {
         setServerResponseAndLoad(mVars, NUM_NAVIGATIONS);
         TestVars restoredVars = saveAndRestoreStateOnUiThread(mVars);
+        mActivityTestRule.pollUiThread(
+                ()
+                        -> TITLES[NUM_NAVIGATIONS - 1].equals(restoredVars.awContents.getTitle())
+                        && TITLES[NUM_NAVIGATIONS - 1].equals(
+                                restoredVars.contentsClient.getUpdatedTitle()));
         checkHistoryItemList(restoredVars);
     }
 
diff --git a/ash/components/arc/bluetooth/bluetooth_mojom_traits.h b/ash/components/arc/bluetooth/bluetooth_mojom_traits.h
index 1f9a0a7..90d8573 100644
--- a/ash/components/arc/bluetooth/bluetooth_mojom_traits.h
+++ b/ash/components/arc/bluetooth/bluetooth_mojom_traits.h
@@ -8,7 +8,7 @@
 #include <memory>
 #include <vector>
 
-#include "components/arc/mojom/bluetooth.mojom.h"
+#include "ash/components/arc/mojom/bluetooth.mojom.h"
 #include "device/bluetooth/bluetooth_advertisement.h"
 #include "device/bluetooth/bluetooth_common.h"
 #include "device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h"
diff --git a/ash/components/arc/bluetooth/bluetooth_type_converters.h b/ash/components/arc/bluetooth/bluetooth_type_converters.h
index fe7a7142..17024fe8 100644
--- a/ash/components/arc/bluetooth/bluetooth_type_converters.h
+++ b/ash/components/arc/bluetooth/bluetooth_type_converters.h
@@ -11,7 +11,7 @@
 #include <string>
 #include <utility>
 
-#include "components/arc/mojom/bluetooth.mojom.h"
+#include "ash/components/arc/mojom/bluetooth.mojom.h"
 #include "device/bluetooth/bluetooth_gatt_service.h"
 #include "device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h"
 #include "device/bluetooth/bluez/bluetooth_service_record_bluez.h"
diff --git a/ash/components/arc/camera/arc_camera_bridge.h b/ash/components/arc/camera/arc_camera_bridge.h
index 669f452a..133dfb4 100644
--- a/ash/components/arc/camera/arc_camera_bridge.h
+++ b/ash/components/arc/camera/arc_camera_bridge.h
@@ -8,7 +8,7 @@
 #include <map>
 #include <memory>
 
-#include "components/arc/mojom/camera.mojom.h"
+#include "ash/components/arc/mojom/camera.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 
diff --git a/ash/components/arc/clipboard/arc_clipboard_bridge.h b/ash/components/arc/clipboard/arc_clipboard_bridge.h
index 03e0b1c1..676839af 100644
--- a/ash/components/arc/clipboard/arc_clipboard_bridge.h
+++ b/ash/components/arc/clipboard/arc_clipboard_bridge.h
@@ -5,8 +5,8 @@
 #ifndef ASH_COMPONENTS_ARC_CLIPBOARD_ARC_CLIPBOARD_BRIDGE_H_
 #define ASH_COMPONENTS_ARC_CLIPBOARD_ARC_CLIPBOARD_BRIDGE_H_
 
+#include "ash/components/arc/mojom/clipboard.mojom.h"
 #include "base/threading/thread_checker.h"
-#include "components/arc/mojom/clipboard.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "ui/base/clipboard/clipboard_observer.h"
 
diff --git a/ash/components/arc/clipboard/arc_clipboard_bridge_unittest.cc b/ash/components/arc/clipboard/arc_clipboard_bridge_unittest.cc
index 2e953082..ee89191 100644
--- a/ash/components/arc/clipboard/arc_clipboard_bridge_unittest.cc
+++ b/ash/components/arc/clipboard/arc_clipboard_bridge_unittest.cc
@@ -8,12 +8,12 @@
 #include <utility>
 #include <vector>
 
+#include "ash/components/arc/mojom/clipboard.mojom.h"
 #include "ash/components/arc/session/arc_bridge_service.h"
 #include "ash/components/arc/test/connection_holder_util.h"
 #include "ash/components/arc/test/fake_clipboard_instance.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/mock_callback.h"
-#include "components/arc/mojom/clipboard.mojom.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/clipboard/clipboard.h"
diff --git a/ash/components/arc/crash_collector/arc_crash_collector_bridge.h b/ash/components/arc/crash_collector/arc_crash_collector_bridge.h
index 2abde18..be23cad0 100644
--- a/ash/components/arc/crash_collector/arc_crash_collector_bridge.h
+++ b/ash/components/arc/crash_collector/arc_crash_collector_bridge.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "components/arc/mojom/crash_collector.mojom.h"
+#include "ash/components/arc/mojom/crash_collector.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "mojo/public/mojom/base/time.mojom.h"
 
diff --git a/ash/components/arc/dark_theme/arc_dark_theme_bridge.h b/ash/components/arc/dark_theme/arc_dark_theme_bridge.h
index 7783366..36c7541 100644
--- a/ash/components/arc/dark_theme/arc_dark_theme_bridge.h
+++ b/ash/components/arc/dark_theme/arc_dark_theme_bridge.h
@@ -5,10 +5,10 @@
 #ifndef ASH_COMPONENTS_ARC_DARK_THEME_ARC_DARK_THEME_BRIDGE_H_
 #define ASH_COMPONENTS_ARC_DARK_THEME_ARC_DARK_THEME_BRIDGE_H_
 
+#include "ash/components/arc/mojom/dark_theme.mojom.h"
 #include "ash/components/arc/session/connection_observer.h"
 #include "ash/public/cpp/style/color_mode_observer.h"
 #include "base/threading/thread_checker.h"
-#include "components/arc/mojom/dark_theme.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/session_manager/core/session_manager_observer.h"
 
diff --git a/ash/components/arc/disk_quota/arc_disk_quota_bridge.h b/ash/components/arc/disk_quota/arc_disk_quota_bridge.h
index a03ab239..cff9060 100644
--- a/ash/components/arc/disk_quota/arc_disk_quota_bridge.h
+++ b/ash/components/arc/disk_quota/arc_disk_quota_bridge.h
@@ -5,10 +5,10 @@
 #ifndef ASH_COMPONENTS_ARC_DISK_QUOTA_ARC_DISK_QUOTA_BRIDGE_H_
 #define ASH_COMPONENTS_ARC_DISK_QUOTA_ARC_DISK_QUOTA_BRIDGE_H_
 
+#include "ash/components/arc/mojom/disk_quota.mojom.h"
 #include "base/files/file_path.h"
 #include "chromeos/dbus/cryptohome/UserDataAuth.pb.h"
 #include "components/account_id/account_id.h"
-#include "components/arc/mojom/disk_quota.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "third_party/cros_system_api/dbus/cryptohome/dbus-constants.h"
 
diff --git a/ash/components/arc/mojom/BUILD.gn b/ash/components/arc/mojom/BUILD.gn
index 6dfca9c..45db74aa 100644
--- a/ash/components/arc/mojom/BUILD.gn
+++ b/ash/components/arc/mojom/BUILD.gn
@@ -20,6 +20,17 @@
       "arc_bridge.mojom",
       "audio.mojom",
       "auth.mojom",
+      "backup_settings.mojom",
+      "bluetooth.mojom",
+      "boot_phase_monitor.mojom",
+      "camera.mojom",
+      "cast_receiver.mojom",
+      "cert_store.mojom",
+      "clipboard.mojom",
+      "crash_collector.mojom",
+      "dark_theme.mojom",
+      "digital_goods.mojom",
+      "disk_quota.mojom",
     ]
 
     public_deps = [
@@ -42,6 +53,44 @@
       "//ui/gfx/geometry/mojom",
       "//url/mojom:url_mojom_gurl",
     ]
+
+    cpp_typemaps = [
+      {
+        types = [
+          {
+            mojom = "arc.mojom.BluetoothDeviceType"
+            cpp = "::device::BluetoothTransport"
+          },
+          {
+            mojom = "arc.mojom.BluetoothSdpAttributeType"
+            cpp = "::bluez::BluetoothServiceAttributeValueBlueZ::Type"
+          },
+          {
+            mojom = "arc.mojom.BluetoothUUID"
+            cpp = "::device::BluetoothUUID"
+          },
+          {
+            mojom = "arc.mojom.BluetoothAdvertisement"
+            cpp = "::std::unique_ptr<::device::BluetoothAdvertisement::Data>"
+            move_only = true
+          },
+        ]
+        traits_headers = [
+          "//device/bluetooth/bluetooth_advertisement.h",
+          "//device/bluetooth/bluetooth_common.h",
+          "//device/bluetooth/public/cpp/bluetooth_uuid.h",
+          "//device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h",
+        ]
+        traits_private_headers =
+            [ "//ash/components/arc/bluetooth/bluetooth_mojom_traits.h" ]
+        traits_sources =
+            [ "//ash/components/arc/bluetooth/bluetooth_mojom_traits.cc" ]
+        traits_public_deps = [
+          "//device/bluetooth",
+          "//device/bluetooth/public/cpp",
+        ]
+      },
+    ]
   }
 
   # Media related mojo interfaces. These are used by
diff --git a/ash/components/arc/mojom/arc_bridge.mojom b/ash/components/arc/mojom/arc_bridge.mojom
index d53d7640..67dfc041 100644
--- a/ash/components/arc/mojom/arc_bridge.mojom
+++ b/ash/components/arc/mojom/arc_bridge.mojom
@@ -9,22 +9,22 @@
 import "ash/components/arc/mojom/appfuse.mojom";
 import "ash/components/arc/mojom/audio.mojom";
 import "ash/components/arc/mojom/auth.mojom";
+import "ash/components/arc/mojom/backup_settings.mojom";
+import "ash/components/arc/mojom/bluetooth.mojom";
+import "ash/components/arc/mojom/boot_phase_monitor.mojom";
+import "ash/components/arc/mojom/camera.mojom";
+import "ash/components/arc/mojom/cast_receiver.mojom";
+import "ash/components/arc/mojom/cert_store.mojom";
+import "ash/components/arc/mojom/clipboard.mojom";
+import "ash/components/arc/mojom/crash_collector.mojom";
+import "ash/components/arc/mojom/dark_theme.mojom";
+import "ash/components/arc/mojom/digital_goods.mojom";
+import "ash/components/arc/mojom/disk_quota.mojom";
 import "ash/components/arc/mojom/notifications.mojom";
 import "ash/components/arc/mojom/oemcrypto.mojom";
 import "components/arc/mojom/app.mojom";
 import "components/arc/mojom/app_permissions.mojom";
-import "components/arc/mojom/backup_settings.mojom";
-import "components/arc/mojom/bluetooth.mojom";
-import "components/arc/mojom/boot_phase_monitor.mojom";
-import "components/arc/mojom/camera.mojom";
-import "components/arc/mojom/cast_receiver.mojom";
-import "components/arc/mojom/cert_store.mojom";
-import "components/arc/mojom/clipboard.mojom";
 import "components/arc/mojom/compatibility_mode.mojom";
-import "components/arc/mojom/crash_collector.mojom";
-import "components/arc/mojom/dark_theme.mojom";
-import "components/arc/mojom/digital_goods.mojom";
-import "components/arc/mojom/disk_quota.mojom";
 import "components/arc/mojom/enterprise_reporting.mojom";
 import "components/arc/mojom/file_system.mojom";
 import "components/arc/mojom/iio_sensor.mojom";
diff --git a/components/arc/mojom/backup_settings.mojom b/ash/components/arc/mojom/backup_settings.mojom
similarity index 100%
rename from components/arc/mojom/backup_settings.mojom
rename to ash/components/arc/mojom/backup_settings.mojom
diff --git a/components/arc/mojom/bluetooth.mojom b/ash/components/arc/mojom/bluetooth.mojom
similarity index 100%
rename from components/arc/mojom/bluetooth.mojom
rename to ash/components/arc/mojom/bluetooth.mojom
diff --git a/components/arc/mojom/boot_phase_monitor.mojom b/ash/components/arc/mojom/boot_phase_monitor.mojom
similarity index 100%
rename from components/arc/mojom/boot_phase_monitor.mojom
rename to ash/components/arc/mojom/boot_phase_monitor.mojom
diff --git a/components/arc/mojom/camera.mojom b/ash/components/arc/mojom/camera.mojom
similarity index 100%
rename from components/arc/mojom/camera.mojom
rename to ash/components/arc/mojom/camera.mojom
diff --git a/components/arc/mojom/cast_receiver.mojom b/ash/components/arc/mojom/cast_receiver.mojom
similarity index 100%
rename from components/arc/mojom/cast_receiver.mojom
rename to ash/components/arc/mojom/cast_receiver.mojom
diff --git a/components/arc/mojom/cert_store.mojom b/ash/components/arc/mojom/cert_store.mojom
similarity index 100%
rename from components/arc/mojom/cert_store.mojom
rename to ash/components/arc/mojom/cert_store.mojom
diff --git a/components/arc/mojom/clipboard.mojom b/ash/components/arc/mojom/clipboard.mojom
similarity index 100%
rename from components/arc/mojom/clipboard.mojom
rename to ash/components/arc/mojom/clipboard.mojom
diff --git a/components/arc/mojom/crash_collector.mojom b/ash/components/arc/mojom/crash_collector.mojom
similarity index 100%
rename from components/arc/mojom/crash_collector.mojom
rename to ash/components/arc/mojom/crash_collector.mojom
diff --git a/components/arc/mojom/dark_theme.mojom b/ash/components/arc/mojom/dark_theme.mojom
similarity index 100%
rename from components/arc/mojom/dark_theme.mojom
rename to ash/components/arc/mojom/dark_theme.mojom
diff --git a/components/arc/mojom/digital_goods.mojom b/ash/components/arc/mojom/digital_goods.mojom
similarity index 100%
rename from components/arc/mojom/digital_goods.mojom
rename to ash/components/arc/mojom/digital_goods.mojom
diff --git a/components/arc/mojom/disk_quota.mojom b/ash/components/arc/mojom/disk_quota.mojom
similarity index 100%
rename from components/arc/mojom/disk_quota.mojom
rename to ash/components/arc/mojom/disk_quota.mojom
diff --git a/ash/components/arc/pay/arc_digital_goods_bridge.h b/ash/components/arc/pay/arc_digital_goods_bridge.h
index ece2e53..b19a033 100644
--- a/ash/components/arc/pay/arc_digital_goods_bridge.h
+++ b/ash/components/arc/pay/arc_digital_goods_bridge.h
@@ -8,7 +8,7 @@
 #include <string>
 #include <vector>
 
-#include "components/arc/mojom/digital_goods.mojom.h"
+#include "ash/components/arc/mojom/digital_goods.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 namespace content {
diff --git a/ash/components/arc/session/arc_bridge_host_impl.cc b/ash/components/arc/session/arc_bridge_host_impl.cc
index 9250e90..19ab5aa 100644
--- a/ash/components/arc/session/arc_bridge_host_impl.cc
+++ b/ash/components/arc/session/arc_bridge_host_impl.cc
@@ -12,6 +12,17 @@
 #include "ash/components/arc/mojom/appfuse.mojom.h"
 #include "ash/components/arc/mojom/audio.mojom.h"
 #include "ash/components/arc/mojom/auth.mojom.h"
+#include "ash/components/arc/mojom/backup_settings.mojom.h"
+#include "ash/components/arc/mojom/bluetooth.mojom.h"
+#include "ash/components/arc/mojom/boot_phase_monitor.mojom.h"
+#include "ash/components/arc/mojom/camera.mojom.h"
+#include "ash/components/arc/mojom/cast_receiver.mojom.h"
+#include "ash/components/arc/mojom/cert_store.mojom.h"
+#include "ash/components/arc/mojom/clipboard.mojom.h"
+#include "ash/components/arc/mojom/crash_collector.mojom.h"
+#include "ash/components/arc/mojom/dark_theme.mojom.h"
+#include "ash/components/arc/mojom/digital_goods.mojom.h"
+#include "ash/components/arc/mojom/disk_quota.mojom.h"
 #include "ash/components/arc/mojom/notifications.mojom.h"
 #include "ash/components/arc/mojom/oemcrypto.mojom.h"
 #include "ash/components/arc/mojom/video.mojom.h"
@@ -24,18 +35,7 @@
 #include "chromeos/components/sensors/mojom/cros_sensor_service.mojom.h"
 #include "components/arc/mojom/app.mojom.h"
 #include "components/arc/mojom/app_permissions.mojom.h"
-#include "components/arc/mojom/backup_settings.mojom.h"
-#include "components/arc/mojom/bluetooth.mojom.h"
-#include "components/arc/mojom/boot_phase_monitor.mojom.h"
-#include "components/arc/mojom/camera.mojom.h"
-#include "components/arc/mojom/cast_receiver.mojom.h"
-#include "components/arc/mojom/cert_store.mojom.h"
-#include "components/arc/mojom/clipboard.mojom.h"
 #include "components/arc/mojom/compatibility_mode.mojom.h"
-#include "components/arc/mojom/crash_collector.mojom.h"
-#include "components/arc/mojom/dark_theme.mojom.h"
-#include "components/arc/mojom/digital_goods.mojom.h"
-#include "components/arc/mojom/disk_quota.mojom.h"
 #include "components/arc/mojom/enterprise_reporting.mojom.h"
 #include "components/arc/mojom/file_system.mojom.h"
 #include "components/arc/mojom/iio_sensor.mojom.h"
diff --git a/ash/components/arc/session/arc_bridge_service.cc b/ash/components/arc/session/arc_bridge_service.cc
index 8ee077634..e5752aa 100644
--- a/ash/components/arc/session/arc_bridge_service.cc
+++ b/ash/components/arc/session/arc_bridge_service.cc
@@ -11,20 +11,20 @@
 #include "ash/components/arc/mojom/arc_bridge.mojom.h"
 #include "ash/components/arc/mojom/audio.mojom.h"
 #include "ash/components/arc/mojom/auth.mojom.h"
+#include "ash/components/arc/mojom/backup_settings.mojom.h"
+#include "ash/components/arc/mojom/bluetooth.mojom.h"
+#include "ash/components/arc/mojom/boot_phase_monitor.mojom.h"
+#include "ash/components/arc/mojom/camera.mojom.h"
+#include "ash/components/arc/mojom/cast_receiver.mojom.h"
+#include "ash/components/arc/mojom/cert_store.mojom.h"
+#include "ash/components/arc/mojom/clipboard.mojom.h"
+#include "ash/components/arc/mojom/crash_collector.mojom.h"
+#include "ash/components/arc/mojom/digital_goods.mojom.h"
+#include "ash/components/arc/mojom/disk_quota.mojom.h"
 #include "ash/components/arc/mojom/oemcrypto.mojom.h"
 #include "ash/components/arc/mojom/video.mojom.h"
 #include "components/arc/mojom/app.mojom.h"
 #include "components/arc/mojom/app_permissions.mojom.h"
-#include "components/arc/mojom/backup_settings.mojom.h"
-#include "components/arc/mojom/bluetooth.mojom.h"
-#include "components/arc/mojom/boot_phase_monitor.mojom.h"
-#include "components/arc/mojom/camera.mojom.h"
-#include "components/arc/mojom/cast_receiver.mojom.h"
-#include "components/arc/mojom/cert_store.mojom.h"
-#include "components/arc/mojom/clipboard.mojom.h"
-#include "components/arc/mojom/crash_collector.mojom.h"
-#include "components/arc/mojom/digital_goods.mojom.h"
-#include "components/arc/mojom/disk_quota.mojom.h"
 #include "components/arc/mojom/enterprise_reporting.mojom.h"
 #include "components/arc/mojom/file_system.mojom.h"
 #include "components/arc/mojom/iio_sensor.mojom.h"
diff --git a/ash/components/arc/test/fake_arc_bridge_host.cc b/ash/components/arc/test/fake_arc_bridge_host.cc
index 5792fb9f..60079af 100644
--- a/ash/components/arc/test/fake_arc_bridge_host.cc
+++ b/ash/components/arc/test/fake_arc_bridge_host.cc
@@ -10,22 +10,22 @@
 #include "ash/components/arc/mojom/arc_bridge.mojom.h"
 #include "ash/components/arc/mojom/audio.mojom.h"
 #include "ash/components/arc/mojom/auth.mojom.h"
+#include "ash/components/arc/mojom/backup_settings.mojom.h"
+#include "ash/components/arc/mojom/bluetooth.mojom.h"
+#include "ash/components/arc/mojom/boot_phase_monitor.mojom.h"
+#include "ash/components/arc/mojom/camera.mojom.h"
+#include "ash/components/arc/mojom/cast_receiver.mojom.h"
+#include "ash/components/arc/mojom/cert_store.mojom.h"
+#include "ash/components/arc/mojom/clipboard.mojom.h"
+#include "ash/components/arc/mojom/crash_collector.mojom.h"
+#include "ash/components/arc/mojom/dark_theme.mojom.h"
+#include "ash/components/arc/mojom/disk_quota.mojom.h"
 #include "ash/components/arc/mojom/notifications.mojom.h"
 #include "ash/components/arc/mojom/oemcrypto.mojom.h"
 #include "ash/components/arc/mojom/video.mojom.h"
 #include "components/arc/mojom/app.mojom.h"
 #include "components/arc/mojom/app_permissions.mojom.h"
-#include "components/arc/mojom/backup_settings.mojom.h"
-#include "components/arc/mojom/bluetooth.mojom.h"
-#include "components/arc/mojom/boot_phase_monitor.mojom.h"
-#include "components/arc/mojom/camera.mojom.h"
-#include "components/arc/mojom/cast_receiver.mojom.h"
-#include "components/arc/mojom/cert_store.mojom.h"
-#include "components/arc/mojom/clipboard.mojom.h"
 #include "components/arc/mojom/compatibility_mode.mojom.h"
-#include "components/arc/mojom/crash_collector.mojom.h"
-#include "components/arc/mojom/dark_theme.mojom.h"
-#include "components/arc/mojom/disk_quota.mojom.h"
 #include "components/arc/mojom/enterprise_reporting.mojom.h"
 #include "components/arc/mojom/file_system.mojom.h"
 #include "components/arc/mojom/ime.mojom.h"
diff --git a/ash/components/arc/test/fake_backup_settings_instance.h b/ash/components/arc/test/fake_backup_settings_instance.h
index bb08216..53595d0 100644
--- a/ash/components/arc/test/fake_backup_settings_instance.h
+++ b/ash/components/arc/test/fake_backup_settings_instance.h
@@ -5,7 +5,7 @@
 #ifndef ASH_COMPONENTS_ARC_TEST_FAKE_BACKUP_SETTINGS_INSTANCE_H_
 #define ASH_COMPONENTS_ARC_TEST_FAKE_BACKUP_SETTINGS_INSTANCE_H_
 
-#include "components/arc/mojom/backup_settings.mojom.h"
+#include "ash/components/arc/mojom/backup_settings.mojom.h"
 
 namespace arc {
 
diff --git a/ash/components/arc/test/fake_bluetooth_instance.h b/ash/components/arc/test/fake_bluetooth_instance.h
index d6c55102..ed5ac59 100644
--- a/ash/components/arc/test/fake_bluetooth_instance.h
+++ b/ash/components/arc/test/fake_bluetooth_instance.h
@@ -8,7 +8,7 @@
 #include <memory>
 #include <vector>
 
-#include "components/arc/mojom/bluetooth.mojom.h"
+#include "ash/components/arc/mojom/bluetooth.mojom.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
diff --git a/ash/components/arc/test/fake_cast_receiver_instance.h b/ash/components/arc/test/fake_cast_receiver_instance.h
index 6351759..c7cc950 100644
--- a/ash/components/arc/test/fake_cast_receiver_instance.h
+++ b/ash/components/arc/test/fake_cast_receiver_instance.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "components/arc/mojom/cast_receiver.mojom.h"
+#include "ash/components/arc/mojom/cast_receiver.mojom.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace arc {
diff --git a/ash/components/arc/test/fake_clipboard_instance.h b/ash/components/arc/test/fake_clipboard_instance.h
index bbba9087..2f52b8b 100644
--- a/ash/components/arc/test/fake_clipboard_instance.h
+++ b/ash/components/arc/test/fake_clipboard_instance.h
@@ -5,7 +5,7 @@
 #ifndef ASH_COMPONENTS_ARC_TEST_FAKE_CLIPBOARD_INSTANCE_H_
 #define ASH_COMPONENTS_ARC_TEST_FAKE_CLIPBOARD_INSTANCE_H_
 
-#include "components/arc/mojom/clipboard.mojom.h"
+#include "ash/components/arc/mojom/clipboard.mojom.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 
 namespace arc {
diff --git a/ash/components/arc/test/fake_dark_theme_instance.h b/ash/components/arc/test/fake_dark_theme_instance.h
index 9059bb9..90a67378 100644
--- a/ash/components/arc/test/fake_dark_theme_instance.h
+++ b/ash/components/arc/test/fake_dark_theme_instance.h
@@ -5,7 +5,7 @@
 #ifndef ASH_COMPONENTS_ARC_TEST_FAKE_DARK_THEME_INSTANCE_H_
 #define ASH_COMPONENTS_ARC_TEST_FAKE_DARK_THEME_INSTANCE_H_
 
-#include "components/arc/mojom/dark_theme.mojom.h"
+#include "ash/components/arc/mojom/dark_theme.mojom.h"
 
 namespace arc {
 
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index c856acd..d04e03e 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -229,7 +229,7 @@
 // Enable or disable manual crop document page to ChromeOS camera app. The flag
 // will be deprecated after feature is fully launched: crbug.com/1259731.
 const base::Feature kCameraAppDocumentManualCrop{
-    "CameraAppDocumentManualCrop", base::FEATURE_DISABLED_BY_DEFAULT};
+    "CameraAppDocumentManualCrop", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Controls whether the camera privacy switch toasts and notification should be
 // displayed.
@@ -721,6 +721,11 @@
 const base::Feature kImeOptionsInSettings{"ImeOptionsInSettings",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
+// If enabled, used to configure the heuristic rules for some advanced IME
+// features (e.g. auto-correct).
+const base::Feature kImeRuleConfig{"ImeRuleConfig",
+                                   base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enable or disable system emoji picker.
 const base::Feature kImeSystemEmojiPicker{"SystemEmojiPicker",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 63e796b..e13eb5c 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -274,6 +274,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kImeMozcProto;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kImeOptionsInSettings;
+COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kImeRuleConfig;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kImeSystemEmojiPicker;
 COMPONENT_EXPORT(ASH_CONSTANTS)
diff --git a/ash/public/cpp/update_types.h b/ash/public/cpp/update_types.h
index 649505b0..9621692 100644
--- a/ash/public/cpp/update_types.h
+++ b/ash/public/cpp/update_types.h
@@ -42,6 +42,11 @@
                              // `rounded_time_until_reboot_required`.
   } requirement_type = kNone;
 
+  enum PolicySource {
+    kUser,    // Relaunch notifications are triggered by a user policy.
+    kDevice,  // Relaunch notifications are triggered by a device policy..
+  } policy_source = kUser;
+
   // The remaining time until the device will restart itself, rounded to the
   // nearest day, hour, minute, or second; depending on how far into the future
   // it is.
diff --git a/ash/services/ime/decoder/system_engine_unittest.cc b/ash/services/ime/decoder/system_engine_unittest.cc
index b7fe2dd..bd988797 100644
--- a/ash/services/ime/decoder/system_engine_unittest.cc
+++ b/ash/services/ime/decoder/system_engine_unittest.cc
@@ -95,7 +95,8 @@
   MOCK_METHOD(void,
               SetComposition,
               (const std::u16string& text,
-               std::vector<mojom::CompositionSpanPtr> spans),
+               std::vector<mojom::CompositionSpanPtr> spans,
+               uint32_t new_cursor_position),
               (override));
   MOCK_METHOD(void,
               SetCompositionRange,
diff --git a/ash/services/ime/ime_service_unittest.cc b/ash/services/ime/ime_service_unittest.cc
index fdb5c926..6063498 100644
--- a/ash/services/ime/ime_service_unittest.cc
+++ b/ash/services/ime/ime_service_unittest.cc
@@ -122,7 +122,8 @@
     last_commit = text;
   }
   void SetComposition(const std::u16string& text,
-                      std::vector<mojom::CompositionSpanPtr> spans) override {
+                      std::vector<mojom::CompositionSpanPtr> spans,
+                      uint32_t new_cursor_position) override {
     last_composition = text;
   }
   void SetCompositionRange(uint32_t start_index, uint32_t end_index) override {}
@@ -155,7 +156,8 @@
   void CommitText(const std::u16string& text,
                   mojom::CommitTextCursorBehavior cursor_behavior) override {}
   void SetComposition(const std::u16string& text,
-                      std::vector<mojom::CompositionSpanPtr> spans) override {}
+                      std::vector<mojom::CompositionSpanPtr> spans,
+                      uint32_t new_cursor_position) override {}
   void SetCompositionRange(uint32_t start_index, uint32_t end_index) override {}
   void FinishComposition() override {}
   void DeleteSurroundingText(uint32_t num_before_cursor,
diff --git a/ash/services/ime/public/mojom/input_method_host.mojom b/ash/services/ime/public/mojom/input_method_host.mojom
index 19fe73b4..e93e17a8 100644
--- a/ash/services/ime/public/mojom/input_method_host.mojom
+++ b/ash/services/ime/public/mojom/input_method_host.mojom
@@ -6,7 +6,7 @@
 // the Chromium repo. This file should be updated first, before syncing in the
 // other repos.
 
-// Next MinVersion: 5
+// Next MinVersion: 6
 
 module chromeos.ime.mojom;
 
@@ -244,9 +244,20 @@
   // Asks the focused input field to set composition with `text`.
   // Replaces the current composition if there is one. Otherwise, start a
   // new composition at the current cursor position, deleting any text in the
-  // current selection if any. The cursor is moved to the end of `text`.
+  // current selection if any.
+  //
   // `spans` is used to style `text`.
-  SetComposition@1(mojo_base.mojom.String16 text, array<CompositionSpan> spans);
+  //
+  // The cursor then moves based on `new_cursor_position`, which is the relative
+  // UTF-16 offset of the new cursor position from the front of `text`.
+  // For example, if `new_cursor_position` is 3, then the cursor is placed
+  // between `text[3]` and `text[4]`. A `new_cursor_position` of 0 places the
+  // cursor immediately before `text`, and a value of `text.length()` places the
+  // cursor immediately after `text`.
+  // If `new_cursor_position > text.length()`, then this is a no-op.
+  SetComposition@1(mojo_base.mojom.String16 text,
+                   array<CompositionSpan> spans,
+                   [MinVersion=5] uint32 new_cursor_position);
 
   // Asks the focused input field to mark the range of text spanned by
   // `start_index` and `end_index` as the current composition, where index 0
diff --git a/ash/services/ime/rule_based_engine.cc b/ash/services/ime/rule_based_engine.cc
index 846894b..0d5c35b 100644
--- a/ash/services/ime/rule_based_engine.cc
+++ b/ash/services/ime/rule_based_engine.cc
@@ -60,7 +60,9 @@
     std::vector<mojom::CompositionSpanPtr> spans;
     spans.push_back(mojom::CompositionSpan::New(
         0, text.length(), mojom::CompositionSpanStyle::kDefault));
-    host->SetComposition(std::move(text), std::move(spans));
+    const int new_cursor_position = text.length();
+    host->SetComposition(std::move(text), std::move(spans),
+                         new_cursor_position);
   }
   return result.key_handled ? mojom::KeyEventResult::kConsumedByIme
                             : mojom::KeyEventResult::kNeedsHandlingBySystem;
diff --git a/ash/system/update/update_notification_controller.cc b/ash/system/update/update_notification_controller.cc
index 2350208..9b95dc6e3 100644
--- a/ash/system/update/update_notification_controller.cc
+++ b/ash/system/update/update_notification_controller.cc
@@ -46,11 +46,20 @@
   return false;
 }
 
-std::u16string GetEnterpriseDomainManager() {
-  return base::UTF8ToUTF16(Shell::Get()
-                               ->system_tray_model()
-                               ->enterprise_domain()
-                               ->enterprise_domain_manager());
+std::u16string GetDomainManager(
+    RelaunchNotificationState::PolicySource policy_source) {
+  EnterpriseDomainModel* enterprise_domain =
+      Shell::Get()->system_tray_model()->enterprise_domain();
+  std::string domain_manager;
+  switch (policy_source) {
+    case RelaunchNotificationState::kDevice:
+      domain_manager = enterprise_domain->enterprise_domain_manager();
+      break;
+    case RelaunchNotificationState::kUser:
+      domain_manager = enterprise_domain->account_domain_manager();
+      break;
+  }
+  return base::UTF8ToUTF16(domain_manager);
 }
 
 }  // namespace
@@ -211,10 +220,11 @@
   }
 
   std::u16string update_text;
-  if (body_message_id.has_value() &&
+  std::u16string domain_manager =
+      GetDomainManager(model_->relaunch_notification_state().policy_source);
+  if (body_message_id.has_value() && !domain_manager.empty() &&
       model_->update_type() == UpdateType::kSystem) {
-    update_text = l10n_util::GetStringFUTF16(*body_message_id,
-                                             GetEnterpriseDomainManager(),
+    update_text = l10n_util::GetStringFUTF16(*body_message_id, domain_manager,
                                              ui::GetChromeOSDeviceName());
   } else {
     update_text = l10n_util::GetStringFUTF16(
diff --git a/ash/system/update/update_notification_controller_unittest.cc b/ash/system/update/update_notification_controller_unittest.cc
index 4c843fe..3857db0 100644
--- a/ash/system/update/update_notification_controller_unittest.cc
+++ b/ash/system/update/update_notification_controller_unittest.cc
@@ -34,7 +34,8 @@
 namespace {
 
 const char kNotificationId[] = "chrome://update";
-const char* kDomain = "google.com";
+const char* kDomain = "example.com";
+const char* kDeviceDomain = "example.org";
 
 // Waits for the notification to be added. Needed because the controller
 // posts a task to check for slow boot request before showing the
@@ -84,10 +85,10 @@
     system_app_name_ =
         l10n_util::GetStringUTF16(IDS_ASH_MESSAGE_CENTER_SYSTEM_APP_NAME);
 
-    Shell::Get()
-        ->system_tray_model()
-        ->enterprise_domain()
-        ->SetEnterpriseDomainInfo(kDomain, false);
+    EnterpriseDomainModel* enterprise_domain =
+        Shell::Get()->system_tray_model()->enterprise_domain();
+    enterprise_domain->SetEnterpriseAccountDomainInfo(kDomain);
+    enterprise_domain->SetEnterpriseDomainInfo(kDeviceDomain, false);
   }
 
  protected:
@@ -490,6 +491,47 @@
             GetNotificationButton(0));
 }
 
+TEST_F(UpdateNotificationControllerTest,
+       SetUpdateNotificationRequiredWithDevicePolicySource) {
+  ShowDefaultUpdateNotification();
+  AddNotificationWaiter waiter;
+
+  Shell::Get()->system_tray_model()->SetRelaunchNotificationState({
+      .requirement_type = RelaunchNotificationState::kRequired,
+      .policy_source = RelaunchNotificationState::kDevice,
+  });
+
+  waiter.Wait();
+
+  const std::string expected_notification_body = l10n_util::GetStringFUTF8(
+      IDS_RELAUNCH_REQUIRED_BODY, base::ASCIIToUTF16(kDeviceDomain),
+      ui::GetChromeOSDeviceName());
+
+  ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(expected_notification_body, GetNotificationMessage());
+}
+
+TEST_F(UpdateNotificationControllerTest,
+       SetUpdateNotificationWithoutAccountDomainManager) {
+  ShowDefaultUpdateNotification();
+  Shell::Get()
+      ->system_tray_model()
+      ->enterprise_domain()
+      ->SetEnterpriseAccountDomainInfo(std::string());
+  AddNotificationWaiter waiter;
+
+  Shell::Get()->system_tray_model()->SetRelaunchNotificationState(
+      {.requirement_type = RelaunchNotificationState::kRequired});
+
+  waiter.Wait();
+
+  const std::string expected_notification_body = l10n_util::GetStringFUTF8(
+      IDS_UPDATE_NOTIFICATION_MESSAGE_LEARN_MORE, system_app_name_);
+
+  ASSERT_TRUE(HasNotification());
+  EXPECT_EQ(expected_notification_body, GetNotificationMessage());
+}
+
 TEST_F(UpdateNotificationControllerTest, SetUpdateNotificationRequiredHours) {
   ShowDefaultUpdateNotification();
 
diff --git a/ash/webui/personalization_app/resources/common/constants.ts b/ash/webui/personalization_app/resources/common/constants.ts
index 7430095..51c2ee3 100644
--- a/ash/webui/personalization_app/resources/common/constants.ts
+++ b/ash/webui/personalization_app/resources/common/constants.ts
@@ -44,7 +44,7 @@
 
 export type SendGooglePhotosCountEvent = {
   type: EventType.SEND_GOOGLE_PHOTOS_COUNT,
-  count: number|null,
+  count: bigint|null,
 };
 
 export type SendGooglePhotosPhotosEvent = {
diff --git a/ash/webui/personalization_app/resources/common/utils.ts b/ash/webui/personalization_app/resources/common/utils.ts
index 7a86355..db670447 100644
--- a/ash/webui/personalization_app/resources/common/utils.ts
+++ b/ash/webui/personalization_app/resources/common/utils.ts
@@ -22,6 +22,12 @@
   return maybeNullOrArray === null || Array.isArray(maybeNullOrArray);
 }
 
+/** Checks if argument is null or is a bigint. */
+export function isNullOrBigint(maybeNullOrBigint: unknown):
+    maybeNullOrBigint is bigint|null {
+  return maybeNullOrBigint === null || typeof maybeNullOrBigint === 'bigint';
+}
+
 /**
  * Checks if argument is null or is a number.
  */
diff --git a/ash/webui/personalization_app/resources/trusted/iframe_api.ts b/ash/webui/personalization_app/resources/trusted/iframe_api.ts
index b54997c..d7c88154 100644
--- a/ash/webui/personalization_app/resources/trusted/iframe_api.ts
+++ b/ash/webui/personalization_app/resources/trusted/iframe_api.ts
@@ -32,7 +32,7 @@
 /**
  * Sends the count of Google Photos photos to untrusted.
  */
-export function sendGooglePhotosCount(target: Window, count: number|null) {
+export function sendGooglePhotosCount(target: Window, count: bigint|null) {
   const event: constants.SendGooglePhotosCountEvent = {
     type: constants.EventType.SEND_GOOGLE_PHOTOS_COUNT,
     count
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_actions.ts b/ash/webui/personalization_app/resources/trusted/personalization_actions.ts
index 97844dc..db84f82 100644
--- a/ash/webui/personalization_app/resources/trusted/personalization_actions.ts
+++ b/ash/webui/personalization_app/resources/trusted/personalization_actions.ts
@@ -57,6 +57,7 @@
 export type BeginLoadGooglePhotosAlbumsAction = Action&{
   name: ActionName.BEGIN_LOAD_GOOGLE_PHOTOS_ALBUMS;
 };
+
 /**
  * Notify that the app is loading the list of Google Photos albums.
  */
@@ -244,14 +245,14 @@
 
 export type SetGooglePhotosCountAction = Action&{
   name: ActionName.SET_GOOGLE_PHOTOS_COUNT;
-  count: number;
+  count: bigint|null;
 };
 
 /**
  * Sets the count of Google Photos photos. May be called with null on error.
  */
-export function setGooglePhotosCountAction(count: number):
-    SetGooglePhotosCountAction {
+export function setGooglePhotosCountAction(count: bigint|
+                                           null): SetGooglePhotosCountAction {
   return {count, name: ActionName.SET_GOOGLE_PHOTOS_COUNT};
 }
 
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_state.ts b/ash/webui/personalization_app/resources/trusted/personalization_state.ts
index c176f1f5..1491fc5 100644
--- a/ash/webui/personalization_app/resources/trusted/personalization_state.ts
+++ b/ash/webui/personalization_app/resources/trusted/personalization_state.ts
@@ -28,7 +28,7 @@
  * initialized, then either null (in error state) or a valid Array.
  */
 export interface GooglePhotosState {
-  count: number|null|undefined;
+  count: bigint|null|undefined;
   albums: Array<WallpaperCollection>|null|undefined;
   photos: Array<undefined>|null|undefined;
   photosByAlbumId: Record<string, Array<undefined>|null|undefined>;
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_collections_element.js b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_collections_element.js
index 1c7fa67..38d5fce 100644
--- a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_collections_element.js
+++ b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_collections_element.js
@@ -11,7 +11,7 @@
 import './styles.js';
 
 import {kMaximumLocalImagePreviews} from '/common/constants.js';
-import {isNonEmptyArray, isNullOrArray, isNullOrNumber, promisifyOnload} from '/common/utils.js';
+import {isNonEmptyArray, isNullOrArray, isNullOrBigint, promisifyOnload} from '/common/utils.js';
 import {sendCollections, sendGooglePhotosCount, sendGooglePhotosPhotos, sendImageCounts, sendLocalImageData, sendLocalImages, sendVisible} from '/trusted/iframe_api.js';
 import {afterNextRender, html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -322,7 +322,7 @@
    */
   async onGooglePhotosCountChanged_(
       googlePhotosCount, googlePhotosCountLoading) {
-    if (googlePhotosCountLoading || !isNullOrNumber(googlePhotosCount)) {
+    if (googlePhotosCountLoading || !isNullOrBigint(googlePhotosCount)) {
       return;
     }
     const iframe = await this.iframePromise_;
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_controller.js b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_controller.js
index b1132ea..fa1b360 100644
--- a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_controller.js
+++ b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_controller.js
@@ -116,13 +116,8 @@
  */
 async function fetchGooglePhotosCount(provider, store) {
   store.dispatch(action.beginLoadGooglePhotosCountAction());
-
-  // TODO(dmblack): Create and wire up mojo API. For now, simulate an async
-  // request that returns a count of 1,000 Google Photos photos.
-  return new Promise(resolve => setTimeout(() => {
-                       store.dispatch(action.setGooglePhotosCountAction(1000));
-                       resolve();
-                     }, 1000));
+  const {count} = await provider.fetchGooglePhotosCount();
+  store.dispatch(action.setGooglePhotosCountAction(count >= 0n ? count : null));
 }
 
 /**
@@ -345,12 +340,12 @@
   // If the count of Google Photos photos is zero or null, it's not necesssary
   // to query the server for the list of albums/photos.
   const count = store.data.googlePhotos.count;
-  if (count === 0 || count === null) {
-    const /** ?Array<undefined> */ result = count === 0 ? [] : null;
+  if (count === 0n || count === null) {
+    const /** ?Array<undefined> */ result = count === 0n ? [] : null;
     store.beginBatchUpdate();
     store.dispatch(action.beginLoadGooglePhotosAlbumsAction());
-    store.dispatch(action.setGooglePhotosAlbumsAction(result));
     store.dispatch(action.beginLoadGooglePhotosPhotosAction());
+    store.dispatch(action.setGooglePhotosAlbumsAction(result));
     store.dispatch(action.setGooglePhotosPhotosAction(result));
     store.endBatchUpdate();
     return;
diff --git a/ash/webui/personalization_app/resources/untrusted/collections_grid.js b/ash/webui/personalization_app/resources/untrusted/collections_grid.js
index 653d766..eafe8c9 100644
--- a/ash/webui/personalization_app/resources/untrusted/collections_grid.js
+++ b/ash/webui/personalization_app/resources/untrusted/collections_grid.js
@@ -9,7 +9,7 @@
 import {afterNextRender, html, PolymerElement} from 'chrome-untrusted://personalization/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {EventType, kMaximumLocalImagePreviews} from '../common/constants.js';
-import {getLoadingPlaceholderAnimationDelay, getNumberOfGridItemsPerRow, isNullOrArray, isNullOrNumber, isSelectionEvent} from '../common/utils.js';
+import {getLoadingPlaceholderAnimationDelay, getNumberOfGridItemsPerRow, isNullOrArray, isNullOrBigint, isSelectionEvent} from '../common/utils.js';
 import {selectCollection, selectGooglePhotosCollection, selectLocalCollection, validateReceivedData} from '../untrusted/iframe_api.js';
 
 /**
@@ -65,7 +65,7 @@
 
 /**
  * Get the text to display for number of images.
- * @param {?number|undefined} x
+ * @param {?bigint|?number|undefined} x
  * @return {string}
  */
 function getCountText(x) {
@@ -74,11 +74,13 @@
     case null:
       return '';
     case 0:
+    case 0n:
       return loadTimeData.getString('zeroImages');
     case 1:
+    case 1n:
       return loadTimeData.getString('oneImage');
     default:
-      if (typeof x !== 'number' || x < 0) {
+      if (!['bigint', 'number'].includes(typeof x) || x < 0) {
         console.error('Received an impossible value');
         return '';
       }
@@ -89,7 +91,7 @@
 /**
  * Returns the tile to display for the Google Photos collection.
  * @param {?Array<undefined>} googlePhotos
- * @param {?number} googlePhotosCount
+ * @param {?bigint} googlePhotosCount
  * @return {!ImageTile}
  */
 function getGooglePhotosTile(googlePhotos, googlePhotosCount) {
@@ -191,7 +193,7 @@
 
       /**
        * The count of Google Photos photos.
-       * @type {?number}
+       * @type {?bigint}
        * @private
        */
       googlePhotosCount_: {
@@ -328,10 +330,10 @@
   /**
    * Invoked on changes to the list and count of Google Photos photos.
    * @param {?Array<undefined>} googlePhotos
-   * @param {?number} googlePhotosCount
+   * @param {?bigint} googlePhotosCount
    */
   onGooglePhotosLoaded_(googlePhotos, googlePhotosCount) {
-    if (isNullOrArray(googlePhotos) && isNullOrNumber(googlePhotosCount)) {
+    if (isNullOrArray(googlePhotos) && isNullOrBigint(googlePhotosCount)) {
       const tile = getGooglePhotosTile(googlePhotos, googlePhotosCount);
       this.set('tiles_.1', tile);
     }
diff --git a/ash/webui/personalization_app/resources/untrusted/iframe_api.ts b/ash/webui/personalization_app/resources/untrusted/iframe_api.ts
index d637ff0..4d60569 100644
--- a/ash/webui/personalization_app/resources/untrusted/iframe_api.ts
+++ b/ash/webui/personalization_app/resources/untrusted/iframe_api.ts
@@ -4,7 +4,7 @@
 
 import {assert, assertNotReached} from '../common/assert.m.js';
 import * as constants from '../common/constants.js';
-import {isNonEmptyArray, isNullOrArray, isNullOrNumber} from '../common/utils.js';
+import {isNonEmptyArray, isNullOrArray, isNullOrBigint} from '../common/utils.js';
 
 /**
  * @fileoverview Helper functions for communicating between trusted and
@@ -74,7 +74,7 @@
       return data.collections;
     }
     case constants.EventType.SEND_GOOGLE_PHOTOS_COUNT: {
-      assert(isNullOrNumber(data.count), 'Expected photos count');
+      assert(isNullOrBigint(data.count), 'Expected photos count');
       return data.count;
     }
     case constants.EventType.SEND_GOOGLE_PHOTOS_PHOTOS: {
diff --git a/base/BUILD.gn b/base/BUILD.gn
index e45a161..5a0d922 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -84,8 +84,7 @@
        "base must not be built in most nacl toolchains")
 
 # Determines whether libevent should be dep.
-dep_libevent =
-    !is_fuchsia && !is_win && !is_mac && !(is_nacl && !is_nacl_nonsfi)
+dep_libevent = !is_fuchsia && !is_win && !is_mac && !is_nacl
 
 # Determines whether message_pump_libevent should be used.
 use_libevent = dep_libevent && !is_ios
@@ -1843,14 +1842,21 @@
       "debug/crash_logging.h",
       "debug/stack_trace.cc",
       "debug/stack_trace_posix.cc",
+      "files/file_descriptor_watcher_posix.cc",
+      "files/file_descriptor_watcher_posix.h",
       "files/file_enumerator.cc",
       "files/file_enumerator_posix.cc",
       "files/file_proxy.cc",
+      "files/file_util.cc",
+      "files/file_util.h",
+      "files/file_util_posix.cc",
       "files/important_file_writer.cc",
       "files/important_file_writer.h",
       "files/important_file_writer_cleaner.cc",
       "files/important_file_writer_cleaner.h",
       "files/scoped_temp_dir.cc",
+      "json/json_file_value_serializer.cc",
+      "json/json_file_value_serializer.h",
       "memory/discardable_memory.cc",
       "memory/discardable_memory.h",
       "memory/discardable_memory_allocator.cc",
@@ -1865,8 +1871,13 @@
       "native_library.cc",
       "native_library_posix.cc",
       "path_service.cc",
+      "posix/unix_domain_socket.cc",
       "process/kill.cc",
       "process/kill.h",
+      "process/kill_posix.cc",
+      "process/launch.cc",
+      "process/launch.h",
+      "process/launch_posix.cc",
       "process/memory.cc",
       "process/memory.h",
       "process/process_iterator.cc",
@@ -1875,35 +1886,16 @@
       "process/process_metrics_posix.cc",
       "process/process_posix.cc",
       "profiler/module_cache_posix.cc",
+      "rand_util_posix.cc",
       "scoped_native_library.cc",
       "sync_socket_posix.cc",
       "system/sys_info.cc",
       "system/sys_info_posix.cc",
       "task/thread_pool/initialization_util.cc",
       "task/thread_pool/initialization_util.h",
+      "task/thread_pool/task_tracker_posix.cc",
+      "task/thread_pool/task_tracker_posix.h",
     ]
-
-    if (is_nacl_nonsfi) {
-      sources -= [ "rand_util_nacl.cc" ]
-    } else {
-      sources -= [
-        "files/file_descriptor_watcher_posix.cc",
-        "files/file_descriptor_watcher_posix.h",
-        "files/file_util.cc",
-        "files/file_util.h",
-        "files/file_util_posix.cc",
-        "json/json_file_value_serializer.cc",
-        "json/json_file_value_serializer.h",
-        "posix/unix_domain_socket.cc",
-        "process/kill_posix.cc",
-        "process/launch.cc",
-        "process/launch.h",
-        "process/launch_posix.cc",
-        "rand_util_posix.cc",
-        "task/thread_pool/task_tracker_posix.cc",
-        "task/thread_pool/task_tracker_posix.h",
-      ]
-    }
   } else {
     # Remove NaCl stuff.
     sources -= [
diff --git a/base/allocator/partition_allocator/partition_alloc_perftest.cc b/base/allocator/partition_allocator/partition_alloc_perftest.cc
index c2b9a66..ab9af8b 100644
--- a/base/allocator/partition_allocator/partition_alloc_perftest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_perftest.cc
@@ -384,12 +384,8 @@
     ::testing::Combine(
         ::testing::Values(1, 2, 3, 4),
         ::testing::Values(AllocatorType::kSystem,
-                          AllocatorType::kPartitionAlloc
-#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-                          ,
-                          AllocatorType::kPartitionAllocWithThreadCache
-#endif
-                          )));
+                          AllocatorType::kPartitionAlloc,
+                          AllocatorType::kPartitionAllocWithThreadCache)));
 
 // This test (and the other one below) allocates a large amount of memory, which
 // can cause issues on Android.
diff --git a/base/memory/raw_ptr.h b/base/memory/raw_ptr.h
index ae4dd677..5200c15 100644
--- a/base/memory/raw_ptr.h
+++ b/base/memory/raw_ptr.h
@@ -557,29 +557,19 @@
     return *this += -delta_elems;
   }
 
-  // Be careful to cover all cases with raw_ptr being on both sides, left
-  // side only and right side only. If any case is missed, a more costly
-  // |operator T*()| will get called, instead of |operator==|.
-  friend ALWAYS_INLINE bool operator==(const raw_ptr& lhs, const raw_ptr& rhs) {
-    return lhs.GetForComparison() == rhs.GetForComparison();
-  }
-  friend ALWAYS_INLINE bool operator!=(const raw_ptr& lhs, const raw_ptr& rhs) {
-    return !(lhs == rhs);
-  }
-  friend ALWAYS_INLINE bool operator==(const raw_ptr& lhs, T* rhs) {
-    return lhs.GetForComparison() == rhs;
-  }
-  friend ALWAYS_INLINE bool operator!=(const raw_ptr& lhs, T* rhs) {
-    return !(lhs == rhs);
-  }
-  friend ALWAYS_INLINE bool operator==(T* lhs, const raw_ptr& rhs) {
-    return rhs == lhs;  // Reverse order to call the operator above.
-  }
-  friend ALWAYS_INLINE bool operator!=(T* lhs, const raw_ptr& rhs) {
-    return rhs != lhs;  // Reverse order to call the operator above.
-  }
-  // Needed for cases like |derived_ptr == base_ptr|. Without these, a more
-  // costly |operator U*()| will get called, instead of |operator==|.
+  // Comparison operators between raw_ptr and raw_ptr<U>/U*/std::nullptr_t.
+  // Strictly speaking, it is not necessary to provide these: the compiler can
+  // use the conversion operator implicitly to allow comparisons to fall back to
+  // comparisons between raw pointers. However, `operator T*`/`operator U*` may
+  // perform safety checks with a higher runtime cost, so to avoid this, provide
+  // explicit comparison operators for all combinations of parameters.
+
+  // Comparisons between `raw_ptr`s. This unusual declaration and separate
+  // definition below is because `GetForComparison()` is a private method. The
+  // more conventional approach of defining a comparison operator between
+  // `raw_ptr` and `raw_ptr<U>` in the friend declaration itself does not work,
+  // because a comparison operator defined inline would not be allowed to call
+  // `raw_ptr<U>`'s private `GetForComparison()` method.
   template <typename U, typename V, typename I>
   friend ALWAYS_INLINE bool operator==(const raw_ptr<U, I>& lhs,
                                        const raw_ptr<V, I>& rhs);
@@ -588,6 +578,9 @@
                                        const raw_ptr<U, Impl>& rhs) {
     return !(lhs == rhs);
   }
+
+  // Comparisons with U*. These operators also handle the case where the RHS is
+  // T*.
   template <typename U>
   friend ALWAYS_INLINE bool operator==(const raw_ptr& lhs, U* rhs) {
     return lhs.GetForComparison() == rhs;
@@ -604,9 +597,8 @@
   friend ALWAYS_INLINE bool operator!=(U* lhs, const raw_ptr& rhs) {
     return rhs != lhs;  // Reverse order to call the operator above.
   }
-  // Needed for comparisons against nullptr. Without these, a slightly more
-  // costly version would be called that extracts wrapped pointer, as opposed
-  // to plain comparison against 0.
+
+  // Comparisons with `std::nullptr_t`.
   friend ALWAYS_INLINE bool operator==(const raw_ptr& lhs, std::nullptr_t) {
     return !lhs;
   }
diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc
index 5f7d73d..7856933 100644
--- a/base/strings/string_util.cc
+++ b/base/strings/string_util.cc
@@ -21,6 +21,7 @@
 #include <type_traits>
 #include <vector>
 
+#include "base/cfi_buildflags.h"
 #include "base/check_op.h"
 #include "base/cxx17_backports.h"
 #include "base/no_destructor.h"
@@ -35,7 +36,8 @@
 bool IsWprintfFormatPortable(const wchar_t* format) {
   // This snippet of code checks that we can build C++17 code.
   // TODO(thakis): Enable this on all platforms, and then remove it again.
-#if defined(OS_WIN)
+#if !defined(OS_IOS) && !defined(OS_MAC) && !BUILDFLAG(CFI_ICALL_CHECK) && \
+    !BUILDFLAG(CFI_CAST_CHECK)
   if constexpr (constexpr int i = 0; i > 0) {
   }
 #endif
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn
index 4a78441..bccfbdd 100644
--- a/base/test/BUILD.gn
+++ b/base/test/BUILD.gn
@@ -264,39 +264,7 @@
     ]
   }
 
-  if (is_nacl_nonsfi) {
-    sources += [
-      "launcher/test_launcher.h",
-      "launcher/test_result.h",
-      "launcher/unit_test_launcher.h",
-      "launcher/unit_test_launcher_nacl_nonsfi.cc",
-    ]
-    sources -= [
-      "gtest_xml_util.cc",
-      "gtest_xml_util.h",
-      "icu_test_util.cc",
-      "icu_test_util.h",
-      "metrics/histogram_enum_reader.cc",
-      "metrics/histogram_enum_reader.h",
-      "perf_test_suite.cc",
-      "perf_test_suite.h",
-      "scoped_path_override.cc",
-      "scoped_path_override.h",
-      "test_discardable_memory_allocator.cc",
-      "test_discardable_memory_allocator.h",
-      "test_file_util.cc",
-      "test_file_util.h",
-      "test_file_util_posix.cc",
-      "test_suite.cc",
-      "test_suite.h",
-    ]
-    public_deps -= [ "//base:i18n" ]
-    deps -= [
-      "//third_party/icu:icuuc",
-      "//third_party/libxml:libxml_utils",
-      "//third_party/libxml:xml_reader",
-    ]
-  } else if (!is_ios) {
+  if (!is_ios) {
     sources += [
       "launcher/test_launcher.cc",
       "launcher/test_launcher.h",
@@ -317,13 +285,9 @@
       "trace_event_analyzer.h",
       "trace_test_utils.cc",
       "trace_test_utils.h",
+      "trace_to_file.cc",
+      "trace_to_file.h",
     ]
-    if (!is_nacl_nonsfi) {
-      sources += [
-        "trace_to_file.cc",
-        "trace_to_file.h",
-      ]
-    }
   }
 }
 
@@ -350,15 +314,6 @@
   public_configs = [ ":perf_test_config" ]
 }
 
-static_library("test_launcher_nacl_nonsfi") {
-  testonly = true
-  sources = [
-    "launcher/test_launcher_nacl_nonsfi.cc",
-    "launcher/test_launcher_nacl_nonsfi.h",
-  ]
-  deps = [ ":test_support" ]
-}
-
 static_library("run_all_unittests") {
   testonly = true
   sources = [ "run_all_unittests.cc" ]
diff --git a/base/test/launcher/unit_test_launcher_nacl_nonsfi.cc b/base/test/launcher/unit_test_launcher_nacl_nonsfi.cc
deleted file mode 100644
index 3f53c84..0000000
--- a/base/test/launcher/unit_test_launcher_nacl_nonsfi.cc
+++ /dev/null
@@ -1,53 +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 "base/test/launcher/unit_test_launcher.h"
-
-#include "base/command_line.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/test/gtest_util.h"
-#include "base/test/gtest_xml_unittest_result_printer.h"
-#include "base/test/test_switches.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-
-int LaunchUnitTests(int argc,
-                    char** argv,
-                    RunTestSuiteCallback run_test_suite,
-                    size_t retry_limit) {
-  CHECK(CommandLine::InitializedForCurrentProcess() ||
-        CommandLine::Init(argc, argv));
-  const CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kTestLauncherListTests)) {
-    // Dump all test list into a file.
-    FilePath list_path(
-        command_line->GetSwitchValuePath(switches::kTestLauncherListTests));
-    if (!WriteCompiledInTestsToFile(list_path)) {
-      LOG(ERROR) << "Failed to write list of tests.";
-      return 1;
-    }
-
-    // Successfully done.
-    return 0;
-  }
-
-  // Register XML output printer, if --test-launcher-output flag is set.
-  if (command_line->HasSwitch(switches::kTestLauncherOutput)) {
-    FilePath output_path = command_line->GetSwitchValuePath(
-        switches::kTestLauncherOutput);
-    if (PathExists(output_path)) {
-      LOG(WARNING) << "Test launcher output path exists. Do not override";
-    } else {
-      XmlUnitTestResultPrinter* printer = new XmlUnitTestResultPrinter;
-      CHECK(printer->Initialize(output_path));
-      testing::UnitTest::GetInstance()->listeners().Append(printer);
-    }
-  }
-
-  return std::move(run_test_suite).Run();
-}
-
-}  // namespace base
diff --git a/base/third_party/libevent/BUILD.gn b/base/third_party/libevent/BUILD.gn
index abd3901d..755a6a6e 100644
--- a/base/third_party/libevent/BUILD.gn
+++ b/base/third_party/libevent/BUILD.gn
@@ -57,22 +57,6 @@
       "epoll.c",
     ]
     include_dirs = [ "android" ]
-  } else if (is_nacl_nonsfi) {
-    sources -= [
-      "evdns.c",
-      "event_tagging.c",
-      "evrpc.c",
-      "http.c",
-      "select.c",
-      "signal.c",
-    ]
-    sources += [
-      "nacl_nonsfi/config.h",
-      "nacl_nonsfi/event-config.h",
-      "nacl_nonsfi/random.c",
-      "nacl_nonsfi/signal_stub.c",
-    ]
-    include_dirs = [ "nacl_nonsfi" ]
   }
 
   if (!is_debug) {
diff --git a/base/third_party/libevent/README.chromium b/base/third_party/libevent/README.chromium
index 85132a48..0f05357 100644
--- a/base/third_party/libevent/README.chromium
+++ b/base/third_party/libevent/README.chromium
@@ -28,13 +28,6 @@
 4) The directories WIN32-Code and WIN32-Prj are not included.
 5) The configs for android were copied from Linux's which were very close to
    android one with the exception of HAVE_FD_MASK and HAVE_STRLCPY.
-6) Add files to support building with the PNaCl toolchain. Added
-   libevent_nacl_nonsfi.gyp for build rule. nacl_nonsfi/config.h and
-   nacl_nonsfi/event-config.h are derived from linux/ counterparts.
-   nacl_nonsfi/random.c is also added to provide the random() function,
-   which is missing in the newlib-based PNaCl toolchain.
-7) Stub out signal.c for nacl_helper_nonsfi. socketpair() will be prohibited
-   by sandbox in nacl_helper_nonsfi.
-8) Remove an unnecessary workaround for OS X 10.4 from kqueue.c. It was causing
+6) Remove an unnecessary workaround for OS X 10.4 from kqueue.c. It was causing
    problems on macOS Sierra.
-9) Change buffer.c to not redefine _GNU_SOURCE.
+7) Change buffer.c to not redefine _GNU_SOURCE.
diff --git a/base/third_party/libevent/event-config.h b/base/third_party/libevent/event-config.h
index bbd23f1..5f301cf9 100644
--- a/base/third_party/libevent/event-config.h
+++ b/base/third_party/libevent/event-config.h
@@ -5,9 +5,7 @@
 // This file is Chromium-specific, and brings in the appropriate
 // event-config.h depending on your platform.
 
-#if defined(__native_client_nonsfi__)
-#include "base/third_party/libevent/nacl_nonsfi/event-config.h"
-#elif defined(__APPLE__)
+#if defined(__APPLE__)
 #include "base/third_party/libevent/mac/event-config.h"
 #elif defined(ANDROID)
 #include "base/third_party/libevent/android/event-config.h"
diff --git a/base/third_party/libevent/nacl_nonsfi/config.h b/base/third_party/libevent/nacl_nonsfi/config.h
deleted file mode 100644
index 60c9dfe7..0000000
--- a/base/third_party/libevent/nacl_nonsfi/config.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/* Copied from Linux version and changed the features according the PNaCl
- * toolchain for the Non-SFI binary build, which is close to one under the
- * linux/ directory. The built binary will be running under Linux directly,
- * actually.
- */
-
-/* Define if clock_gettime is available in libc */
-#define DNS_USE_CPU_CLOCK_FOR_ID 1
-
-/* Define is no secure id variant is available */
-/* #undef DNS_USE_GETTIMEOFDAY_FOR_ID */
-
-/* Define to 1 if you have the `clock_gettime' function. */
-#define HAVE_CLOCK_GETTIME 1
-
-/* Define if /dev/poll is available */
-/* #undef HAVE_DEVPOLL */
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-/* #undef HAVE_DLFCN_H */
-
-/* Define if your system supports the epoll system calls */
-/* #undef HAVE_EPOLL */
-
-/* Define to 1 if you have the `epoll_ctl' function. */
-/* #undef HAVE_EPOLL_CTL */
-
-/* Define if your system supports event ports */
-/* #undef HAVE_EVENT_PORTS */
-
-/* Define to 1 if you have the `fcntl' function. */
-#define HAVE_FCNTL 1
-
-/* Define to 1 if you have the <fcntl.h> header file. */
-#define HAVE_FCNTL_H 1
-
-/* Define to 1 if the system has the type `fd_mask'. */
-#define HAVE_FD_MASK 1
-
-/* Define to 1 if you have the `getaddrinfo' function. */
-#define HAVE_GETADDRINFO 1
-
-/* Define to 1 if you have the `getegid' function. */
-#define HAVE_GETEGID 1
-
-/* Define to 1 if you have the `geteuid' function. */
-#define HAVE_GETEUID 1
-
-/* Define to 1 if you have the `getnameinfo' function. */
-#define HAVE_GETNAMEINFO 1
-
-/* Define to 1 if you have the `gettimeofday' function. */
-#define HAVE_GETTIMEOFDAY 1
-
-/* Define to 1 if you have the `inet_ntop' function. */
-#define HAVE_INET_NTOP 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the `issetugid' function. */
-/* #undef HAVE_ISSETUGID */
-
-/* Define to 1 if you have the `kqueue' function. */
-/* #undef HAVE_KQUEUE */
-
-/* Define to 1 if you have the `nsl' library (-lnsl). */
-#define HAVE_LIBNSL 1
-
-/* Define to 1 if you have the `resolv' library (-lresolv). */
-#define HAVE_LIBRESOLV 1
-
-/* Define to 1 if you have the `rt' library (-lrt). */
-#define HAVE_LIBRT 1
-
-/* Define to 1 if you have the `socket' library (-lsocket). */
-/* #undef HAVE_LIBSOCKET */
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define to 1 if you have the <netinet/in6.h> header file. */
-/* #undef HAVE_NETINET_IN6_H */
-
-/* Define to 1 if you have the `poll' function. */
-#define HAVE_POLL 1
-
-/* Define to 1 if you have the <poll.h> header file. */
-#define HAVE_POLL_H 1
-
-/* Define to 1 if you have the `port_create' function. */
-/* #undef HAVE_PORT_CREATE */
-
-/* Define to 1 if you have the <port.h> header file. */
-/* #undef HAVE_PORT_H */
-
-/* Define to 1 if you have the `select' function. */
-/* #undef HAVE_SELECT */
-
-/* Define if F_SETFD is defined in <fcntl.h> */
-#define HAVE_SETFD 1
-
-/* Note: The PNaCl toolchain prodives linux ABI's sigaction, named
- * linux_sigaction() in native_client/src/nonsfi/linux/linux_sys_private.c,
- * but newlib ABI sigaction() is not provided.
- */
-/* Define to 1 if you have the `sigaction' function. */
-/* #undef HAVE_SIGACTION */
-
-/* Define to 1 if you have the `signal' function. */
-/* #undef HAVE_SIGNAL */
-
-/* Define to 1 if you have the <signal.h> header file. */
-#define HAVE_SIGNAL_H 1
-
-/* Define to 1 if you have the <stdarg.h> header file. */
-#define HAVE_STDARG_H 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the `strlcpy' function. */
-/* #undef HAVE_STRLCPY */
-
-/* Define to 1 if you have the `strsep' function. */
-#define HAVE_STRSEP 1
-
-/* Define to 1 if you have the `strtok_r' function. */
-#define HAVE_STRTOK_R 1
-
-/* Define to 1 if you have the `strtoll' function. */
-#define HAVE_STRTOLL 1
-
-/* Define to 1 if the system has the type `struct in6_addr'. */
-#define HAVE_STRUCT_IN6_ADDR 1
-
-/* Define to 1 if you have the <sys/devpoll.h> header file. */
-/* #undef HAVE_SYS_DEVPOLL_H */
-
-/* Define to 1 if you have the <sys/epoll.h> header file. */
-#define HAVE_SYS_EPOLL_H 1
-
-/* Define to 1 if you have the <sys/event.h> header file. */
-/* #undef HAVE_SYS_EVENT_H */
-
-/* Define to 1 if you have the <sys/ioctl.h> header file. */
-/* #undef HAVE_SYS_IOCTL_H */
-
-/* Define to 1 if you have the <sys/param.h> header file. */
-#define HAVE_SYS_PARAM_H 1
-
-/* Define to 1 if you have the <sys/queue.h> header file. */
-#define HAVE_SYS_QUEUE_H 1
-
-/* Define to 1 if you have the <sys/select.h> header file. */
-/* #undef HAVE_SYS_SELECT_H */
-
-/* Define to 1 if you have the <sys/socket.h> header file. */
-#define HAVE_SYS_SOCKET_H 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#define HAVE_SYS_TIME_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
-#define HAVE_TAILQFOREACH 1
-
-/* Define if timeradd is defined in <sys/time.h> */
-/* #undef HAVE_TIMERADD */
-
-/* Define if timerclear is defined in <sys/time.h> */
-/* #undef HAVE_TIMERCLEAR */
-
-/* Define if timercmp is defined in <sys/time.h> */
-/* #undef HAVE_TIMERCMP */
-
-/* Define if timerisset is defined in <sys/time.h> */
-/* #undef HAVE_TIMERISSET */
-
-/* Define to 1 if the system has the type `uint16_t'. */
-#define HAVE_UINT16_T 1
-
-/* Define to 1 if the system has the type `uint32_t'. */
-#define HAVE_UINT32_T 1
-
-/* Define to 1 if the system has the type `uint64_t'. */
-#define HAVE_UINT64_T 1
-
-/* Define to 1 if the system has the type `uint8_t'. */
-#define HAVE_UINT8_T 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
-
-/* Define to 1 if you have the `vasprintf' function. */
-/* #undef HAVE_VASPRINTF */
-
-/* Define if kqueue works correctly with pipes */
-/* #undef HAVE_WORKING_KQUEUE */
-
-/* Name of package */
-#define PACKAGE "libevent_nacl"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT ""
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME ""
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING ""
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME ""
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION ""
-
-/* The size of `int', as computed by sizeof. */
-#define SIZEOF_INT 4
-
-/* The size of `long', as computed by sizeof. */
-#define SIZEOF_LONG 8
-
-/* The size of `long long', as computed by sizeof. */
-#define SIZEOF_LONG_LONG 8
-
-/* The size of `short', as computed by sizeof. */
-#define SIZEOF_SHORT 2
-
-/* Define to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
-#define TIME_WITH_SYS_TIME 1
-
-/* Version number of package */
-#define VERSION "1.4.13-stable"
-
-/* Define to appropriate substitue if compiler doesnt have __func__ */
-/* #undef __func__ */
-
-/* Define to empty if `const' does not conform to ANSI C. */
-/* #undef const */
-
-/* Define to `__inline__' or `__inline' if that's what the C compiler
-   calls it, or to nothing if 'inline' is not supported under any name.  */
-#ifndef __cplusplus
-/* #undef inline */
-#endif
-
-/* Define to `int' if <sys/types.h> does not define. */
-/* #undef pid_t */
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-/* #undef size_t */
-
-/* Define to unsigned int if you dont have it */
-/* #undef socklen_t */
diff --git a/base/third_party/libevent/nacl_nonsfi/event-config.h b/base/third_party/libevent/nacl_nonsfi/event-config.h
deleted file mode 100644
index fe28043..0000000
--- a/base/third_party/libevent/nacl_nonsfi/event-config.h
+++ /dev/null
@@ -1,290 +0,0 @@
-/* Copied from Linux version and changed the features according the PNaCl
- * toolchain for the Non-SFI binary build, which is close to one under the
- * linux/ directory. The built binary will be running under Linux directly,
- * actually.
- */
-
-#ifndef _EVENT_CONFIG_H_
-#define _EVENT_CONFIG_H_
-
-/* Define if clock_gettime is available in libc */
-#define _EVENT_DNS_USE_CPU_CLOCK_FOR_ID 1
-
-/* Define is no secure id variant is available */
-/* #undef _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID */
-
-/* Define to 1 if you have the `clock_gettime' function. */
-#define _EVENT_HAVE_CLOCK_GETTIME 1
-
-/* Define if /dev/poll is available */
-/* #undef _EVENT_HAVE_DEVPOLL */
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#define _EVENT_HAVE_DLFCN_H 1
-
-/* Define if your system supports the epoll system calls */
-/* #undef _EVENT_HAVE_EPOLL */
-
-/* Define to 1 if you have the `epoll_ctl' function. */
-/* #undef _EVENT_HAVE_EPOLL_CTL */
-
-/* Define if your system supports event ports */
-/* #undef _EVENT_HAVE_EVENT_PORTS */
-
-/* Define to 1 if you have the `fcntl' function. */
-#define _EVENT_HAVE_FCNTL 1
-
-/* Define to 1 if you have the <fcntl.h> header file. */
-#define _EVENT_HAVE_FCNTL_H 1
-
-/* Define to 1 if the system has the type `fd_mask'. */
-#define _EVENT_HAVE_FD_MASK 1
-
-/* Define to 1 if you have the `getaddrinfo' function. */
-#define _EVENT_HAVE_GETADDRINFO 1
-
-/* Define to 1 if you have the `getegid' function. */
-#define _EVENT_HAVE_GETEGID 1
-
-/* Define to 1 if you have the `geteuid' function. */
-#define _EVENT_HAVE_GETEUID 1
-
-/* Define to 1 if you have the `getnameinfo' function. */
-#define _EVENT_HAVE_GETNAMEINFO 1
-
-/* Define to 1 if you have the `gettimeofday' function. */
-#define _EVENT_HAVE_GETTIMEOFDAY 1
-
-/* Define to 1 if you have the `inet_ntop' function. */
-#define _EVENT_HAVE_INET_NTOP 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define _EVENT_HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the `issetugid' function. */
-/* #undef _EVENT_HAVE_ISSETUGID */
-
-/* Define to 1 if you have the `kqueue' function. */
-/* #undef _EVENT_HAVE_KQUEUE */
-
-/* Define to 1 if you have the `nsl' library (-lnsl). */
-#define _EVENT_HAVE_LIBNSL 1
-
-/* Define to 1 if you have the `resolv' library (-lresolv). */
-#define _EVENT_HAVE_LIBRESOLV 1
-
-/* Define to 1 if you have the `rt' library (-lrt). */
-#define _EVENT_HAVE_LIBRT 1
-
-/* Define to 1 if you have the `socket' library (-lsocket). */
-/* #undef _EVENT_HAVE_LIBSOCKET */
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define _EVENT_HAVE_MEMORY_H 1
-
-/* Define to 1 if you have the <netinet/in6.h> header file. */
-/* #undef _EVENT_HAVE_NETINET_IN6_H */
-
-/* Define to 1 if you have the `poll' function. */
-#define _EVENT_HAVE_POLL 1
-
-/* Define to 1 if you have the <poll.h> header file. */
-#define _EVENT_HAVE_POLL_H 1
-
-/* Define to 1 if you have the `port_create' function. */
-/* #undef _EVENT_HAVE_PORT_CREATE */
-
-/* Define to 1 if you have the <port.h> header file. */
-/* #undef _EVENT_HAVE_PORT_H */
-
-/* Define to 1 if you have the `select' function. */
-/* #undef _EVENT_HAVE_SELECT */
-
-/* Define if F_SETFD is defined in <fcntl.h> */
-#define _EVENT_HAVE_SETFD 1
-
-/* Define to 1 if you have the `sigaction' function. */
-/* #undef _EVENT_HAVE_SIGACTION */
-
-/* Define to 1 if you have the `signal' function. */
-#define _EVENT_HAVE_SIGNAL 1
-
-/* Define to 1 if you have the <signal.h> header file. */
-#define _EVENT_HAVE_SIGNAL_H 1
-
-/* Define to 1 if you have the <stdarg.h> header file. */
-#define _EVENT_HAVE_STDARG_H 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#define _EVENT_HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define _EVENT_HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define _EVENT_HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define _EVENT_HAVE_STRING_H 1
-
-/* Define to 1 if you have the `strlcpy' function. */
-/* #undef _EVENT_HAVE_STRLCPY */
-
-/* Define to 1 if you have the `strsep' function. */
-#define _EVENT_HAVE_STRSEP 1
-
-/* Define to 1 if you have the `strtok_r' function. */
-#define _EVENT_HAVE_STRTOK_R 1
-
-/* Define to 1 if you have the `strtoll' function. */
-#define _EVENT_HAVE_STRTOLL 1
-
-/* Define to 1 if the system has the type `struct in6_addr'. */
-#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
-
-/* Define to 1 if you have the <sys/devpoll.h> header file. */
-/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
-
-/* Define to 1 if you have the <sys/epoll.h> header file. */
-/* #undef _EVENT_HAVE_SYS_EPOLL_H */
-
-/* Define to 1 if you have the <sys/event.h> header file. */
-/* #undef _EVENT_HAVE_SYS_EVENT_H */
-
-/* Define to 1 if you have the <sys/ioctl.h> header file. */
-/* #undef _EVENT_HAVE_SYS_IOCTL_H */
-
-/* Define to 1 if you have the <sys/param.h> header file. */
-#define _EVENT_HAVE_SYS_PARAM_H 1
-
-/* Define to 1 if you have the <sys/queue.h> header file. */
-#define _EVENT_HAVE_SYS_QUEUE_H 1
-
-/* Define to 1 if you have the <sys/select.h> header file. */
-#define _EVENT_HAVE_SYS_SELECT_H 1
-
-/* Define to 1 if you have the <sys/socket.h> header file. */
-#define _EVENT_HAVE_SYS_SOCKET_H 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define _EVENT_HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#define _EVENT_HAVE_SYS_TIME_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define _EVENT_HAVE_SYS_TYPES_H 1
-
-/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
-#define _EVENT_HAVE_TAILQFOREACH 1
-
-/* Define if timeradd is defined in <sys/time.h> */
-/* #undef _EVENT_HAVE_TIMERADD */
-
-/* Define if timerclear is defined in <sys/time.h> */
-/* #undef _EVENT_HAVE_TIMERCLEAR */
-
-/* Define if timercmp is defined in <sys/time.h> */
-/* #undef _EVENT_HAVE_TIMERCMP */
-
-/* Define if timerisset is defined in <sys/time.h> */
-/* #undef _EVENT_HAVE_TIMERISSET */
-
-/* Define to 1 if the system has the type `uint16_t'. */
-#define _EVENT_HAVE_UINT16_T 1
-
-/* Define to 1 if the system has the type `uint32_t'. */
-#define _EVENT_HAVE_UINT32_T 1
-
-/* Define to 1 if the system has the type `uint64_t'. */
-#define _EVENT_HAVE_UINT64_T 1
-
-/* Define to 1 if the system has the type `uint8_t'. */
-#define _EVENT_HAVE_UINT8_T 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define _EVENT_HAVE_UNISTD_H 1
-
-/* Define to 1 if you have the `vasprintf' function. */
-#define _EVENT_HAVE_VASPRINTF 1
-
-/* Define if kqueue works correctly with pipes */
-/* #undef _EVENT_HAVE_WORKING_KQUEUE */
-
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
-   */
-#define _EVENT_LT_OBJDIR ".libs/"
-
-/* Numeric representation of the version */
-#define _EVENT_NUMERIC_VERSION 0x01040f00
-
-/* Name of package */
-#define _EVENT_PACKAGE "libevent_nacl"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define _EVENT_PACKAGE_BUGREPORT ""
-
-/* Define to the full name of this package. */
-#define _EVENT_PACKAGE_NAME ""
-
-/* Define to the full name and version of this package. */
-#define _EVENT_PACKAGE_STRING ""
-
-/* Define to the one symbol short name of this package. */
-#define _EVENT_PACKAGE_TARNAME ""
-
-/* Define to the home page for this package. */
-#define _EVENT_PACKAGE_URL ""
-
-/* Define to the version of this package. */
-#define _EVENT_PACKAGE_VERSION ""
-
-/* The size of `int', as computed by sizeof. */
-#define _EVENT_SIZEOF_INT 4
-
-/* The size of `long', as computed by sizeof. */
-#define _EVENT_SIZEOF_LONG 8
-
-/* The size of `long long', as computed by sizeof. */
-#define _EVENT_SIZEOF_LONG_LONG 8
-
-/* The size of `short', as computed by sizeof. */
-#define _EVENT_SIZEOF_SHORT 2
-
-/* Define to 1 if you have the ANSI C header files. */
-#define _EVENT_STDC_HEADERS 1
-
-/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
-#define _EVENT_TIME_WITH_SYS_TIME 1
-
-/* Version number of package */
-#define _EVENT_VERSION "1.4.15"
-
-/* Define to appropriate substitue if compiler doesnt have __func__ */
-/* #undef _EVENT___func__ */
-
-/* Define to empty if `const' does not conform to ANSI C. */
-/* #undef _EVENT_const */
-
-/* Define to `__inline__' or `__inline' if that's what the C compiler
-   calls it, or to nothing if 'inline' is not supported under any name.  */
-#ifndef _EVENT___cplusplus
-/* #undef _EVENT_inline */
-#endif
-
-/* Define to `int' if <sys/types.h> does not define. */
-/* #undef _EVENT_pid_t */
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-/* #undef _EVENT_size_t */
-
-/* Define to unsigned int if you dont have it */
-/* #undef _EVENT_socklen_t */
-
-/* Work around for __native_client_nonsfi__ build. random() is not provided
- * by the newlib-based PNaCl toolchain, so here we declare it. Please see also
- * nacl_nonsfi/random.c for more details.
- */
-long int random();
-
-#endif
diff --git a/base/third_party/libevent/nacl_nonsfi/random.c b/base/third_party/libevent/nacl_nonsfi/random.c
deleted file mode 100644
index 3577dd50..0000000
--- a/base/third_party/libevent/nacl_nonsfi/random.c
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Copyright 2014 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 <stdlib.h>
-
-/* The newlib-based PNaCl toolchain does not provide random(). So, here we
- * define it. It just redirects to the rand(), which is provided by the
- * toolchain. */
-long int random() {
-  return rand();
-}
diff --git a/base/third_party/libevent/nacl_nonsfi/signal_stub.c b/base/third_party/libevent/nacl_nonsfi/signal_stub.c
deleted file mode 100644
index 0399e8c..0000000
--- a/base/third_party/libevent/nacl_nonsfi/signal_stub.c
+++ /dev/null
@@ -1,48 +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.
- */
-
-/*
- * In nacl_helper_nonsfi, socketpair() is unavailable. In libevent, it is used
- * to notify of a signal handler invocation, which is unused in
- * nacl_helper_nonsfi. Unfortunately, there is no macro to disable the feature,
- * so we stub out the signal module entirely.
- */
-
-
-#include <signal.h>
-#include <stdlib.h>
-#include <sys/queue.h>
-
-/* config.h must be included before any other libevent header is included. */
-#include "config.h"
-
-#include "base/third_party/libevent/event-internal.h"
-#include "base/third_party/libevent/event.h"
-#include "base/third_party/libevent/evsignal.h"
-
-
-struct event_base *evsignal_base = 0;
-
-int evsignal_init(struct event_base *base) {
-  /* Do nothing, and return success. */
-  return 0;
-}
-
-void evsignal_process(struct event_base *base) {
-}
-
-int evsignal_add(struct event *event) {
-  /* Do nothing, and return an error. */
-  return -1;
-}
-
-int evsignal_del(struct event *event) {
-  /* Do nothing, and return an error. */
-  return -1;
-}
-
-void evsignal_dealloc(struct event_base *base) {
-}
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index a9d955d..c6430b4 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -252,12 +252,7 @@
 namespace core {
 class ScopedIPCSupport;
 }
-}
-namespace nacl {
-namespace nonsfi {
-class PluginMainDelegate;
-}
-}  // namespace nacl
+}  // namespace mojo
 namespace printing {
 class LocalPrinterHandlerDefault;
 #if defined(OS_MAC)
@@ -828,8 +823,6 @@
   PermanentSingletonAllowance() = delete;
 
  private:
-  friend class nacl::nonsfi::PluginMainDelegate;
-
   // Re-allow singletons on this thread. Since //base APIs DisallowSingleton()
   // when they risk running past shutdown, this should only be called in rare
   // cases where the caller knows the process will be killed rather than
diff --git a/build/apple/xcrun.py b/build/apple/xcrun.py
index 71bf50c..c505494 100755
--- a/build/apple/xcrun.py
+++ b/build/apple/xcrun.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # 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.
diff --git a/build/build_config.h b/build/build_config.h
index 63cec87..a39aea55 100644
--- a/build/build_config.h
+++ b/build/build_config.h
@@ -6,7 +6,7 @@
 //
 //  Operating System:
 //    OS_AIX / OS_ANDROID / OS_ASMJS / OS_FREEBSD / OS_FUCHSIA / OS_IOS /
-//    OS_LINUX / OS_MAC / OS_NACL (SFI or NONSFI) / OS_NETBSD / OS_OPENBSD /
+//    OS_LINUX / OS_MAC / OS_NACL / OS_NETBSD / OS_OPENBSD /
 //    OS_QNX / OS_SOLARIS / OS_WIN
 //  Operating System family:
 //    OS_APPLE: IOS or MAC
@@ -40,14 +40,7 @@
 #if defined(__native_client__)
 // __native_client__ must be first, so that other OS_ defines are not set.
 #define OS_NACL 1
-// OS_NACL comes in two sandboxing technology flavors, SFI or Non-SFI.
-// PNaCl toolchain defines __native_client_nonsfi__ macro in Non-SFI build
-// mode, while it does not in SFI build mode.
-#if defined(__native_client_nonsfi__)
-#define OS_NACL_NONSFI
-#else
 #define OS_NACL_SFI
-#endif
 #elif defined(ANDROID)
 #define OS_ANDROID 1
 #elif defined(__APPLE__)
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 010268c..cdb9a62 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -579,7 +579,20 @@
     }
 
     cflags_c += [ "-std=${standard_prefix}11" ]
-    cflags_cc += [ "-std=${standard_prefix}++14" ]
+
+    # TODO(https://crbug.com/1273966): Use C++17 with is_cfi once
+    # https://chromium-review.googlesource.com/c/v8/v8/+/3304143/ is rolled in.
+    if ((is_nacl && !is_nacl_saigo) || is_cfi) {
+      # This is for the pnacl_newlib toolchain. It's only used to build
+      # a few independent ppapi test files that don't pull in any other
+      # dependencies.
+      cflags_cc += [
+        "-std=${standard_prefix}++14",
+        "-fno-trigraphs",
+      ]
+    } else {
+      cflags_cc += [ "-std=${standard_prefix}++17" ]
+    }
   } else if (is_win) {
     cflags_cc += [ "/std:c++17" ]
   } else if (!is_nacl) {
@@ -588,26 +601,46 @@
     # are still a few buildbots using it, so until those are turned off
     # we need the !is_nacl clause and the (is_nacl && is_clang) clause, above.
     cflags_c += [ "-std=c11" ]
-    cflags_cc += [ "-std=c++14" ]
+
+    if (is_apple) {
+      # TODO(thakis): Use C++17 on macOS and iOS once it works.
+      cflags_cc += [
+        "-std=c++14",
+        "-fno-trigraphs",
+      ]
+    } else {
+      cflags_cc += [ "-std=c++17" ]
+    }
   }
 
-  # C++17 removes trigraph support, so preemptively disable trigraphs. This is
-  # especially useful given the collision with ecmascript's logical assignment
-  # operators: https://github.com/tc39/proposal-logical-assignment
   if (is_clang && current_os != "zos") {
-    # clang-cl disables trigraphs by default
-    if (!is_win) {
-      # The gnu variants of C++11 and C++14 already disable trigraph support,
-      # but when building with clang, we use -std=c++11 / -std=c++14, which
-      # enables trigraph support: override that here.
-      cflags_cc += [ "-fno-trigraphs" ]
-    }
-
-    # Don't warn that trigraphs are ignored, since trigraphs are disabled
-    # anyway.
+    # C++17 removes trigraph support, but clang still warns that it ignores
+    # them when seeing them.  Don't.
     cflags_cc += [ "-Wno-trigraphs" ]
   }
 
+  # Before C++17, an `alignas(N)` type would be N-aligned on the stack,
+  # but heap allocation would just return something aligned to whatever the
+  # default allocator happens to return. Starting with C++17, operator new
+  # called on aligned types with N > __STDCPP_DEFAULT_NEW_ALIGNMENT__ will
+  # call a special overload that hands in the desired alignment, and that will
+  # honor the alignas even for memory on the stack.
+  # However, that requires that operator new overload to exist. At least on
+  # macOS and iOS, they are in libc++abi, and system libc++abi has them as of
+  # "macOS 10.12, iOS 10.0" (https://reviews.llvm.org/D112921#3128089).
+  # However, we do statically link libc++abi, so maybe just explicitly passing
+  # -faligned-allocation is enough to make things work.
+  # For now, explicitly disable this feature though to keep the C++14 aligned
+  # allocation behavior (and do that on all platforms so that we have
+  # consistent behavior across platforms), to make the change more incremental.
+  if (!is_nacl || is_nacl_saigo) {
+    if (is_win) {
+      cflags_cc += [ "/Zc:alignedNew-" ]
+    } else {
+      cflags_cc += [ "-fno-aligned-new" ]
+    }
+  }
+
   if (is_mac) {
     # The system libc++ on Mac doesn't have aligned allocation in C++17.
     defines += [ "_LIBCPP_HAS_NO_ALIGNED_ALLOCATION" ]
@@ -1126,33 +1159,6 @@
         ]
         ldflags += [ "-mips64r2" ]
       }
-    } else if (current_cpu == "pnacl" && is_nacl_nonsfi) {
-      if (target_cpu == "x86" || target_cpu == "x64") {
-        cflags += [
-          "-arch",
-          "x86-32-nonsfi",
-          "--pnacl-bias=x86-32-nonsfi",
-          "--target=i686-unknown-nacl",
-        ]
-        ldflags += [
-          "-arch",
-          "x86-32-nonsfi",
-          "--target=i686-unknown-nacl",
-        ]
-      } else if (target_cpu == "arm") {
-        cflags += [
-          "-arch",
-          "arm-nonsfi",
-          "-mfloat-abi=hard",
-          "--pnacl-bias=arm-nonsfi",
-          "--target=armv7-unknown-nacl-gnueabihf",
-        ]
-        ldflags += [
-          "-arch",
-          "arm-nonsfi",
-          "--target=armv7-unknown-nacl-gnueabihf",
-        ]
-      }
     } else if (current_cpu == "ppc64") {
       if (current_os == "aix") {
         cflags += [ "-maix64" ]
diff --git a/build/config/nacl/BUILD.gn b/build/config/nacl/BUILD.gn
index c0c5282..dfab7f7 100644
--- a/build/config/nacl/BUILD.gn
+++ b/build/config/nacl/BUILD.gn
@@ -17,7 +17,7 @@
     defines = [ "__STDC_LIMIT_MACROS=1" ]
   }
 
-  if (current_cpu == "pnacl" && !is_nacl_nonsfi) {
+  if (current_cpu == "pnacl") {
     # TODO: Remove the following definition once NACL_BUILD_ARCH and
     # NACL_BUILD_SUBARCH are defined by the PNaCl toolchain.
     defines += [ "NACL_BUILD_ARCH=pnacl" ]
@@ -73,29 +73,6 @@
     # everywhere for consistency (and possibly quicker builds).
     cflags += [ "-integrated-as" ]
   }
-  if (is_nacl_nonsfi) {
-    cflags += [ "--pnacl-allow-translate" ]
-    ldflags += [
-      "--pnacl-allow-translate",
-      "--pnacl-allow-native",
-      "-Wl,--noirt",
-      "-Wt,--noirt",
-      "-Wt,--noirtshim",
-
-      # The clang driver automatically injects -lpthread when using libc++, but
-      # the toolchain doesn't have it yet.  To get around this, use
-      # -nodefaultlibs and make each executable target depend on
-      # "//native_client/src/nonsfi/irt:nacl_sys_private".
-      "-nodefaultlibs",
-    ]
-    libs += [
-      "c++",
-      "m",
-      "c",
-      "pnaclmm",
-    ]
-    include_dirs = [ "//native_client/src/public/linux_syscalls" ]
-  }
 
   asmflags = cflags
 }
diff --git a/build/config/nacl/config.gni b/build/config/nacl/config.gni
index 6873055c..6e88fd2 100644
--- a/build/config/nacl/config.gni
+++ b/build/config/nacl/config.gni
@@ -16,7 +16,6 @@
 }
 
 is_nacl_irt = false
-is_nacl_nonsfi = false
 
 nacl_toolchain_dir = "//native_client/toolchain/${host_os}_x86"
 
@@ -54,8 +53,3 @@
 
 nacl_irt_toolchain = "//build/toolchain/nacl:irt_" + target_cpu
 is_nacl_irt = current_toolchain == nacl_irt_toolchain
-
-# Non-SFI mode is a lightweight sandbox used by Chrome OS for running ARC
-# applications.
-nacl_nonsfi_toolchain = "//build/toolchain/nacl:newlib_pnacl_nonsfi"
-is_nacl_nonsfi = current_toolchain == nacl_nonsfi_toolchain
diff --git a/build/config/nacl/rules.gni b/build/config/nacl/rules.gni
index 834c461..a15d3262 100644
--- a/build/config/nacl/rules.gni
+++ b/build/config/nacl/rules.gni
@@ -128,53 +128,3 @@
     }
   }
 }
-
-# Generate a nmf file for Non-SFI tests
-#
-# Non-SFI tests use a different manifest format from regular Native Client and
-# as such requires a different generator.
-#
-# Variables:
-#   executable: Non-SFI .nexe executable to generate nmf for
-#   nmf: the name and the path of the output file
-#   nmfflags: additional flags for the nmf generator
-template("generate_nonsfi_test_nmf") {
-  assert(defined(invoker.executable), "Must define executable")
-  assert(defined(invoker.nmf), "Must define nmf")
-
-  action(target_name) {
-    forward_variables_from(invoker,
-                           [
-                             "deps",
-                             "data_deps",
-                             "executable",
-                             "nmf",
-                             "testonly",
-                             "public_deps",
-                             "visibility",
-                           ])
-
-    script = "//ppapi/tests/create_nonsfi_test_nmf.py"
-    sources = [ executable ]
-    outputs = [ nmf ]
-
-    # NOTE: We use target_cpu rather than current_cpu on purpose because
-    # current_cpu is always going to be pnacl for Non-SFI, but the Non-SFI
-    # .nexe executable is always translated to run on the target machine.
-    if (target_cpu == "x86") {
-      arch = "x86-32"
-    } else if (target_cpu == "x64") {
-      arch = "x86-64"
-    } else {
-      arch = target_cpu
-    }
-    args = [
-      "--program=" + rebase_path(executable, root_build_dir),
-      "--arch=${arch}",
-      "--output=" + rebase_path(nmf, root_build_dir),
-    ]
-    if (defined(invoker.nmfflags)) {
-      args += invoker.nmfflags
-    }
-  }
-}
diff --git a/build/fuchsia/qemu_target_test.py b/build/fuchsia/qemu_target_test.py
index 44b3802..21006ffc 100755
--- a/build/fuchsia/qemu_target_test.py
+++ b/build/fuchsia/qemu_target_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python
 # 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.
diff --git a/build/nocompile.gni b/build/nocompile.gni
index 5b4aeb8f..db937ed5 100644
--- a/build/nocompile.gni
+++ b/build/nocompile.gni
@@ -96,7 +96,7 @@
         "-nostdinc++",
         "-isystem" + rebase_path("$libcxx_prefix/include", root_build_dir),
         "-isystem" + rebase_path("$libcxxabi_prefix/include", root_build_dir),
-        "-std=c++14",
+        "-std=c++17",
         "-Wall",
         "-Werror",
         "-Wfatal-errors",
diff --git a/build/print_python_deps.py b/build/print_python_deps.py
index e567834..d7218dc1 100755
--- a/build/print_python_deps.py
+++ b/build/print_python_deps.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2.7
+#!/usr/bin/env python2
 # 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.
diff --git a/build/toolchain/nacl/BUILD.gn b/build/toolchain/nacl/BUILD.gn
index 383d2b54..97f3da9 100644
--- a/build/toolchain/nacl/BUILD.gn
+++ b/build/toolchain/nacl/BUILD.gn
@@ -116,15 +116,6 @@
   strip = "finalize"
 }
 
-pnacl_toolchain("newlib_pnacl_nonsfi") {
-  executable_extension = ""
-  strip = "strip"
-
-  # This macro is embedded on nonsfi toolchains but reclient can't figure
-  # that out itself, so we make it explicit.
-  extra_cppflags = "-D__native_client_nonsfi__"
-}
-
 template("nacl_glibc_toolchain") {
   toolchain_cpu = target_name
   assert(defined(invoker.toolchain_tuple), "Must define toolchain_tuple")
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index d37ac6f7..7cfce806 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -1201,7 +1201,8 @@
             mRedirectHandler.updateNewUrlLoading(navigationParams.pageTransitionType,
                     navigationParams.isRedirect,
                     navigationParams.hasUserGesture || navigationParams.hasUserGestureCarryover,
-                    mLastUserInteractionTimeSupplier.get(), RedirectHandler.INVALID_ENTRY_INDEX);
+                    mLastUserInteractionTimeSupplier.get(), RedirectHandler.INVALID_ENTRY_INDEX,
+                    true /* isInitialNavigation */);
             ExternalNavigationParams params =
                     new ExternalNavigationParams
                             .Builder(navigationParams.url, false, navigationParams.referrer,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java
index e265a444..d23e511 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java
@@ -40,7 +40,8 @@
         if (!isOffTheRecord || !ChromeFeatureList.isEnabled(INCOGNITO_HISTORY_ENTRIES_FLAG)) {
             history.addEntry(new NavigationEntry(FULL_HISTORY_ENTRY_INDEX,
                     new GURL(UrlConstants.HISTORY_URL), GURL.emptyGURL(), GURL.emptyGURL(),
-                    GURL.emptyGURL(), mFullHistoryMenu, null, 0, 0));
+                    GURL.emptyGURL(), mFullHistoryMenu, null, 0, 0,
+                    /* isInitialEntry=*/false));
         }
         return history;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java b/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java
index 16f0bd1..e03aadb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java
@@ -69,7 +69,7 @@
         int DISABLED_BY_FEATURE = 6;
         int ALL_SATISFIED = 7;
 
-        int NUM_ENTRIES = 3;
+        int NUM_ENTRIES = 8;
     }
 
     private final Supplier<Intent> mIntentSupplier;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
index bb56978d..9d99a87 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
@@ -314,8 +314,7 @@
     @Test
     @MediumTest
     @Feature({"Navigation"})
-    @CommandLineFlags.
-    Add({"enable-features=UserAgentClientHint, FeaturePolicyForClientHints, CriticalClientHint"})
+    @CommandLineFlags.Add({"enable-features=UserAgentClientHint, CriticalClientHint"})
     // TODO(https://crbug.com/928669) Remove switch when UA-CH-* launched.
     public void testRequestDesktopSiteCriticalClientHints() throws Exception {
         // TODO(https://crbug.com/1138913): Move EchoCriticalHeader request handler here when
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java
index 2976810..f13677c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java
@@ -78,7 +78,7 @@
         public TestNavigationEntry(int index, GURL url, GURL virtualUrl, GURL originalUrl,
                 String title, Bitmap favicon, int transition, long timestamp) {
             super(index, url, virtualUrl, originalUrl, /*referrerUrl=*/null, title, favicon,
-                    transition, timestamp);
+                    transition, timestamp, /* isInitialEntry=*/false);
         }
     }
 
@@ -128,7 +128,7 @@
                         GURL.emptyGURL(),
                         mActivityTestRule.getActivity().getResources().getString(
                                 R.string.show_full_history),
-                        null, 0, 0));
+                        null, 0, 0, /* isInitialEntry=*/false));
             }
             return history;
         }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java
index 17cbecfc..e7744b85 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java
@@ -305,6 +305,7 @@
     @Test
     @LargeTest
     @Feature({"TabPersistentStore", "MultiWindow"})
+    @DisabledTest(message = "https://crbug.com/1275082")
     public void testMergeIntoChromeTabbedActivity1() {
         mergeTabsAndAssert(mActivity1, mMergeIntoActivity1ExpectedTabs);
         mActivity1.finishAndRemoveTask();
@@ -313,6 +314,7 @@
     @Test
     @LargeTest
     @Feature({"TabPersistentStore", "MultiWindow"})
+    @DisabledTest(message = "https://crbug.com/1275082")
     public void testMergeIntoChromeTabbedActivity2() {
         mergeTabsAndAssert(mActivity2, mMergeIntoActivity2ExpectedTabs);
         mActivity2.finishAndRemoveTask();
@@ -321,6 +323,7 @@
     @Test
     @LargeTest
     @Feature({"TabPersistentStore", "MultiWindow"})
+    @DisabledTest(message = "https://crbug.com/1275082")
     public void testMergeOnColdStart() {
         String expectedSelectedUrl = ChromeTabUtils.getUrlStringOnUiThread(
                 mActivity1.getTabModelSelector().getCurrentTab());
@@ -358,6 +361,7 @@
     @Test
     @LargeTest
     @Feature({"TabPersistentStore", "MultiWindow"})
+    @DisabledTest(message = "https://crbug.com/1275082")
     public void testMergeOnColdStartFromChromeTabbedActivity2() throws Exception {
         String expectedSelectedUrl = ChromeTabUtils.getUrlStringOnUiThread(
                 mActivity2.getTabModelSelector().getCurrentTab());
@@ -452,6 +456,7 @@
     @LargeTest
     @Feature({"TabPersistentStore", "MultiWindow"})
     @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+    @DisabledTest(message = "https://crbug.com/1275082")
     public void testMergeWhileInTabSwitcher() {
         OverviewModeBehaviorWatcher overviewModeWatcher = new OverviewModeBehaviorWatcher(
                 mActivity1.getLayoutManager(), true, false);
@@ -467,6 +472,7 @@
     @Test
     @LargeTest
     @Feature({"TabPersistentStore", "MultiWindow"})
+    @DisabledTest(message = "https://crbug.com/1275082")
     public void testMergeWithNoTabs() {
         // Enter the tab switcher before closing all tabs with grid tab switcher enabled, otherwise
         // the activity is killed and the test fails.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/NavigationPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/NavigationPopupTest.java
index bc8b0403..5433480a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/NavigationPopupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/NavigationPopupTest.java
@@ -63,7 +63,7 @@
         public TestNavigationEntry(int index, GURL url, GURL virtualUrl, GURL originalUrl,
                 String title, Bitmap favicon, int transition, long timestamp) {
             super(index, url, virtualUrl, originalUrl, GURL.emptyGURL(), title, favicon, transition,
-                    timestamp);
+                    timestamp, /* isInitialEntry=*/false);
         }
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigatorTest.java
index deb2ec5..74541d9 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigatorTest.java
@@ -104,8 +104,8 @@
         NavigationHistory history = new NavigationHistory();
 
         for (GURL url : urls) {
-            history.addEntry(new NavigationEntry(
-                    0, url, GURL.emptyGURL(), GURL.emptyGURL(), GURL.emptyGURL(), "", null, 0, 0));
+            history.addEntry(new NavigationEntry(0, url, GURL.emptyGURL(), GURL.emptyGURL(),
+                    GURL.emptyGURL(), "", null, 0, 0, /* isInitialEntry=*/false));
         }
 
         // Point to the most recent entry in history.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerTest.java
index 7705e71..147afdf 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerTest.java
@@ -268,6 +268,7 @@
      * @return A new {@link NavigationEntry}.
      */
     private NavigationEntry createNavigationEntry(int index, GURL url) {
-        return new NavigationEntry(index, url, url, url, url, "", null, 0, 0);
+        return new NavigationEntry(
+                index, url, url, url, url, "", null, 0, 0, /* isInitialEntry=*/false);
     }
 }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index eceb01e0..8419b3e 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -371,8 +371,11 @@
     "content_settings/sound_content_setting_observer.h",
     "crash_upload_list/crash_upload_list.cc",
     "crash_upload_list/crash_upload_list.h",
+    "custom_handlers/chrome_protocol_handler_registry_delegate.cc",
+    "custom_handlers/chrome_protocol_handler_registry_delegate.h",
     "custom_handlers/protocol_handler_registry.cc",
     "custom_handlers/protocol_handler_registry.h",
+    "custom_handlers/protocol_handler_registry.h",
     "custom_handlers/protocol_handler_registry_factory.cc",
     "custom_handlers/protocol_handler_registry_factory.h",
     "data_reduction_proxy/data_reduction_proxy_chrome_settings.cc",
@@ -6351,6 +6354,15 @@
         "signin/signin_util_win.h",
       ]
     }
+
+    # TODO(https://crbug.com/1198523: Remove this once enable_dice_support is no
+    # longer defined on Lacros.
+    if (is_chromeos_lacros) {
+      sources -= [
+        "signin/signin_manager_factory.cc",
+        "signin/signin_manager_factory.h",
+      ]
+    }
   }
 
   if (enable_media_remoting) {
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index e08431b7..9d7104d7 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -59,7 +59,6 @@
 #include "chrome/browser/sharing/shared_clipboard/feature_flags.h"
 #include "chrome/browser/sharing/sms/sms_flags.h"
 #include "chrome/browser/sharing_hub/sharing_hub_features.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/site_isolation/about_flags.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/unexpire_flags.h"
@@ -6036,11 +6035,6 @@
      FEATURE_VALUE_TYPE(ash::features::kSettingsAppNotificationSettings)},
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-    {"decode-jpeg-images-to-yuv",
-     flag_descriptions::kDecodeJpeg420ImagesToYUVName,
-     flag_descriptions::kDecodeJpeg420ImagesToYUVDescription, kOsAll,
-     FEATURE_VALUE_TYPE(blink::features::kDecodeJpeg420ImagesToYUV)},
-
     {"dns-httpssvc", flag_descriptions::kDnsHttpssvcName,
      flag_descriptions::kDnsHttpssvcDescription,
      kOsMac | kOsWin | kOsCrOS | kOsAndroid,
@@ -7470,13 +7464,6 @@
      FEATURE_VALUE_TYPE(share::kShareMenu)},
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-    {"multi-profile-account-consistency",
-     flag_descriptions::kMultiProfileAccountConsistencyName,
-     flag_descriptions::kMultiProfileAccountConsistencyDescription, kOsLinux,
-     FEATURE_VALUE_TYPE(kMultiProfileAccountConsistency)},
-#endif
-
     {"enable-drdc", flag_descriptions::kEnableDrDcName,
      flag_descriptions::kEnableDrDcDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kEnableDrDc)},
diff --git a/chrome/browser/android/vr/vr_shell.cc b/chrome/browser/android/vr/vr_shell.cc
index eef94c82..5f66857b 100644
--- a/chrome/browser/android/vr/vr_shell.cc
+++ b/chrome/browser/android/vr/vr_shell.cc
@@ -975,7 +975,7 @@
 
 bool VrShell::ShouldDisplayURL() const {
   content::NavigationEntry* entry = GetNavigationEntry();
-  if (!entry) {
+  if (!entry || entry->IsInitialEntry()) {
     return ChromeLocationBarModelDelegate::ShouldDisplayURL();
   }
   GURL url = entry->GetVirtualURL();
diff --git a/chrome/browser/apps/app_service/browser_app_instance_tracker.cc b/chrome/browser/apps/app_service/browser_app_instance_tracker.cc
index 8a73c64..6eb0be42 100644
--- a/chrome/browser/apps/app_service/browser_app_instance_tracker.cc
+++ b/chrome/browser/apps/app_service/browser_app_instance_tracker.cc
@@ -275,9 +275,6 @@
     }
 #endif
     if (tab_is_new) {
-      webcontents_to_observer_map_[contents] =
-          std::make_unique<BrowserAppInstanceTracker::WebContentsObserver>(
-              contents, this);
       OnTabCreated(browser, contents);
     }
     OnTabAttached(browser, contents);
@@ -318,10 +315,6 @@
     if (tab_will_be_closed) {
       OnTabClosing(browser, contents);
     }
-    if (tab_will_be_closed) {
-      DCHECK(base::Contains(webcontents_to_observer_map_, contents));
-      webcontents_to_observer_map_.erase(contents);
-    }
   }
   // Last tab detached.
   if (browser->tab_strip_model()->count() == 0) {
@@ -366,7 +359,8 @@
   }
 
   tracked_browsers_.insert(browser);
-  if (browser->is_type_normal() || browser->is_type_devtools()) {
+  if (browser->is_type_normal() || browser->is_type_popup() ||
+      browser->is_type_devtools()) {
     CreateWindowInstance(browser);
   }
 }
@@ -385,6 +379,10 @@
 
 void BrowserAppInstanceTracker::OnTabCreated(Browser* browser,
                                              content::WebContents* contents) {
+  webcontents_to_observer_map_[contents] =
+      std::make_unique<BrowserAppInstanceTracker::WebContentsObserver>(contents,
+                                                                       this);
+
   std::string app_id = GetAppId(contents);
   if (!app_id.empty()) {
     CreateAppInstance(std::move(app_id), browser, contents);
@@ -423,6 +421,8 @@
 void BrowserAppInstanceTracker::OnTabClosing(Browser* browser,
                                              content::WebContents* contents) {
   RemoveAppInstanceIfExists(contents);
+  DCHECK(base::Contains(webcontents_to_observer_map_, contents));
+  webcontents_to_observer_map_.erase(contents);
 }
 
 void BrowserAppInstanceTracker::OnWebContentsUpdated(
diff --git a/chrome/browser/apps/app_service/browser_app_instance_tracker_browsertest.cc b/chrome/browser/apps/app_service/browser_app_instance_tracker_browsertest.cc
index b4aff41..b759ea7 100644
--- a/chrome/browser/apps/app_service/browser_app_instance_tracker_browsertest.cc
+++ b/chrome/browser/apps/app_service/browser_app_instance_tracker_browsertest.cc
@@ -230,6 +230,15 @@
     return browser;
   }
 
+  Browser* CreatePopupBrowser() {
+    Profile* profile = ProfileManager::GetPrimaryUserProfile();
+    Browser::CreateParams params(profile, true /* user_gesture */);
+    params.type = Browser::TYPE_POPUP;
+    Browser* browser = Browser::Create(params);
+    browser->window()->Show();
+    return browser;
+  }
+
   Browser* CreateAppBrowser(const std::string& app_id) {
     Profile* profile = ProfileManager::GetPrimaryUserProfile();
     auto params = Browser::CreateParams::CreateForApp(
@@ -439,6 +448,66 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_F(BrowserAppInstanceTrackerTest, PopupBrowserWindow) {
+  Browser* browser = nullptr;
+  aura::Window* window = nullptr;
+
+  {
+    SCOPED_TRACE("open popup browser window");
+    Recorder recorder(*tracker_);
+
+    browser = CreatePopupBrowser();
+    window = browser->window()->GetNativeWindow();
+    InsertForegroundTab(browser, "https://c.example.org");
+
+    recorder.Verify({
+        {"added", 1, kChromeWindow, "", window, "", kActive, false},
+    });
+  }
+
+  {
+    SCOPED_TRACE("close popup browser window");
+    Recorder recorder(*tracker_);
+
+    browser->tab_strip_model()->CloseAllTabs();
+
+    recorder.Verify({
+        {"removed", 1, kChromeWindow, "", window, "", kActive, false},
+    });
+  }
+
+  {
+    // Happens when an app running in a browser tab opens a separate popup
+    // window: it's not of type Browser::TYPE_APP_POPUP, but the window contains
+    // an instance of this app.
+    SCOPED_TRACE("open popup browser window with app tab");
+    Recorder recorder(*tracker_);
+
+    browser = CreatePopupBrowser();
+    window = browser->window()->GetNativeWindow();
+    InsertForegroundTab(browser, "https://a.example.org");
+
+    recorder.Verify({
+        {"added", 2, kChromeWindow, "", window, "", kActive, false},
+        {"added", 3, kAppTab, kAppId_A, window, "", kActive, kActive},
+        {"updated", 3, kAppTab, kAppId_A, window, kURL_A, kActive, kActive},
+        {"updated", 3, kAppTab, kAppId_A, window, kTitle_A, kActive, kActive},
+    });
+  }
+
+  {
+    SCOPED_TRACE("close popup browser window with app tab");
+    Recorder recorder(*tracker_);
+
+    browser->tab_strip_model()->CloseAllTabs();
+
+    recorder.Verify({
+        {"removed", 3, kAppTab, kAppId_A, window, kTitle_A, kActive, kActive},
+        {"removed", 2, kChromeWindow, "", window, "", kActive, false},
+    });
+  }
+}
+
 IN_PROC_BROWSER_TEST_F(BrowserAppInstanceTrackerTest, DevtoolsWindow) {
   Browser* browser = CreateBrowser();
   InsertForegroundTab(browser, "https://c.example.org");
@@ -857,6 +926,8 @@
   });
 }
 
+// TODO(crbug.com/1220420): test tab replace (portals)
+
 IN_PROC_BROWSER_TEST_F(BrowserAppInstanceTrackerTest, Accessors) {
   // Setup: two regular browsers, and one app window browser.
   auto* browser1 = CreateBrowser();
diff --git a/chrome/browser/apps/app_service/publishers/extension_apps_base.cc b/chrome/browser/apps/app_service/publishers/extension_apps_base.cc
index 5156e34..eaf22f5 100644
--- a/chrome/browser/apps/app_service/publishers/extension_apps_base.cc
+++ b/chrome/browser/apps/app_service/publishers/extension_apps_base.cc
@@ -386,7 +386,17 @@
 
 void ExtensionAppsBase::LaunchAppWithParams(AppLaunchParams&& params,
                                             LaunchCallback callback) {
-  LaunchImpl(std::move(params));
+  auto event_flags = apps::GetEventFlags(params.container, params.disposition,
+                                         /*prefer_container=*/false);
+  auto window_info = apps::MakeWindowInfo(params.display_id);
+  if (params.intent) {
+    LaunchAppWithIntent(params.app_id, event_flags, std::move(params.intent),
+                        params.launch_source, std::move(window_info),
+                        base::DoNothing());
+  } else {
+    Launch(params.app_id, event_flags, params.launch_source,
+           std::move(window_info));
+  }
   // TODO(crbug.com/1244506): Add launch return value.
   std::move(callback).Run(LaunchResult());
 }
diff --git a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
index fd7fdcd7..34f18ac 100644
--- a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
+++ b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
@@ -202,20 +202,8 @@
                &display_mode](const apps::AppUpdate& update) {
         is_system_web_app =
             update.InstallReason() == apps::mojom::InstallReason::kSystem;
-        // TODO(1258432): Clean up common logic between ash/lacros.
-        switch (update.InstallReason()) {
-          case apps::mojom::InstallReason::kDefault:
-          case apps::mojom::InstallReason::kSync:
-          case apps::mojom::InstallReason::kUser:
-            can_use_uninstall = true;
-            break;
-          case apps::mojom::InstallReason::kSystem:
-          case apps::mojom::InstallReason::kPolicy:
-          case apps::mojom::InstallReason::kOem:
-          case apps::mojom::InstallReason::kSubApp:
-          case apps::mojom::InstallReason::kUnknown:
-            can_use_uninstall = false;
-        }
+        can_use_uninstall =
+            update.AllowUninstall() == apps::mojom::OptionalBool::kTrue;
         display_mode = update.WindowMode();
       });
 
diff --git a/chrome/browser/ash/account_manager/account_apps_availability.cc b/chrome/browser/ash/account_manager/account_apps_availability.cc
new file mode 100644
index 0000000..01394690
--- /dev/null
+++ b/chrome/browser/ash/account_manager/account_apps_availability.cc
@@ -0,0 +1,22 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/account_manager/account_apps_availability.h"
+
+#include "ash/constants/ash_features.h"
+#include "base/feature_list.h"
+
+namespace ash {
+
+AccountAppsAvailability::AccountAppsAvailability() = default;
+AccountAppsAvailability::~AccountAppsAvailability() = default;
+
+// static
+bool AccountAppsAvailability::IsArcAccountRestrictionsEnabled() {
+  return base::FeatureList::IsEnabled(
+             chromeos::features::kArcAccountRestrictions) &&
+         base::FeatureList::IsEnabled(chromeos::features::kLacrosSupport);
+}
+
+}  // namespace ash
diff --git a/chrome/browser/ash/account_manager/account_apps_availability.h b/chrome/browser/ash/account_manager/account_apps_availability.h
new file mode 100644
index 0000000..ae76e11
--- /dev/null
+++ b/chrome/browser/ash/account_manager/account_apps_availability.h
@@ -0,0 +1,34 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_ACCOUNT_MANAGER_ACCOUNT_APPS_AVAILABILITY_H_
+#define CHROME_BROWSER_ASH_ACCOUNT_MANAGER_ACCOUNT_APPS_AVAILABILITY_H_
+
+#include "components/keyed_service/core/keyed_service.h"
+
+namespace ash {
+
+// This class is tracking which accounts from `AccountManager` should be
+// available in apps. Currently only availability in ARC++ is being tracked.
+// ARC++ availability may be set just after account addition or when user
+// changes it manually in OS Settings.
+// There should be only one instance of this class, which is attached to the
+// only regular Ash profile. The class should exist only if Account Manager
+// exists (if `ash::IsAccountManagerAvailable(profile)` is `true`).
+class AccountAppsAvailability : public KeyedService {
+ public:
+  AccountAppsAvailability();
+  ~AccountAppsAvailability() override;
+
+  AccountAppsAvailability(const AccountAppsAvailability&) = delete;
+  AccountAppsAvailability& operator=(const AccountAppsAvailability&) = delete;
+
+  // Returns `true` if `kArcAccountRestrictions` and `kLacrosSupport` are
+  // enabled.
+  static bool IsArcAccountRestrictionsEnabled();
+};
+
+}  // namespace ash
+
+#endif  // CHROME_BROWSER_ASH_ACCOUNT_MANAGER_ACCOUNT_APPS_AVAILABILITY_H_
diff --git a/chrome/browser/ash/account_manager/account_apps_availability_factory.cc b/chrome/browser/ash/account_manager/account_apps_availability_factory.cc
new file mode 100644
index 0000000..03c90cb
--- /dev/null
+++ b/chrome/browser/ash/account_manager/account_apps_availability_factory.cc
@@ -0,0 +1,47 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/account_manager/account_apps_availability_factory.h"
+
+#include "chrome/browser/ash/account_manager/account_apps_availability.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/browser_context.h"
+
+namespace ash {
+
+// static
+AccountAppsAvailabilityFactory* AccountAppsAvailabilityFactory::GetInstance() {
+  static base::NoDestructor<AccountAppsAvailabilityFactory> factory;
+  return factory.get();
+}
+
+// static
+AccountAppsAvailability* AccountAppsAvailabilityFactory::GetForProfile(
+    Profile* profile) {
+  return static_cast<AccountAppsAvailability*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+AccountAppsAvailabilityFactory::AccountAppsAvailabilityFactory()
+    : BrowserContextKeyedServiceFactory(
+          "AccountAppsAvailability",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+AccountAppsAvailabilityFactory::~AccountAppsAvailabilityFactory() = default;
+
+KeyedService* AccountAppsAvailabilityFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new AccountAppsAvailability();
+}
+
+bool AccountAppsAvailabilityFactory::ServiceIsCreatedWithBrowserContext()
+    const {
+  // To ensure the class is always tracking accounts in Account Manager.
+  return true;
+}
+
+}  // namespace ash
diff --git a/chrome/browser/ash/account_manager/account_apps_availability_factory.h b/chrome/browser/ash/account_manager/account_apps_availability_factory.h
new file mode 100644
index 0000000..1d5dbfed
--- /dev/null
+++ b/chrome/browser/ash/account_manager/account_apps_availability_factory.h
@@ -0,0 +1,48 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_ACCOUNT_MANAGER_ACCOUNT_APPS_AVAILABILITY_FACTORY_H_
+#define CHROME_BROWSER_ASH_ACCOUNT_MANAGER_ACCOUNT_APPS_AVAILABILITY_FACTORY_H_
+
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+#include "base/no_destructor.h"
+
+class Profile;
+class KeyedService;
+
+namespace content {
+class BrowserContext;
+}
+
+namespace ash {
+
+class AccountAppsAvailability;
+
+class AccountAppsAvailabilityFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  static AccountAppsAvailabilityFactory* GetInstance();
+  static AccountAppsAvailability* GetForProfile(Profile* profile);
+
+  AccountAppsAvailabilityFactory(const AccountAppsAvailabilityFactory&) =
+      delete;
+  AccountAppsAvailabilityFactory& operator=(
+      const AccountAppsAvailabilityFactory&) = delete;
+
+ private:
+  friend class base::NoDestructor<AccountAppsAvailabilityFactory>;
+
+  AccountAppsAvailabilityFactory();
+  ~AccountAppsAvailabilityFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+  bool ServiceIsCreatedWithBrowserContext() const override;
+};
+
+}  // namespace ash
+
+#endif  // CHROME_BROWSER_ASH_ACCOUNT_MANAGER_ACCOUNT_APPS_AVAILABILITY_FACTORY_H_
diff --git a/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.h b/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.h
index 2111c91..aa96bd3 100644
--- a/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.h
+++ b/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.h
@@ -15,6 +15,7 @@
 #include <unordered_set>
 #include <vector>
 
+#include "ash/components/arc/mojom/bluetooth.mojom.h"
 #include "ash/components/arc/session/connection_observer.h"
 #include "base/callback_forward.h"
 #include "base/containers/unique_ptr_adapters.h"
@@ -23,7 +24,6 @@
 #include "base/threading/thread_checker.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/ash/arc/bluetooth/arc_bluetooth_task_queue.h"
-#include "components/arc/mojom/bluetooth.mojom.h"
 #include "components/arc/mojom/intent_helper.mojom-forward.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "device/bluetooth/bluetooth_adapter.h"
diff --git a/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge_unittest.cc b/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge_unittest.cc
index e37b571..4aa9f5e 100644
--- a/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge_unittest.cc
+++ b/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge_unittest.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "ash/components/arc/bluetooth/bluetooth_type_converters.h"
+#include "ash/components/arc/mojom/bluetooth.mojom.h"
 #include "ash/components/arc/session/arc_bridge_service.h"
 #include "ash/components/arc/test/connection_holder_util.h"
 #include "ash/components/arc/test/fake_bluetooth_instance.h"
@@ -18,7 +19,6 @@
 #include "base/system/sys_info.h"
 #include "base/test/scoped_chromeos_version_info.h"
 #include "base/test/task_environment.h"
-#include "components/arc/mojom/bluetooth.mojom.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
 #include "device/bluetooth/dbus/fake_bluetooth_adapter_client.h"
 #include "device/bluetooth/dbus/fake_bluetooth_device_client.h"
diff --git a/chrome/browser/ash/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h b/chrome/browser/ash/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h
index 5eb330b..b23b879f 100644
--- a/chrome/browser/ash/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h
+++ b/chrome/browser/ash/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h"
+#include "ash/components/arc/mojom/boot_phase_monitor.mojom.h"
 #include "base/memory/singleton.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
@@ -17,7 +18,6 @@
 #include "chrome/browser/ash/arc/session/arc_session_manager_observer.h"
 #include "chrome/browser/sessions/session_restore_observer.h"
 #include "components/account_id/account_id.h"
-#include "components/arc/mojom/boot_phase_monitor.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 namespace content {
diff --git a/chrome/browser/ash/arc/cast_receiver/arc_cast_receiver_service.cc b/chrome/browser/ash/arc/cast_receiver/arc_cast_receiver_service.cc
index 983e6e01..6c11f73 100644
--- a/chrome/browser/ash/arc/cast_receiver/arc_cast_receiver_service.cc
+++ b/chrome/browser/ash/arc/cast_receiver/arc_cast_receiver_service.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h"
+#include "ash/components/arc/mojom/cast_receiver.mojom.h"
 #include "ash/components/arc/session/arc_bridge_service.h"
 #include "ash/components/arc/session/connection_observer.h"
 #include "base/bind.h"
@@ -15,7 +16,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
-#include "components/arc/mojom/cast_receiver.mojom.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
 
diff --git a/chrome/browser/ash/arc/cast_receiver/arc_cast_receiver_service.h b/chrome/browser/ash/arc/cast_receiver/arc_cast_receiver_service.h
index 6cb48414..83454f83 100644
--- a/chrome/browser/ash/arc/cast_receiver/arc_cast_receiver_service.h
+++ b/chrome/browser/ash/arc/cast_receiver/arc_cast_receiver_service.h
@@ -7,9 +7,9 @@
 
 #include <memory>
 
+#include "ash/components/arc/mojom/cast_receiver.mojom-forward.h"
 #include "ash/components/arc/session/connection_observer.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
-#include "components/arc/mojom/cast_receiver.mojom-forward.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 namespace content {
diff --git a/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc b/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc
index 55bc0ab8..a672ac1 100644
--- a/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc
+++ b/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc
@@ -10,6 +10,7 @@
 #include "ash/components/arc/arc_features.h"
 #include "ash/components/arc/arc_prefs.h"
 #include "ash/components/arc/arc_util.h"
+#include "ash/components/arc/mojom/backup_settings.mojom.h"
 #include "ash/components/arc/session/arc_bridge_service.h"
 #include "ash/components/settings/timezone_settings.h"
 #include "ash/constants/ash_pref_names.h"
@@ -40,7 +41,6 @@
 #include "chromeos/network/onc/onc_utils.h"
 #include "chromeos/network/proxy/proxy_config_service_impl.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
-#include "components/arc/mojom/backup_settings.mojom.h"
 #include "components/arc/mojom/pip.mojom.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/onc/onc_pref_names.h"
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn
index c9dedfbf..7fba70d 100644
--- a/chrome/browser/ash/crosapi/BUILD.gn
+++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -8,6 +8,27 @@
 assert(is_chromeos_ash)
 assert(use_ozone)
 
+source_set("browser_util") {
+  sources = [
+    "browser_util.cc",
+    "browser_util.h",
+  ]
+
+  deps = [
+    "//ash/constants",
+    "//base",
+    "//chrome/browser:browser_process",
+    "//chrome/common",
+    "//chromeos/crosapi/cpp",
+    "//chromeos/crosapi/mojom",
+    "//components/exo",
+    "//components/prefs",
+    "//components/user_manager",
+    "//components/version_info",
+    "//google_apis",
+  ]
+}
+
 source_set("crosapi") {
   sources = [
     "arc_ash.cc",
@@ -28,8 +49,6 @@
     "browser_service_host_ash.cc",
     "browser_service_host_ash.h",
     "browser_service_host_observer.h",
-    "browser_util.cc",
-    "browser_util.h",
     "browser_version_service_ash.cc",
     "browser_version_service_ash.h",
     "cert_database_ash.cc",
@@ -47,6 +66,8 @@
     "crosapi_id.h",
     "crosapi_manager.cc",
     "crosapi_manager.h",
+    "crosapi_util.cc",
+    "crosapi_util.h",
     "device_attributes_ash.cc",
     "device_attributes_ash.h",
     "device_settings_ash.cc",
@@ -203,6 +224,8 @@
   # depend on //chrome/browser/chromeos. However, that creates a circular
   # dependency, so add this indirect dependency to make it work as intended.
   deps += [ "//ash/webui/print_management/mojom" ]
+
+  public_deps = [ ":browser_util" ]
 }
 
 source_set("test_support") {
@@ -235,6 +258,7 @@
     "browser_util_unittest.cc",
     "browser_version_service_ash_unittest.cc",
     "chrome_app_window_tracker_ash_unittest.cc",
+    "crosapi_util_unittest.cc",
     "download_controller_ash_unittest.cc",
     "fake_migration_progress_tracker.h",
     "field_trial_service_ash_unittest.cc",
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator.cc b/chrome/browser/ash/crosapi/browser_data_migrator.cc
index 0a7a0378..27095440 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator.cc
+++ b/chrome/browser/ash/crosapi/browser_data_migrator.cc
@@ -31,6 +31,7 @@
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
@@ -102,9 +103,6 @@
                                                "Top Sites",
                                                "Shortcuts",
                                                "Sessions"};
-// `First Run` is the only file that should be copied to lacros from user data
-// directory (parent directory of profile directory).
-const char* const kFirstRun = "First Run";
 // Flag values for `switches::kForceBrowserDataMigrationForTesting`.
 const char kBrowserDataMigrationForceSkip[] = "force-skip";
 const char kBrowserDataMigrationForceMigration[] = "force-migration";
@@ -768,12 +766,10 @@
                        progress_tracker))
     return false;
 
-  // Copy `First Run` in user data directory.
-  const base::FilePath first_run_file = from_dir.DirName().Append(kFirstRun);
-  if (base::PathExists(first_run_file)) {
-    if (!base::CopyFile(first_run_file, tmp_dir.Append(kFirstRun)))
-      return false;
-  }
+  // Create `First Run` sentinel file instead of copying. This avoids copying
+  // from outside of cryptohome.
+  if (!base::WriteFile(tmp_dir.Append(chrome::kFirstRunSentinel), ""))
+    return false;
 
   return true;
 }
diff --git a/chrome/browser/ash/crosapi/browser_manager.cc b/chrome/browser/ash/crosapi/browser_manager.cc
index a34dec7..e13c8b6 100644
--- a/chrome/browser/ash/crosapi/browser_manager.cc
+++ b/chrome/browser/ash/crosapi/browser_manager.cc
@@ -43,7 +43,6 @@
 #include "chrome/browser/ash/crosapi/browser_data_migrator.h"
 #include "chrome/browser/ash/crosapi/browser_loader.h"
 #include "chrome/browser/ash/crosapi/browser_service_host_ash.h"
-#include "chrome/browser/ash/crosapi/browser_util.h"
 #include "chrome/browser/ash/crosapi/crosapi_ash.h"
 #include "chrome/browser/ash/crosapi/crosapi_manager.h"
 #include "chrome/browser/ash/crosapi/environment_provider.h"
diff --git a/chrome/browser/ash/crosapi/browser_manager.h b/chrome/browser/ash/crosapi/browser_manager.h
index 2b45809..c6b4da3 100644
--- a/chrome/browser/ash/crosapi/browser_manager.h
+++ b/chrome/browser/ash/crosapi/browser_manager.h
@@ -21,6 +21,7 @@
 #include "chrome/browser/ash/crosapi/browser_service_host_observer.h"
 #include "chrome/browser/ash/crosapi/browser_util.h"
 #include "chrome/browser/ash/crosapi/crosapi_id.h"
+#include "chrome/browser/ash/crosapi/crosapi_util.h"
 #include "chrome/browser/ash/crosapi/environment_provider.h"
 #include "chromeos/crosapi/mojom/crosapi.mojom.h"
 #include "components/component_updater/component_updater_service.h"
diff --git a/chrome/browser/ash/crosapi/browser_util.cc b/chrome/browser/ash/crosapi/browser_util.cc
index ef67cfdf..e82f7cd1 100644
--- a/chrome/browser/ash/crosapi/browser_util.cc
+++ b/chrome/browser/ash/crosapi/browser_util.cc
@@ -4,103 +4,27 @@
 
 #include "chrome/browser/ash/crosapi/browser_util.h"
 
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <utility>
-
 #include "ash/constants/ash_features.h"
-#include "ash/constants/ash_pref_names.h"
 #include "ash/constants/ash_switches.h"
-#include "base/callback.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/containers/fixed_flat_map.h"
 #include "base/containers/flat_map.h"
-#include "base/cxx17_backports.h"
-#include "base/feature_list.h"
-#include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
 #include "base/path_service.h"
-#include "base/process/process_handle.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
 #include "base/system/sys_info.h"
 #include "base/values.h"
 #include "base/version.h"
-#include "chrome/browser/ash/crosapi/browser_version_service_ash.h"
-#include "chrome/browser/ash/crosapi/field_trial_service_ash.h"
-#include "chrome/browser/ash/crosapi/idle_service_ash.h"
-#include "chrome/browser/ash/crosapi/native_theme_service_ash.h"
-#include "chrome/browser/ash/crosapi/resource_manager_ash.h"
-#include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chrome/browser/ash/settings/cros_settings.h"
-#include "chrome/browser/ash/settings/device_settings_service.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/policy/profile_policy_connector.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
-#include "chrome/browser/web_applications/web_app_utils.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
-#include "chrome/common/pref_names.h"
-#include "chromeos/components/cdm_factory_daemon/mojom/browser_cdm_factory.mojom.h"
-#include "chromeos/components/sensors/mojom/cros_sensor_service.mojom.h"
 #include "chromeos/crosapi/cpp/crosapi_constants.h"
-#include "chromeos/crosapi/mojom/app_service.mojom.h"
-#include "chromeos/crosapi/mojom/app_window_tracker.mojom.h"
-#include "chromeos/crosapi/mojom/arc.mojom.h"
-#include "chromeos/crosapi/mojom/authentication.mojom.h"
-#include "chromeos/crosapi/mojom/automation.mojom.h"
-#include "chromeos/crosapi/mojom/browser_app_instance_registry.mojom.h"
-#include "chromeos/crosapi/mojom/cert_database.mojom.h"
-#include "chromeos/crosapi/mojom/clipboard.mojom.h"
-#include "chromeos/crosapi/mojom/clipboard_history.mojom.h"
-#include "chromeos/crosapi/mojom/content_protection.mojom.h"
 #include "chromeos/crosapi/mojom/crosapi.mojom.h"
-#include "chromeos/crosapi/mojom/device_attributes.mojom.h"
-#include "chromeos/crosapi/mojom/device_settings_service.mojom.h"
-#include "chromeos/crosapi/mojom/download_controller.mojom.h"
-#include "chromeos/crosapi/mojom/drive_integration_service.mojom.h"
-#include "chromeos/crosapi/mojom/feedback.mojom.h"
-#include "chromeos/crosapi/mojom/file_manager.mojom.h"
-#include "chromeos/crosapi/mojom/force_installed_tracker.mojom.h"
-#include "chromeos/crosapi/mojom/geolocation.mojom.h"
-#include "chromeos/crosapi/mojom/holding_space_service.mojom.h"
-#include "chromeos/crosapi/mojom/identity_manager.mojom.h"
-#include "chromeos/crosapi/mojom/image_writer.mojom.h"
-#include "chromeos/crosapi/mojom/keystore_service.mojom.h"
-#include "chromeos/crosapi/mojom/kiosk_session_service.mojom.h"
-#include "chromeos/crosapi/mojom/local_printer.mojom.h"
-#include "chromeos/crosapi/mojom/login_state.mojom.h"
-#include "chromeos/crosapi/mojom/message_center.mojom.h"
-#include "chromeos/crosapi/mojom/metrics_reporting.mojom.h"
-#include "chromeos/crosapi/mojom/network_settings_service.mojom.h"
-#include "chromeos/crosapi/mojom/networking_attributes.mojom.h"
-#include "chromeos/crosapi/mojom/policy_service.mojom.h"
-#include "chromeos/crosapi/mojom/power.mojom.h"
-#include "chromeos/crosapi/mojom/prefs.mojom.h"
-#include "chromeos/crosapi/mojom/remoting.mojom.h"
-#include "chromeos/crosapi/mojom/screen_manager.mojom.h"
-#include "chromeos/crosapi/mojom/structured_metrics_service.mojom.h"
-#include "chromeos/crosapi/mojom/system_display.mojom.h"
-#include "chromeos/crosapi/mojom/task_manager.mojom.h"
-#include "chromeos/crosapi/mojom/test_controller.mojom.h"
-#include "chromeos/crosapi/mojom/tts.mojom.h"
-#include "chromeos/crosapi/mojom/url_handler.mojom.h"
-#include "chromeos/crosapi/mojom/video_capture.mojom.h"
-#include "chromeos/crosapi/mojom/web_page_info.mojom.h"
-#include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
-#include "components/account_id/account_id.h"
-#include "components/account_manager_core/account.h"
-#include "components/account_manager_core/account_manager_util.h"
 #include "components/exo/shell_surface_util.h"
-#include "components/metrics/metrics_pref_names.h"
-#include "components/metrics/metrics_service.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/policy_constants.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -108,21 +32,10 @@
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
-#include "components/user_manager/user_type.h"
 #include "components/version_info/channel.h"
 #include "components/version_info/version_info.h"
 #include "google_apis/gaia/gaia_auth_util.h"
-#include "media/capture/mojom/video_capture.mojom.h"
-#include "media/media_buildflags.h"
-#include "media/mojo/mojom/stable/stable_video_decoder.mojom.h"
-#include "mojo/public/cpp/platform/platform_channel.h"
-#include "mojo/public/cpp/system/invitation.h"
-#include "services/device/public/mojom/hid.mojom.h"
-#include "services/media_session/public/mojom/audio_focus.mojom.h"
-#include "services/media_session/public/mojom/media_controller.mojom.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 
-using MojoOptionalBool = crosapi::mojom::DeviceSettings::OptionalBool;
 using user_manager::User;
 using version_info::Channel;
 
@@ -235,133 +148,6 @@
   }
 }
 
-// Returns the vector containing policy data of the device account. In case of
-// an error, returns nullopt.
-absl::optional<std::vector<uint8_t>> GetDeviceAccountPolicy(
-    EnvironmentProvider* environment_provider) {
-  if (!user_manager::UserManager::IsInitialized()) {
-    LOG(ERROR) << "User not initialized.";
-    return absl::nullopt;
-  }
-  const auto* primary_user = user_manager::UserManager::Get()->GetPrimaryUser();
-  if (!primary_user) {
-    LOG(ERROR) << "No primary user.";
-    return absl::nullopt;
-  }
-  std::string policy_data = environment_provider->GetDeviceAccountPolicy();
-  return std::vector<uint8_t>(policy_data.begin(), policy_data.end());
-}
-
-// Returns the device specific data needed for Lacros.
-mojom::DevicePropertiesPtr GetDeviceProperties() {
-  mojom::DevicePropertiesPtr result = mojom::DeviceProperties::New();
-  result->device_dm_token = "";
-
-  if (ash::DeviceSettingsService::IsInitialized()) {
-    const enterprise_management::PolicyData* policy_data =
-        ash::DeviceSettingsService::Get()->policy_data();
-
-    if (policy_data && policy_data->has_request_token())
-      result->device_dm_token = policy_data->request_token();
-
-    if (policy_data && !policy_data->device_affiliation_ids().empty()) {
-      const auto& ids = policy_data->device_affiliation_ids();
-      result->device_affiliation_ids = {ids.begin(), ids.end()};
-    }
-  }
-
-  return result;
-}
-
-struct InterfaceVersionEntry {
-  base::Token uuid;
-  uint32_t version;
-};
-
-template <typename T>
-constexpr InterfaceVersionEntry MakeInterfaceVersionEntry() {
-  return {T::Uuid_, T::Version_};
-}
-
-constexpr InterfaceVersionEntry kInterfaceVersionEntries[] = {
-    MakeInterfaceVersionEntry<chromeos::cdm::mojom::BrowserCdmFactory>(),
-    MakeInterfaceVersionEntry<chromeos::sensors::mojom::SensorHalClient>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::Arc>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::Authentication>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::Automation>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::AccountManager>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::AppPublisher>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::AppServiceProxy>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::AppWindowTracker>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::BrowserAppInstanceRegistry>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::BrowserServiceHost>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::BrowserVersionService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::CertDatabase>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::Clipboard>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::ClipboardHistory>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::ContentProtection>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::Crosapi>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::DeviceAttributes>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::DeviceSettingsService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::DownloadController>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::DriveIntegrationService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::Feedback>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::FieldTrialService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::FileManager>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::ForceInstalledTracker>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::GeolocationService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::HoldingSpaceService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::IdentityManager>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::IdleService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::ImageWriter>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::KeystoreService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::KioskSessionService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::LocalPrinter>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::LoginState>(),
-    MakeInterfaceVersionEntry<
-        chromeos::machine_learning::mojom::MachineLearningService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::MessageCenter>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::MetricsReporting>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::NativeThemeService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::NetworkingAttributes>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::NetworkSettingsService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::PolicyService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::Power>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::Prefs>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::Remoting>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::ResourceManager>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::ScreenManager>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::StructuredMetricsService>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::SnapshotCapturer>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::SystemDisplay>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::TaskManager>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::TestController>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::Tts>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::UrlHandler>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::VideoCaptureDeviceFactory>(),
-    MakeInterfaceVersionEntry<crosapi::mojom::WebPageInfoFactory>(),
-    MakeInterfaceVersionEntry<device::mojom::HidConnection>(),
-    MakeInterfaceVersionEntry<device::mojom::HidManager>(),
-    MakeInterfaceVersionEntry<
-        media::stable::mojom::StableVideoDecoderFactory>(),
-    MakeInterfaceVersionEntry<media_session::mojom::MediaControllerManager>(),
-    MakeInterfaceVersionEntry<media_session::mojom::AudioFocusManager>(),
-    MakeInterfaceVersionEntry<media_session::mojom::AudioFocusManagerDebug>(),
-};
-
-constexpr bool HasDuplicatedUuid() {
-  // We assume the number of entries are small enough so that simple
-  // O(N^2) check works.
-  const size_t size = base::size(kInterfaceVersionEntries);
-  for (size_t i = 0; i < size; ++i) {
-    for (size_t j = i + 1; j < size; ++j) {
-      if (kInterfaceVersionEntries[i].uuid == kInterfaceVersionEntries[j].uuid)
-        return true;
-    }
-  }
-  return false;
-}
-
 // Called from `IsDataWipeRequired()` or `IsDataWipeRequiredForTesting()`.
 // data_version` is the version of last data wipe. `current_version` is the
 // version of ash-chrome. `required_version` is the version that introduces some
@@ -423,8 +209,6 @@
 static_assert(
     crosapi::mojom::Crosapi::Version_ == 59,
     "if you add a new crosapi, please add it to kInterfaceVersionEntries");
-static_assert(!HasDuplicatedUuid(),
-              "Each Crosapi Mojom interface should have unique UUID.");
 
 }  // namespace
 
@@ -756,187 +540,6 @@
   return major_version >= 1000 && minor_version >= 0;
 }
 
-base::flat_map<base::Token, uint32_t> GetInterfaceVersions() {
-  base::flat_map<base::Token, uint32_t> versions;
-  for (const auto& entry : kInterfaceVersionEntries)
-    versions.emplace(entry.uuid, entry.version);
-  return versions;
-}
-
-mojom::BrowserInitParamsPtr GetBrowserInitParams(
-    EnvironmentProvider* environment_provider,
-    InitialBrowserAction initial_browser_action,
-    bool is_keep_alive_enabled) {
-  auto params = mojom::BrowserInitParams::New();
-  params->crosapi_version = crosapi::mojom::Crosapi::Version_;
-  params->deprecated_ash_metrics_enabled_has_value = true;
-  PrefService* local_state = g_browser_process->local_state();
-  params->ash_metrics_enabled =
-      local_state->GetBoolean(metrics::prefs::kMetricsReportingEnabled);
-  params->ash_metrics_managed =
-      local_state->IsManagedPreference(metrics::prefs::kMetricsReportingEnabled)
-          ? mojom::MetricsReportingManaged::kManaged
-          : mojom::MetricsReportingManaged::kNotManaged;
-
-  params->session_type = environment_provider->GetSessionType();
-  params->device_mode = environment_provider->GetDeviceMode();
-  params->interface_versions = GetInterfaceVersions();
-  params->default_paths = environment_provider->GetDefaultPaths();
-  params->use_new_account_manager =
-      environment_provider->GetUseNewAccountManager();
-
-  params->device_account_gaia_id =
-      environment_provider->GetDeviceAccountGaiaId();
-  const absl::optional<account_manager::Account> maybe_device_account =
-      environment_provider->GetDeviceAccount();
-  if (maybe_device_account) {
-    params->device_account =
-        account_manager::ToMojoAccount(maybe_device_account.value());
-  }
-
-  // TODO(crbug.com/1093194): This should be updated to a new value when
-  // the long term fix is made in ash-chrome, atomically.
-  params->exo_ime_support =
-      crosapi::mojom::ExoImeSupport::kConsumedByImeWorkaround;
-  params->cros_user_id_hash = chromeos::ProfileHelper::GetUserIdHashFromProfile(
-      ProfileManager::GetPrimaryUserProfile());
-  params->device_account_policy = GetDeviceAccountPolicy(environment_provider);
-  params->idle_info = IdleServiceAsh::ReadIdleInfoFromSystem();
-  params->native_theme_info = NativeThemeServiceAsh::GetNativeThemeInfo();
-
-  params->is_incognito_deprecated =
-      initial_browser_action.action ==
-      crosapi::mojom::InitialBrowserAction::kOpenIncognitoWindow;
-  params->restore_last_session_deprecated =
-      initial_browser_action.action ==
-      crosapi::mojom::InitialBrowserAction::kRestoreLastSession;
-  params->initial_browser_action = initial_browser_action.action;
-  if (initial_browser_action.action ==
-      crosapi::mojom::InitialBrowserAction::kOpenWindowWithUrls) {
-    params->startup_urls = std::move(initial_browser_action.urls);
-  }
-
-  params->web_apps_enabled = web_app::IsWebAppsCrosapiEnabled();
-  params->standalone_browser_is_primary = IsLacrosPrimaryBrowser();
-  params->device_properties = GetDeviceProperties();
-  params->device_settings = GetDeviceSettings();
-  // |metrics_service| could be nullptr in tests.
-  if (auto* metrics_service = g_browser_process->metrics_service()) {
-    // Send metrics service client id to Lacros if it's present.
-    std::string client_id = metrics_service->GetClientId();
-    if (!client_id.empty())
-      params->metrics_service_client_id = client_id;
-  }
-
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          ash::switches::kOndeviceHandwritingSwitch)) {
-    const auto handwriting_switch =
-        base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-            ash::switches::kOndeviceHandwritingSwitch);
-
-    // TODO(https://crbug.com/1168978): Query mlservice instead of using
-    // hard-coded values.
-    if (handwriting_switch == "use_rootfs") {
-      params->ondevice_handwriting_support =
-          crosapi::mojom::OndeviceHandwritingSupport::kUseRootfs;
-    } else if (handwriting_switch == "use_dlc") {
-      params->ondevice_handwriting_support =
-          crosapi::mojom::OndeviceHandwritingSupport::kUseDlc;
-    } else {
-      params->ondevice_handwriting_support =
-          crosapi::mojom::OndeviceHandwritingSupport::kUnsupported;
-    }
-  }
-
-  // Add any BUILDFLAGs we use to pass our per-platform/ build configuration to
-  // lacros for runtime handling instead.
-  std::vector<crosapi::mojom::BuildFlag> build_flags;
-#if BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_HEVC)
-  build_flags.emplace_back(
-      crosapi::mojom::BuildFlag::kEnablePlatformEncryptedHevc);
-#endif  // BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_HEVC)
-#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
-  build_flags.emplace_back(crosapi::mojom::BuildFlag::kEnablePlatformHevc);
-#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
-#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
-  build_flags.emplace_back(
-      crosapi::mojom::BuildFlag::kUseChromeosProtectedMedia);
-#endif  // BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
-#if BUILDFLAG(USE_CHROMEOS_PROTECTED_AV1)
-  build_flags.emplace_back(crosapi::mojom::BuildFlag::kUseChromeosProtectedAv1);
-#endif  // BUILDFLAG(USE_CHROMEOS_PROTECTED_AV1)
-  params->build_flags = std::move(build_flags);
-
-  params->standalone_browser_is_only_browser = !IsAshWebBrowserEnabled();
-  params->publish_chrome_apps = browser_util::IsLacrosChromeAppsEnabled();
-
-  // Keep-alive mojom API is now used by the current ash-chrome.
-  params->initial_keep_alive =
-      is_keep_alive_enabled
-          ? crosapi::mojom::BrowserInitParams::InitialKeepAlive::kEnabled
-          : crosapi::mojom::BrowserInitParams::InitialKeepAlive::kDisabled;
-
-  params->is_unfiltered_bluetooth_device_enabled =
-      chromeos::switches::IsUnfilteredBluetoothDevicesEnabled();
-
-  // Pass the accepted internal urls to lacros. Only accepted urls are allowed
-  // to be passed via OpenURL from Lacros to Ash.
-  params->accepted_internal_ash_urls =
-      std::move(ChromeWebUIControllerFactory::GetInstance())
-          ->GetListOfAcceptableURLs();
-  return params;
-}
-
-InitialBrowserAction::InitialBrowserAction(
-    crosapi::mojom::InitialBrowserAction action)
-    : action(action) {
-  // kOpnWindowWIthUrls should take the argument, so the ctor below should be
-  // used.
-  DCHECK_NE(action, crosapi::mojom::InitialBrowserAction::kOpenWindowWithUrls);
-}
-
-InitialBrowserAction::InitialBrowserAction(
-    crosapi::mojom::InitialBrowserAction action,
-    std::vector<GURL> urls)
-    : action(action), urls(std::move(urls)) {
-  // Currently, only kOpenWindowWithUrls can take the URLs as its argument.
-  DCHECK_EQ(action, crosapi::mojom::InitialBrowserAction::kOpenWindowWithUrls);
-}
-
-InitialBrowserAction::InitialBrowserAction(InitialBrowserAction&&) = default;
-InitialBrowserAction& InitialBrowserAction::operator=(InitialBrowserAction&&) =
-    default;
-
-InitialBrowserAction::~InitialBrowserAction() = default;
-
-base::ScopedFD CreateStartupData(EnvironmentProvider* environment_provider,
-                                 InitialBrowserAction initial_browser_action,
-                                 bool is_keep_alive_enabled) {
-  auto data = GetBrowserInitParams(environment_provider,
-                                   std::move(initial_browser_action),
-                                   is_keep_alive_enabled);
-  std::vector<uint8_t> serialized =
-      crosapi::mojom::BrowserInitParams::Serialize(&data);
-
-  base::ScopedFD fd(memfd_create("startup_data", 0));
-  if (!fd.is_valid()) {
-    PLOG(ERROR) << "Failed to create a memory backed file";
-    return base::ScopedFD();
-  }
-
-  if (!base::WriteFileDescriptor(fd.get(), serialized)) {
-    LOG(ERROR) << "Failed to dump the serialized startup data";
-    return base::ScopedFD();
-  }
-
-  if (lseek(fd.get(), 0, SEEK_SET) < 0) {
-    PLOG(ERROR) << "Failed to reset the FD position";
-    return base::ScopedFD();
-  }
-
-  return fd;
-}
-
 base::Version GetDataVer(PrefService* local_state,
                          const std::string& user_id_hash) {
   const base::DictionaryValue* data_versions =
@@ -1013,20 +616,6 @@
   return base::Version{version->GetString()};
 }
 
-bool IsSigninProfileOrBelongsToAffiliatedUser(Profile* profile) {
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
-    return true;
-
-  if (profile->IsOffTheRecord())
-    return false;
-
-  const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
-  if (!user)
-    return false;
-  return user->IsAffiliated();
-}
-
 void CacheLacrosLaunchSwitch(const policy::PolicyMap& map) {
   if (g_lacros_launch_switch_cache.has_value()) {
     // Some browser tests might call this multiple times.
@@ -1092,72 +681,6 @@
   }
 }
 
-// Returns the device policy data needed for Lacros.
-mojom::DeviceSettingsPtr GetDeviceSettings() {
-  mojom::DeviceSettingsPtr result = mojom::DeviceSettings::New();
-
-  result->attestation_for_content_protection_enabled = MojoOptionalBool::kUnset;
-  if (ash::CrosSettings::IsInitialized()) {
-    // It's expected that the CrosSettings values are trusted. The only
-    // theoretical exception is when device ownership is taken on consumer
-    // device. Then there's no settings to be passed to Lacros anyway.
-    auto trusted_result =
-        ash::CrosSettings::Get()->PrepareTrustedValues(base::DoNothing());
-    if (trusted_result == ash::CrosSettingsProvider::TRUSTED) {
-      const auto* cros_settings = ash::CrosSettings::Get();
-      bool attestation_enabled = false;
-      if (cros_settings->GetBoolean(
-              ash::kAttestationForContentProtectionEnabled,
-              &attestation_enabled)) {
-        result->attestation_for_content_protection_enabled =
-            attestation_enabled ? MojoOptionalBool::kTrue
-                                : MojoOptionalBool::kFalse;
-      }
-
-      const base::ListValue* usb_detachable_allow_list;
-      if (cros_settings->GetList(ash::kUsbDetachableAllowlist,
-                                 &usb_detachable_allow_list)) {
-        mojom::UsbDetachableAllowlistPtr allow_list =
-            mojom::UsbDetachableAllowlist::New();
-        for (const auto& entry : usb_detachable_allow_list->GetList()) {
-          mojom::UsbDeviceIdPtr usb_device_id = mojom::UsbDeviceId::New();
-          absl::optional<int> vid =
-              entry.FindIntKey(ash::kUsbDetachableAllowlistKeyVid);
-          if (vid) {
-            usb_device_id->has_vendor_id = true;
-            usb_device_id->vendor_id = vid.value();
-          }
-          absl::optional<int> pid =
-              entry.FindIntKey(ash::kUsbDetachableAllowlistKeyPid);
-          if (pid) {
-            usb_device_id->has_product_id = true;
-            usb_device_id->product_id = pid.value();
-          }
-          allow_list->usb_device_ids.push_back(std::move(usb_device_id));
-        }
-        result->usb_detachable_allow_list = std::move(allow_list);
-      }
-    } else {
-      LOG(WARNING) << "Unexpected crossettings trusted values status: "
-                   << trusted_result;
-    }
-  }
-
-  result->device_system_wide_tracing_enabled = MojoOptionalBool::kUnset;
-  auto* local_state = g_browser_process->local_state();
-  if (local_state) {
-    auto* pref = local_state->FindPreference(
-        ash::prefs::kDeviceSystemWideTracingEnabled);
-    if (pref && pref->IsManaged()) {
-      result->device_system_wide_tracing_enabled =
-          pref->GetValue()->GetBool() ? MojoOptionalBool::kTrue
-                                      : MojoOptionalBool::kFalse;
-    }
-  }
-
-  return result;
-}
-
 LacrosLaunchSwitch GetLaunchSwitchForTesting() {
   return GetLaunchSwitch();
 }
diff --git a/chrome/browser/ash/crosapi/browser_util.h b/chrome/browser/ash/crosapi/browser_util.h
index 5d306b4..60971ee 100644
--- a/chrome/browser/ash/crosapi/browser_util.h
+++ b/chrome/browser/ash/crosapi/browser_util.h
@@ -5,20 +5,14 @@
 #ifndef CHROME_BROWSER_ASH_CROSAPI_BROWSER_UTIL_H_
 #define CHROME_BROWSER_ASH_CROSAPI_BROWSER_UTIL_H_
 
-#include "base/callback_forward.h"
-#include "base/containers/flat_map.h"
+#include <string>
+
 #include "base/feature_list.h"
-#include "base/token.h"
-#include "chrome/browser/ash/crosapi/environment_provider.h"
-#include "chromeos/crosapi/mojom/crosapi.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
+class AccountId;
 class PrefRegistrySimple;
 class PrefService;
-class Profile;
-class AccountId;
 
 namespace aura {
 class Window;
@@ -26,13 +20,10 @@
 
 namespace base {
 class FilePath;
+class Value;
 class Version;
 }  // namespace base
 
-namespace mojo {
-class PlatformChannelEndpoint;
-}  // namespace mojo
-
 namespace version_info {
 enum class Channel;
 }  // namespace version_info
@@ -203,54 +194,6 @@
 // account_manager logic.
 bool DoesMetadataSupportNewAccountManager(base::Value* metadata);
 
-// Checks for the given profile if the user is affiliated or belongs to the
-// sign-in profile.
-bool IsSigninProfileOrBelongsToAffiliatedUser(Profile* profile);
-
-// Returns the UUID and version for all tracked interfaces. Exposed for testing.
-base::flat_map<base::Token, uint32_t> GetInterfaceVersions();
-
-// Represents how to launch Lacros Chrome.
-struct InitialBrowserAction {
-  explicit InitialBrowserAction(crosapi::mojom::InitialBrowserAction action);
-  InitialBrowserAction(crosapi::mojom::InitialBrowserAction action,
-                       std::vector<GURL> urls);
-  InitialBrowserAction(InitialBrowserAction&&);
-  InitialBrowserAction& operator=(InitialBrowserAction&&);
-  ~InitialBrowserAction();
-
-  // Mode how to launch Lacros chrome.
-  crosapi::mojom::InitialBrowserAction action;
-
-  // If action is kOpenWindowWithUrls, URLs here is passed to Lacros Chrome,
-  // and they will be opened.
-  std::vector<GURL> urls;
-};
-
-// Returns the initial parameter to be passed to Crosapi client,
-// such as lacros-chrome.
-mojom::BrowserInitParamsPtr GetBrowserInitParams(
-    EnvironmentProvider* environment_provider,
-    InitialBrowserAction initial_browser_action,
-    bool is_keep_alive_enabled);
-
-// Invite the lacros-chrome to the mojo universe.
-// Queue messages to establish the mojo connection, so that the passed IPC is
-// available already when lacros-chrome accepts the invitation.
-mojo::Remote<crosapi::mojom::BrowserService> SendMojoInvitationToLacrosChrome(
-    ::crosapi::EnvironmentProvider* environment_provider,
-    mojo::PlatformChannelEndpoint local_endpoint,
-    base::OnceClosure mojo_disconnected_callback,
-    base::OnceCallback<void(mojo::PendingReceiver<crosapi::mojom::Crosapi>)>
-        crosapi_callback);
-
-// Creates a memory backed file containing the serialized |params|,
-// and returns its FD.
-base::ScopedFD CreateStartupData(
-    ::crosapi::EnvironmentProvider* environment_provider,
-    InitialBrowserAction initial_browser_action,
-    bool is_keep_alive_enabled);
-
 // Reads `kDataVerPref` and gets corresponding data version for `user_id_hash`.
 // If no such version is registered yet, returns `Version` that is invalid.
 // Should only be called on UI thread since it reads from `LocalState`.
@@ -289,9 +232,6 @@
 version_info::Channel GetLacrosSelectionUpdateChannel(
     LacrosSelection selection);
 
-// Returns the device settings needed for Lacros.
-mojom::DeviceSettingsPtr GetDeviceSettings();
-
 // Exposed for testing. Returns the lacros integration suggested by the policy
 // lacros-availability, modified by Finch flags and user flags as appropriate.
 LacrosLaunchSwitch GetLaunchSwitchForTesting();
diff --git a/chrome/browser/ash/crosapi/browser_util_unittest.cc b/chrome/browser/ash/crosapi/browser_util_unittest.cc
index 1aad10e..51f7ad3 100644
--- a/chrome/browser/ash/crosapi/browser_util_unittest.cc
+++ b/chrome/browser/ash/crosapi/browser_util_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ash/crosapi/browser_util.h"
 
-#include "ash/components/settings/cros_settings_names.h"
 #include "ash/constants/ash_features.h"
 #include "base/containers/fixed_flat_map.h"
 #include "base/files/file_util.h"
@@ -14,22 +13,13 @@
 #include "base/values.h"
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/pref_names.h"
-#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/crosapi/mojom/crosapi.mojom.h"
-#include "chromeos/crosapi/mojom/keystore_service.mojom.h"
 #include "components/account_id/account_id.h"
 #include "components/policy/policy_constants.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "components/version_info/channel.h"
-#include "components/version_info/version_info.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -409,20 +399,6 @@
   }
 }
 
-TEST_F(BrowserUtilTest, GetInterfaceVersions) {
-  base::flat_map<base::Token, uint32_t> versions =
-      browser_util::GetInterfaceVersions();
-
-  // Check that a known interface with version > 0 is present and has non-zero
-  // version.
-  EXPECT_GT(versions[mojom::KeystoreService::Uuid_], 0);
-
-  // Check that the empty token is not present.
-  base::Token token;
-  auto it = versions.find(token);
-  EXPECT_EQ(it, versions.end());
-}
-
 TEST_F(BrowserUtilTest, MetadataMissing) {
   EXPECT_FALSE(browser_util::DoesMetadataSupportNewAccountManager(nullptr));
 }
@@ -660,58 +636,6 @@
   EXPECT_FALSE(browser_util::GetRootfsLacrosVersionMayBlock(path).IsValid());
 }
 
-TEST_F(BrowserUtilTest, IsSigninProfileOrBelongsToAffiliatedUserSigninProfile) {
-  TestingProfile::Builder builder;
-  builder.SetPath(base::FilePath(FILE_PATH_LITERAL(chrome::kInitialProfile)));
-  std::unique_ptr<Profile> signin_profile = builder.Build();
-
-  EXPECT_TRUE(browser_util::IsSigninProfileOrBelongsToAffiliatedUser(
-      signin_profile.get()));
-}
-
-TEST_F(BrowserUtilTest, IsSigninProfileOrBelongsToAffiliatedUserOffTheRecord) {
-  Profile* otr_profile = testing_profile_.GetOffTheRecordProfile(
-      Profile::OTRProfileID::CreateUniqueForTesting(),
-      /*create_if_needed=*/true);
-
-  EXPECT_FALSE(
-      browser_util::IsSigninProfileOrBelongsToAffiliatedUser(otr_profile));
-}
-
-TEST_F(BrowserUtilTest,
-       IsSigninProfileOrBelongsToAffiliatedUserAffiliatedUser) {
-  AccountId account_id = AccountId::FromUserEmail("user@test.com");
-  const User* user = fake_user_manager_->AddUserWithAffiliation(
-      account_id, /*is_affiliated=*/true);
-  fake_user_manager_->UserLoggedIn(account_id, user->username_hash(),
-                                   /*browser_restart=*/false,
-                                   /*is_child=*/false);
-  chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
-      user, &testing_profile_);
-
-  EXPECT_TRUE(browser_util::IsSigninProfileOrBelongsToAffiliatedUser(
-      &testing_profile_));
-}
-
-TEST_F(BrowserUtilTest,
-       IsSigninProfileOrBelongsToAffiliatedUserNotAffiliatedUser) {
-  AddRegularUser("user@test.com");
-
-  EXPECT_FALSE(browser_util::IsSigninProfileOrBelongsToAffiliatedUser(
-      &testing_profile_));
-}
-
-TEST_F(BrowserUtilTest,
-       IsSigninProfileOrBelongsToAffiliatedUserLockScreenProfile) {
-  TestingProfile::Builder builder;
-  builder.SetPath(
-      base::FilePath(FILE_PATH_LITERAL(chrome::kLockScreenProfile)));
-  std::unique_ptr<Profile> lock_screen_profile = builder.Build();
-
-  EXPECT_FALSE(browser_util::IsSigninProfileOrBelongsToAffiliatedUser(
-      lock_screen_profile.get()));
-}
-
 TEST_F(BrowserUtilTest, StatefulLacrosSelectionUpdateChannel) {
   // Assert that when no Lacros stability switch is specified, we return the
   // "unknown" channel.
@@ -728,52 +652,6 @@
   cmdline->RemoveSwitch(browser_util::kLacrosStabilitySwitch);
 }
 
-TEST_F(BrowserUtilTest, EmptyDeviceSettings) {
-  auto settings = browser_util::GetDeviceSettings();
-  EXPECT_EQ(settings->attestation_for_content_protection_enabled,
-            crosapi::mojom::DeviceSettings::OptionalBool::kUnset);
-  EXPECT_EQ(settings->device_system_wide_tracing_enabled,
-            crosapi::mojom::DeviceSettings::OptionalBool::kUnset);
-}
-
-TEST_F(BrowserUtilTest, DeviceSettingsWithData) {
-  testing_profile_.ScopedCrosSettingsTestHelper()
-      ->ReplaceDeviceSettingsProviderWithStub();
-  testing_profile_.ScopedCrosSettingsTestHelper()->SetTrustedStatus(
-      ash::CrosSettingsProvider::TRUSTED);
-  base::RunLoop().RunUntilIdle();
-  testing_profile_.ScopedCrosSettingsTestHelper()
-      ->GetStubbedProvider()
-      ->SetBoolean(ash::kAttestationForContentProtectionEnabled, true);
-
-  base::Value allowlist(base::Value::Type::LIST);
-  base::Value ids(base::Value::Type::DICTIONARY);
-  ids.SetIntKey(ash::kUsbDetachableAllowlistKeyVid, 2);
-  ids.SetIntKey(ash::kUsbDetachableAllowlistKeyPid, 3);
-  allowlist.Append(std::move(ids));
-
-  testing_profile_.ScopedCrosSettingsTestHelper()->GetStubbedProvider()->Set(
-      ash::kUsbDetachableAllowlist, std::move(allowlist));
-
-  auto settings = browser_util::GetDeviceSettings();
-  testing_profile_.ScopedCrosSettingsTestHelper()
-      ->RestoreRealDeviceSettingsProvider();
-
-  EXPECT_EQ(settings->attestation_for_content_protection_enabled,
-            crosapi::mojom::DeviceSettings::OptionalBool::kTrue);
-  EXPECT_EQ(settings->usb_detachable_allow_list->usb_device_ids.size(), 1);
-  EXPECT_EQ(
-      settings->usb_detachable_allow_list->usb_device_ids[0]->has_vendor_id,
-      true);
-  EXPECT_EQ(settings->usb_detachable_allow_list->usb_device_ids[0]->vendor_id,
-            2);
-  EXPECT_EQ(
-      settings->usb_detachable_allow_list->usb_device_ids[0]->has_product_id,
-      true);
-  EXPECT_EQ(settings->usb_detachable_allow_list->usb_device_ids[0]->product_id,
-            3);
-}
-
 TEST_F(BrowserUtilTest, IsProfileMigrationCompletedForUser) {
   const std::string user_id_hash = "abcd";
 
diff --git a/chrome/browser/ash/crosapi/crosapi_util.cc b/chrome/browser/ash/crosapi/crosapi_util.cc
new file mode 100644
index 0000000..9ae0350
--- /dev/null
+++ b/chrome/browser/ash/crosapi/crosapi_util.cc
@@ -0,0 +1,487 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/crosapi/crosapi_util.h"
+
+#include <sys/mman.h>
+
+#include "ash/components/settings/cros_settings_provider.h"
+#include "ash/constants/ash_pref_names.h"
+#include "ash/constants/ash_switches.h"
+#include "base/files/file_util.h"
+#include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/browser/ash/crosapi/browser_version_service_ash.h"
+#include "chrome/browser/ash/crosapi/field_trial_service_ash.h"
+#include "chrome/browser/ash/crosapi/idle_service_ash.h"
+#include "chrome/browser/ash/crosapi/native_theme_service_ash.h"
+#include "chrome/browser/ash/crosapi/resource_manager_ash.h"
+#include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/ash/settings/cros_settings.h"
+#include "chrome/browser/ash/settings/device_settings_service.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
+#include "chrome/browser/web_applications/web_app_utils.h"
+#include "chromeos/components/cdm_factory_daemon/mojom/browser_cdm_factory.mojom.h"
+#include "chromeos/components/sensors/mojom/cros_sensor_service.mojom.h"
+#include "chromeos/crosapi/cpp/crosapi_constants.h"
+#include "chromeos/crosapi/mojom/app_service.mojom.h"
+#include "chromeos/crosapi/mojom/app_window_tracker.mojom.h"
+#include "chromeos/crosapi/mojom/arc.mojom.h"
+#include "chromeos/crosapi/mojom/authentication.mojom.h"
+#include "chromeos/crosapi/mojom/automation.mojom.h"
+#include "chromeos/crosapi/mojom/browser_app_instance_registry.mojom.h"
+#include "chromeos/crosapi/mojom/cert_database.mojom.h"
+#include "chromeos/crosapi/mojom/clipboard.mojom.h"
+#include "chromeos/crosapi/mojom/clipboard_history.mojom.h"
+#include "chromeos/crosapi/mojom/content_protection.mojom.h"
+#include "chromeos/crosapi/mojom/crosapi.mojom.h"
+#include "chromeos/crosapi/mojom/device_attributes.mojom.h"
+#include "chromeos/crosapi/mojom/device_settings_service.mojom.h"
+#include "chromeos/crosapi/mojom/download_controller.mojom.h"
+#include "chromeos/crosapi/mojom/drive_integration_service.mojom.h"
+#include "chromeos/crosapi/mojom/feedback.mojom.h"
+#include "chromeos/crosapi/mojom/file_manager.mojom.h"
+#include "chromeos/crosapi/mojom/force_installed_tracker.mojom.h"
+#include "chromeos/crosapi/mojom/geolocation.mojom.h"
+#include "chromeos/crosapi/mojom/holding_space_service.mojom.h"
+#include "chromeos/crosapi/mojom/identity_manager.mojom.h"
+#include "chromeos/crosapi/mojom/image_writer.mojom.h"
+#include "chromeos/crosapi/mojom/keystore_service.mojom.h"
+#include "chromeos/crosapi/mojom/kiosk_session_service.mojom.h"
+#include "chromeos/crosapi/mojom/local_printer.mojom.h"
+#include "chromeos/crosapi/mojom/login_state.mojom.h"
+#include "chromeos/crosapi/mojom/message_center.mojom.h"
+#include "chromeos/crosapi/mojom/metrics_reporting.mojom.h"
+#include "chromeos/crosapi/mojom/network_settings_service.mojom.h"
+#include "chromeos/crosapi/mojom/networking_attributes.mojom.h"
+#include "chromeos/crosapi/mojom/policy_service.mojom.h"
+#include "chromeos/crosapi/mojom/power.mojom.h"
+#include "chromeos/crosapi/mojom/prefs.mojom.h"
+#include "chromeos/crosapi/mojom/remoting.mojom.h"
+#include "chromeos/crosapi/mojom/screen_manager.mojom.h"
+#include "chromeos/crosapi/mojom/structured_metrics_service.mojom.h"
+#include "chromeos/crosapi/mojom/system_display.mojom.h"
+#include "chromeos/crosapi/mojom/task_manager.mojom.h"
+#include "chromeos/crosapi/mojom/test_controller.mojom.h"
+#include "chromeos/crosapi/mojom/tts.mojom.h"
+#include "chromeos/crosapi/mojom/url_handler.mojom.h"
+#include "chromeos/crosapi/mojom/video_capture.mojom.h"
+#include "chromeos/crosapi/mojom/web_page_info.mojom.h"
+#include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
+#include "components/account_manager_core/account_manager_util.h"
+#include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/metrics_service.h"
+#include "components/policy/policy_constants.h"
+#include "components/prefs/pref_service.h"
+#include "components/user_manager/user.h"
+#include "components/user_manager/user_manager.h"
+#include "media/capture/mojom/video_capture.mojom.h"
+#include "media/mojo/mojom/stable/stable_video_decoder.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
+#include "services/media_session/public/mojom/media_controller.mojom.h"
+
+using MojoOptionalBool = crosapi::mojom::DeviceSettings::OptionalBool;
+
+namespace crosapi {
+namespace browser_util {
+
+namespace {
+
+// Returns the vector containing policy data of the device account. In case of
+// an error, returns nullopt.
+absl::optional<std::vector<uint8_t>> GetDeviceAccountPolicy(
+    EnvironmentProvider* environment_provider) {
+  if (!user_manager::UserManager::IsInitialized()) {
+    LOG(ERROR) << "User not initialized.";
+    return absl::nullopt;
+  }
+  const auto* primary_user = user_manager::UserManager::Get()->GetPrimaryUser();
+  if (!primary_user) {
+    LOG(ERROR) << "No primary user.";
+    return absl::nullopt;
+  }
+  std::string policy_data = environment_provider->GetDeviceAccountPolicy();
+  return std::vector<uint8_t>(policy_data.begin(), policy_data.end());
+}
+
+// Returns the device specific data needed for Lacros.
+mojom::DevicePropertiesPtr GetDeviceProperties() {
+  mojom::DevicePropertiesPtr result = mojom::DeviceProperties::New();
+  result->device_dm_token = "";
+
+  if (ash::DeviceSettingsService::IsInitialized()) {
+    const enterprise_management::PolicyData* policy_data =
+        ash::DeviceSettingsService::Get()->policy_data();
+
+    if (policy_data && policy_data->has_request_token())
+      result->device_dm_token = policy_data->request_token();
+
+    if (policy_data && !policy_data->device_affiliation_ids().empty()) {
+      const auto& ids = policy_data->device_affiliation_ids();
+      result->device_affiliation_ids = {ids.begin(), ids.end()};
+    }
+  }
+
+  return result;
+}
+
+struct InterfaceVersionEntry {
+  base::Token uuid;
+  uint32_t version;
+};
+
+template <typename T>
+constexpr InterfaceVersionEntry MakeInterfaceVersionEntry() {
+  return {T::Uuid_, T::Version_};
+}
+
+constexpr InterfaceVersionEntry kInterfaceVersionEntries[] = {
+    MakeInterfaceVersionEntry<chromeos::cdm::mojom::BrowserCdmFactory>(),
+    MakeInterfaceVersionEntry<chromeos::sensors::mojom::SensorHalClient>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::Arc>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::Authentication>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::Automation>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::AccountManager>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::AppPublisher>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::AppServiceProxy>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::AppWindowTracker>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::BrowserAppInstanceRegistry>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::BrowserServiceHost>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::BrowserVersionService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::CertDatabase>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::Clipboard>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::ClipboardHistory>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::ContentProtection>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::Crosapi>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::DeviceAttributes>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::DeviceSettingsService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::DownloadController>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::DriveIntegrationService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::Feedback>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::FieldTrialService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::FileManager>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::ForceInstalledTracker>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::GeolocationService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::HoldingSpaceService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::IdentityManager>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::IdleService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::ImageWriter>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::KeystoreService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::KioskSessionService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::LocalPrinter>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::LoginState>(),
+    MakeInterfaceVersionEntry<
+        chromeos::machine_learning::mojom::MachineLearningService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::MessageCenter>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::MetricsReporting>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::NativeThemeService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::NetworkingAttributes>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::NetworkSettingsService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::PolicyService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::Power>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::Prefs>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::Remoting>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::ResourceManager>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::ScreenManager>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::StructuredMetricsService>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::SnapshotCapturer>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::SystemDisplay>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::TaskManager>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::TestController>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::Tts>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::UrlHandler>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::VideoCaptureDeviceFactory>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::WebPageInfoFactory>(),
+    MakeInterfaceVersionEntry<device::mojom::HidConnection>(),
+    MakeInterfaceVersionEntry<device::mojom::HidManager>(),
+    MakeInterfaceVersionEntry<
+        media::stable::mojom::StableVideoDecoderFactory>(),
+    MakeInterfaceVersionEntry<media_session::mojom::MediaControllerManager>(),
+    MakeInterfaceVersionEntry<media_session::mojom::AudioFocusManager>(),
+    MakeInterfaceVersionEntry<media_session::mojom::AudioFocusManagerDebug>(),
+};
+
+constexpr bool HasDuplicatedUuid() {
+  // We assume the number of entries are small enough so that simple
+  // O(N^2) check works.
+  const size_t size = base::size(kInterfaceVersionEntries);
+  for (size_t i = 0; i < size; ++i) {
+    for (size_t j = i + 1; j < size; ++j) {
+      if (kInterfaceVersionEntries[i].uuid == kInterfaceVersionEntries[j].uuid)
+        return true;
+    }
+  }
+  return false;
+}
+
+static_assert(!HasDuplicatedUuid(),
+              "Each Crosapi Mojom interface should have unique UUID.");
+
+}  // namespace
+
+base::flat_map<base::Token, uint32_t> GetInterfaceVersions() {
+  base::flat_map<base::Token, uint32_t> versions;
+  for (const auto& entry : kInterfaceVersionEntries)
+    versions.emplace(entry.uuid, entry.version);
+  return versions;
+}
+
+InitialBrowserAction::InitialBrowserAction(
+    crosapi::mojom::InitialBrowserAction action)
+    : action(action) {
+  // kOpnWindowWIthUrls should take the argument, so the ctor below should be
+  // used.
+  DCHECK_NE(action, crosapi::mojom::InitialBrowserAction::kOpenWindowWithUrls);
+}
+
+InitialBrowserAction::InitialBrowserAction(
+    crosapi::mojom::InitialBrowserAction action,
+    std::vector<GURL> urls)
+    : action(action), urls(std::move(urls)) {
+  // Currently, only kOpenWindowWithUrls can take the URLs as its argument.
+  DCHECK_EQ(action, crosapi::mojom::InitialBrowserAction::kOpenWindowWithUrls);
+}
+
+InitialBrowserAction::InitialBrowserAction(InitialBrowserAction&&) = default;
+InitialBrowserAction& InitialBrowserAction::operator=(InitialBrowserAction&&) =
+    default;
+
+InitialBrowserAction::~InitialBrowserAction() = default;
+
+mojom::BrowserInitParamsPtr GetBrowserInitParams(
+    EnvironmentProvider* environment_provider,
+    InitialBrowserAction initial_browser_action,
+    bool is_keep_alive_enabled) {
+  auto params = mojom::BrowserInitParams::New();
+  params->crosapi_version = crosapi::mojom::Crosapi::Version_;
+  params->deprecated_ash_metrics_enabled_has_value = true;
+  PrefService* local_state = g_browser_process->local_state();
+  params->ash_metrics_enabled =
+      local_state->GetBoolean(metrics::prefs::kMetricsReportingEnabled);
+  params->ash_metrics_managed =
+      local_state->IsManagedPreference(metrics::prefs::kMetricsReportingEnabled)
+          ? mojom::MetricsReportingManaged::kManaged
+          : mojom::MetricsReportingManaged::kNotManaged;
+
+  params->session_type = environment_provider->GetSessionType();
+  params->device_mode = environment_provider->GetDeviceMode();
+  params->interface_versions = GetInterfaceVersions();
+  params->default_paths = environment_provider->GetDefaultPaths();
+  params->use_new_account_manager =
+      environment_provider->GetUseNewAccountManager();
+
+  params->device_account_gaia_id =
+      environment_provider->GetDeviceAccountGaiaId();
+  const absl::optional<account_manager::Account> maybe_device_account =
+      environment_provider->GetDeviceAccount();
+  if (maybe_device_account) {
+    params->device_account =
+        account_manager::ToMojoAccount(maybe_device_account.value());
+  }
+
+  // TODO(crbug.com/1093194): This should be updated to a new value when
+  // the long term fix is made in ash-chrome, atomically.
+  params->exo_ime_support =
+      crosapi::mojom::ExoImeSupport::kConsumedByImeWorkaround;
+  params->cros_user_id_hash = chromeos::ProfileHelper::GetUserIdHashFromProfile(
+      ProfileManager::GetPrimaryUserProfile());
+  params->device_account_policy = GetDeviceAccountPolicy(environment_provider);
+  params->idle_info = IdleServiceAsh::ReadIdleInfoFromSystem();
+  params->native_theme_info = NativeThemeServiceAsh::GetNativeThemeInfo();
+
+  params->is_incognito_deprecated =
+      initial_browser_action.action ==
+      crosapi::mojom::InitialBrowserAction::kOpenIncognitoWindow;
+  params->restore_last_session_deprecated =
+      initial_browser_action.action ==
+      crosapi::mojom::InitialBrowserAction::kRestoreLastSession;
+  params->initial_browser_action = initial_browser_action.action;
+  if (initial_browser_action.action ==
+      crosapi::mojom::InitialBrowserAction::kOpenWindowWithUrls) {
+    params->startup_urls = std::move(initial_browser_action.urls);
+  }
+
+  params->web_apps_enabled = web_app::IsWebAppsCrosapiEnabled();
+  params->standalone_browser_is_primary = IsLacrosPrimaryBrowser();
+  params->device_properties = GetDeviceProperties();
+  params->device_settings = GetDeviceSettings();
+  // |metrics_service| could be nullptr in tests.
+  if (auto* metrics_service = g_browser_process->metrics_service()) {
+    // Send metrics service client id to Lacros if it's present.
+    std::string client_id = metrics_service->GetClientId();
+    if (!client_id.empty())
+      params->metrics_service_client_id = client_id;
+  }
+
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          ash::switches::kOndeviceHandwritingSwitch)) {
+    const auto handwriting_switch =
+        base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+            ash::switches::kOndeviceHandwritingSwitch);
+
+    // TODO(https://crbug.com/1168978): Query mlservice instead of using
+    // hard-coded values.
+    if (handwriting_switch == "use_rootfs") {
+      params->ondevice_handwriting_support =
+          crosapi::mojom::OndeviceHandwritingSupport::kUseRootfs;
+    } else if (handwriting_switch == "use_dlc") {
+      params->ondevice_handwriting_support =
+          crosapi::mojom::OndeviceHandwritingSupport::kUseDlc;
+    } else {
+      params->ondevice_handwriting_support =
+          crosapi::mojom::OndeviceHandwritingSupport::kUnsupported;
+    }
+  }
+
+  // Add any BUILDFLAGs we use to pass our per-platform/ build configuration to
+  // lacros for runtime handling instead.
+  std::vector<crosapi::mojom::BuildFlag> build_flags;
+#if BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_HEVC)
+  build_flags.emplace_back(
+      crosapi::mojom::BuildFlag::kEnablePlatformEncryptedHevc);
+#endif  // BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_HEVC)
+#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
+  build_flags.emplace_back(crosapi::mojom::BuildFlag::kEnablePlatformHevc);
+#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
+#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
+  build_flags.emplace_back(
+      crosapi::mojom::BuildFlag::kUseChromeosProtectedMedia);
+#endif  // BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
+#if BUILDFLAG(USE_CHROMEOS_PROTECTED_AV1)
+  build_flags.emplace_back(crosapi::mojom::BuildFlag::kUseChromeosProtectedAv1);
+#endif  // BUILDFLAG(USE_CHROMEOS_PROTECTED_AV1)
+  params->build_flags = std::move(build_flags);
+
+  params->standalone_browser_is_only_browser = !IsAshWebBrowserEnabled();
+  params->publish_chrome_apps = browser_util::IsLacrosChromeAppsEnabled();
+
+  // Keep-alive mojom API is now used by the current ash-chrome.
+  params->initial_keep_alive =
+      is_keep_alive_enabled
+          ? crosapi::mojom::BrowserInitParams::InitialKeepAlive::kEnabled
+          : crosapi::mojom::BrowserInitParams::InitialKeepAlive::kDisabled;
+
+  params->is_unfiltered_bluetooth_device_enabled =
+      chromeos::switches::IsUnfilteredBluetoothDevicesEnabled();
+
+  // Pass the accepted internal urls to lacros. Only accepted urls are allowed
+  // to be passed via OpenURL from Lacros to Ash.
+  params->accepted_internal_ash_urls =
+      std::move(ChromeWebUIControllerFactory::GetInstance())
+          ->GetListOfAcceptableURLs();
+  return params;
+}
+
+base::ScopedFD CreateStartupData(EnvironmentProvider* environment_provider,
+                                 InitialBrowserAction initial_browser_action,
+                                 bool is_keep_alive_enabled) {
+  auto data = GetBrowserInitParams(environment_provider,
+                                   std::move(initial_browser_action),
+                                   is_keep_alive_enabled);
+  std::vector<uint8_t> serialized =
+      crosapi::mojom::BrowserInitParams::Serialize(&data);
+
+  base::ScopedFD fd(memfd_create("startup_data", 0));
+  if (!fd.is_valid()) {
+    PLOG(ERROR) << "Failed to create a memory backed file";
+    return base::ScopedFD();
+  }
+
+  if (!base::WriteFileDescriptor(fd.get(), serialized)) {
+    LOG(ERROR) << "Failed to dump the serialized startup data";
+    return base::ScopedFD();
+  }
+
+  if (lseek(fd.get(), 0, SEEK_SET) < 0) {
+    PLOG(ERROR) << "Failed to reset the FD position";
+    return base::ScopedFD();
+  }
+
+  return fd;
+}
+
+bool IsSigninProfileOrBelongsToAffiliatedUser(Profile* profile) {
+  if (chromeos::ProfileHelper::IsSigninProfile(profile))
+    return true;
+
+  if (profile->IsOffTheRecord())
+    return false;
+
+  const user_manager::User* user =
+      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+  if (!user)
+    return false;
+  return user->IsAffiliated();
+}
+
+// Returns the device policy data needed for Lacros.
+mojom::DeviceSettingsPtr GetDeviceSettings() {
+  mojom::DeviceSettingsPtr result = mojom::DeviceSettings::New();
+
+  result->attestation_for_content_protection_enabled = MojoOptionalBool::kUnset;
+  if (ash::CrosSettings::IsInitialized()) {
+    // It's expected that the CrosSettings values are trusted. The only
+    // theoretical exception is when device ownership is taken on consumer
+    // device. Then there's no settings to be passed to Lacros anyway.
+    auto trusted_result =
+        ash::CrosSettings::Get()->PrepareTrustedValues(base::DoNothing());
+    if (trusted_result == ash::CrosSettingsProvider::TRUSTED) {
+      const auto* cros_settings = ash::CrosSettings::Get();
+      bool attestation_enabled = false;
+      if (cros_settings->GetBoolean(
+              ash::kAttestationForContentProtectionEnabled,
+              &attestation_enabled)) {
+        result->attestation_for_content_protection_enabled =
+            attestation_enabled ? MojoOptionalBool::kTrue
+                                : MojoOptionalBool::kFalse;
+      }
+
+      const base::ListValue* usb_detachable_allow_list;
+      if (cros_settings->GetList(ash::kUsbDetachableAllowlist,
+                                 &usb_detachable_allow_list)) {
+        mojom::UsbDetachableAllowlistPtr allow_list =
+            mojom::UsbDetachableAllowlist::New();
+        for (const auto& entry : usb_detachable_allow_list->GetList()) {
+          mojom::UsbDeviceIdPtr usb_device_id = mojom::UsbDeviceId::New();
+          absl::optional<int> vid =
+              entry.FindIntKey(ash::kUsbDetachableAllowlistKeyVid);
+          if (vid) {
+            usb_device_id->has_vendor_id = true;
+            usb_device_id->vendor_id = vid.value();
+          }
+          absl::optional<int> pid =
+              entry.FindIntKey(ash::kUsbDetachableAllowlistKeyPid);
+          if (pid) {
+            usb_device_id->has_product_id = true;
+            usb_device_id->product_id = pid.value();
+          }
+          allow_list->usb_device_ids.push_back(std::move(usb_device_id));
+        }
+        result->usb_detachable_allow_list = std::move(allow_list);
+      }
+    } else {
+      LOG(WARNING) << "Unexpected crossettings trusted values status: "
+                   << trusted_result;
+    }
+  }
+
+  result->device_system_wide_tracing_enabled = MojoOptionalBool::kUnset;
+  auto* local_state = g_browser_process->local_state();
+  if (local_state) {
+    auto* pref = local_state->FindPreference(
+        ash::prefs::kDeviceSystemWideTracingEnabled);
+    if (pref && pref->IsManaged()) {
+      result->device_system_wide_tracing_enabled =
+          pref->GetValue()->GetBool() ? MojoOptionalBool::kTrue
+                                      : MojoOptionalBool::kFalse;
+    }
+  }
+
+  return result;
+}
+
+}  // namespace browser_util
+}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/crosapi_util.h b/chrome/browser/ash/crosapi/crosapi_util.h
new file mode 100644
index 0000000..0485cf4
--- /dev/null
+++ b/chrome/browser/ash/crosapi/crosapi_util.h
@@ -0,0 +1,67 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_CROSAPI_CROSAPI_UTIL_H_
+#define CHROME_BROWSER_ASH_CROSAPI_CROSAPI_UTIL_H_
+
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "base/files/scoped_file.h"
+#include "base/token.h"
+#include "chrome/browser/ash/crosapi/environment_provider.h"
+#include "chromeos/crosapi/mojom/crosapi.mojom.h"
+#include "url/gurl.h"
+
+class Profile;
+
+// These methods are used by ash-chrome.
+namespace crosapi {
+namespace browser_util {
+
+// Checks for the given profile if the user is affiliated or belongs to the
+// sign-in profile.
+bool IsSigninProfileOrBelongsToAffiliatedUser(Profile* profile);
+
+// Returns the UUID and version for all tracked interfaces. Exposed for testing.
+base::flat_map<base::Token, uint32_t> GetInterfaceVersions();
+
+// Represents how to launch Lacros Chrome.
+struct InitialBrowserAction {
+  explicit InitialBrowserAction(crosapi::mojom::InitialBrowserAction action);
+  InitialBrowserAction(crosapi::mojom::InitialBrowserAction action,
+                       std::vector<GURL> urls);
+  InitialBrowserAction(InitialBrowserAction&&);
+  InitialBrowserAction& operator=(InitialBrowserAction&&);
+  ~InitialBrowserAction();
+
+  // Mode how to launch Lacros chrome.
+  crosapi::mojom::InitialBrowserAction action;
+
+  // If action is kOpenWindowWithUrls, URLs here is passed to Lacros Chrome,
+  // and they will be opened.
+  std::vector<GURL> urls;
+};
+
+// Returns the initial parameter to be passed to Crosapi client,
+// such as lacros-chrome.
+mojom::BrowserInitParamsPtr GetBrowserInitParams(
+    EnvironmentProvider* environment_provider,
+    InitialBrowserAction initial_browser_action,
+    bool is_keep_alive_enabled);
+
+// Creates a memory backed file containing the serialized |params|,
+// and returns its FD.
+base::ScopedFD CreateStartupData(
+    ::crosapi::EnvironmentProvider* environment_provider,
+    InitialBrowserAction initial_browser_action,
+    bool is_keep_alive_enabled);
+
+// Returns the device settings needed for Lacros.
+mojom::DeviceSettingsPtr GetDeviceSettings();
+
+}  // namespace browser_util
+}  // namespace crosapi
+
+#endif  // CHROME_BROWSER_ASH_CROSAPI_CROSAPI_UTIL_H_
diff --git a/chrome/browser/ash/crosapi/crosapi_util_unittest.cc b/chrome/browser/ash/crosapi/crosapi_util_unittest.cc
new file mode 100644
index 0000000..234d9b44
--- /dev/null
+++ b/chrome/browser/ash/crosapi/crosapi_util_unittest.cc
@@ -0,0 +1,166 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/crosapi/crosapi_util.h"
+
+#include <string>
+
+#include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
+#include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chromeos/crosapi/mojom/keystore_service.mojom.h"
+#include "components/user_manager/scoped_user_manager.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using user_manager::User;
+
+namespace crosapi {
+
+class CrosapiUtilTest : public testing::Test {
+ public:
+  CrosapiUtilTest() = default;
+  ~CrosapiUtilTest() override = default;
+
+  void SetUp() override {
+    fake_user_manager_ = new ash::FakeChromeUserManager;
+    scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
+        base::WrapUnique(fake_user_manager_));
+    browser_util::RegisterLocalStatePrefs(pref_service_.registry());
+  }
+
+  void AddRegularUser(const std::string& email) {
+    AccountId account_id = AccountId::FromUserEmail(email);
+    const User* user = fake_user_manager_->AddUser(account_id);
+    fake_user_manager_->UserLoggedIn(account_id, user->username_hash(),
+                                     /*browser_restart=*/false,
+                                     /*is_child=*/false);
+    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+        user, &testing_profile_);
+  }
+
+  // The order of these members is relevant for both construction and
+  // destruction timing.
+  content::BrowserTaskEnvironment task_environment_;
+  TestingProfile testing_profile_;
+  ash::FakeChromeUserManager* fake_user_manager_ = nullptr;
+  std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
+  TestingPrefServiceSimple pref_service_;
+};
+
+TEST_F(CrosapiUtilTest, GetInterfaceVersions) {
+  base::flat_map<base::Token, uint32_t> versions =
+      browser_util::GetInterfaceVersions();
+
+  // Check that a known interface with version > 0 is present and has non-zero
+  // version.
+  EXPECT_GT(versions[mojom::KeystoreService::Uuid_], 0);
+
+  // Check that the empty token is not present.
+  base::Token token;
+  auto it = versions.find(token);
+  EXPECT_EQ(it, versions.end());
+}
+
+TEST_F(CrosapiUtilTest, IsSigninProfileOrBelongsToAffiliatedUserSigninProfile) {
+  TestingProfile::Builder builder;
+  builder.SetPath(base::FilePath(FILE_PATH_LITERAL(chrome::kInitialProfile)));
+  std::unique_ptr<Profile> signin_profile = builder.Build();
+
+  EXPECT_TRUE(browser_util::IsSigninProfileOrBelongsToAffiliatedUser(
+      signin_profile.get()));
+}
+
+TEST_F(CrosapiUtilTest, IsSigninProfileOrBelongsToAffiliatedUserOffTheRecord) {
+  Profile* otr_profile = testing_profile_.GetOffTheRecordProfile(
+      Profile::OTRProfileID::CreateUniqueForTesting(),
+      /*create_if_needed=*/true);
+
+  EXPECT_FALSE(
+      browser_util::IsSigninProfileOrBelongsToAffiliatedUser(otr_profile));
+}
+
+TEST_F(CrosapiUtilTest,
+       IsSigninProfileOrBelongsToAffiliatedUserAffiliatedUser) {
+  AccountId account_id = AccountId::FromUserEmail("user@test.com");
+  const User* user = fake_user_manager_->AddUserWithAffiliation(
+      account_id, /*is_affiliated=*/true);
+  fake_user_manager_->UserLoggedIn(account_id, user->username_hash(),
+                                   /*browser_restart=*/false,
+                                   /*is_child=*/false);
+  chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+      user, &testing_profile_);
+
+  EXPECT_TRUE(browser_util::IsSigninProfileOrBelongsToAffiliatedUser(
+      &testing_profile_));
+}
+
+TEST_F(CrosapiUtilTest,
+       IsSigninProfileOrBelongsToAffiliatedUserNotAffiliatedUser) {
+  AddRegularUser("user@test.com");
+
+  EXPECT_FALSE(browser_util::IsSigninProfileOrBelongsToAffiliatedUser(
+      &testing_profile_));
+}
+
+TEST_F(CrosapiUtilTest,
+       IsSigninProfileOrBelongsToAffiliatedUserLockScreenProfile) {
+  TestingProfile::Builder builder;
+  builder.SetPath(
+      base::FilePath(FILE_PATH_LITERAL(chrome::kLockScreenProfile)));
+  std::unique_ptr<Profile> lock_screen_profile = builder.Build();
+
+  EXPECT_FALSE(browser_util::IsSigninProfileOrBelongsToAffiliatedUser(
+      lock_screen_profile.get()));
+}
+
+TEST_F(CrosapiUtilTest, EmptyDeviceSettings) {
+  auto settings = browser_util::GetDeviceSettings();
+  EXPECT_EQ(settings->attestation_for_content_protection_enabled,
+            crosapi::mojom::DeviceSettings::OptionalBool::kUnset);
+  EXPECT_EQ(settings->device_system_wide_tracing_enabled,
+            crosapi::mojom::DeviceSettings::OptionalBool::kUnset);
+}
+
+TEST_F(CrosapiUtilTest, DeviceSettingsWithData) {
+  testing_profile_.ScopedCrosSettingsTestHelper()
+      ->ReplaceDeviceSettingsProviderWithStub();
+  testing_profile_.ScopedCrosSettingsTestHelper()->SetTrustedStatus(
+      ash::CrosSettingsProvider::TRUSTED);
+  base::RunLoop().RunUntilIdle();
+  testing_profile_.ScopedCrosSettingsTestHelper()
+      ->GetStubbedProvider()
+      ->SetBoolean(ash::kAttestationForContentProtectionEnabled, true);
+
+  base::Value allowlist(base::Value::Type::LIST);
+  base::Value ids(base::Value::Type::DICTIONARY);
+  ids.SetIntKey(ash::kUsbDetachableAllowlistKeyVid, 2);
+  ids.SetIntKey(ash::kUsbDetachableAllowlistKeyPid, 3);
+  allowlist.Append(std::move(ids));
+
+  testing_profile_.ScopedCrosSettingsTestHelper()->GetStubbedProvider()->Set(
+      ash::kUsbDetachableAllowlist, std::move(allowlist));
+
+  auto settings = browser_util::GetDeviceSettings();
+  testing_profile_.ScopedCrosSettingsTestHelper()
+      ->RestoreRealDeviceSettingsProvider();
+
+  EXPECT_EQ(settings->attestation_for_content_protection_enabled,
+            crosapi::mojom::DeviceSettings::OptionalBool::kTrue);
+  EXPECT_EQ(settings->usb_detachable_allow_list->usb_device_ids.size(), 1);
+  EXPECT_EQ(
+      settings->usb_detachable_allow_list->usb_device_ids[0]->has_vendor_id,
+      true);
+  EXPECT_EQ(settings->usb_detachable_allow_list->usb_device_ids[0]->vendor_id,
+            2);
+  EXPECT_EQ(
+      settings->usb_detachable_allow_list->usb_device_ids[0]->has_product_id,
+      true);
+  EXPECT_EQ(settings->usb_detachable_allow_list->usb_device_ids[0]->product_id,
+            3);
+}
+
+}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/device_attributes_ash.cc b/chrome/browser/ash/crosapi/device_attributes_ash.cc
index ce5e6809c..a93352a 100644
--- a/chrome/browser/ash/crosapi/device_attributes_ash.cc
+++ b/chrome/browser/ash/crosapi/device_attributes_ash.cc
@@ -6,7 +6,7 @@
 
 #include <utility>
 
-#include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/browser/ash/crosapi/crosapi_util.h"
 #include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
 #include "chrome/browser/ash/policy/handlers/device_name_policy_handler.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
diff --git a/chrome/browser/ash/crosapi/device_settings_ash.cc b/chrome/browser/ash/crosapi/device_settings_ash.cc
index bc8ad9b..5f0a2175 100644
--- a/chrome/browser/ash/crosapi/device_settings_ash.cc
+++ b/chrome/browser/ash/crosapi/device_settings_ash.cc
@@ -6,7 +6,7 @@
 
 #include <utility>
 
-#include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/browser/ash/crosapi/crosapi_util.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
 namespace crosapi {
diff --git a/chrome/browser/ash/crosapi/networking_attributes_ash.cc b/chrome/browser/ash/crosapi/networking_attributes_ash.cc
index b8887068..b5c5389 100644
--- a/chrome/browser/ash/crosapi/networking_attributes_ash.cc
+++ b/chrome/browser/ash/crosapi/networking_attributes_ash.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/ash/crosapi/networking_attributes_ash.h"
 
 #include "base/values.h"
-#include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/browser/ash/crosapi/crosapi_util.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/ash/crosapi/test_mojo_connection_manager.cc b/chrome/browser/ash/crosapi/test_mojo_connection_manager.cc
index fe320e0b..fb7883f 100644
--- a/chrome/browser/ash/crosapi/test_mojo_connection_manager.cc
+++ b/chrome/browser/ash/crosapi/test_mojo_connection_manager.cc
@@ -12,8 +12,8 @@
 #include "base/path_service.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
-#include "chrome/browser/ash/crosapi/browser_util.h"
 #include "chrome/browser/ash/crosapi/crosapi_manager.h"
+#include "chrome/browser/ash/crosapi/crosapi_util.h"
 #include "chrome/browser/ash/crosapi/environment_provider.h"
 #include "chrome/common/chrome_paths.h"
 #include "components/account_manager_core/account.h"
diff --git a/chrome/browser/ash/input_method/ime_rules_config.cc b/chrome/browser/ash/input_method/ime_rules_config.cc
new file mode 100644
index 0000000..5f46c3ad
--- /dev/null
+++ b/chrome/browser/ash/input_method/ime_rules_config.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/input_method/ime_rules_config.h"
+
+#include "ash/constants/ash_features.h"
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+
+namespace ash {
+namespace input_method {
+namespace {
+
+// String parameter containing the JSON-encoded rules dictionary.
+const char kJsonRulesDictKey[] = "json_rules";
+
+constexpr base::FeatureParam<std::string> kFieldTrialParams{
+    &ash::features::kImeRuleConfig, kJsonRulesDictKey, ""};
+
+// Array of objects, containing the list of rules.
+const char kConfigRulesKey[] = "rules";
+
+// Array of strings, containing the list of items the rule will use.
+const char kConfigRuleItemsKey[] = "items";
+
+// String, rule name of autocorrect domain denylist, containing the list of
+// globally denylisted domains for auto correct..
+const char kAutocorrectDomainDenylistKey[] = "ac-domain-denylist";
+
+}  // namespace
+
+ImeRulesConfig::ImeRulesConfig() {
+  InitFromTrialParams();
+}
+
+ImeRulesConfig::~ImeRulesConfig() = default;
+
+void ImeRulesConfig::InitFromTrialParams() {
+  std::string params = kFieldTrialParams.Get();
+  if (params.empty()) {
+    VLOG(2) << "Field trial parameter not set";
+    return;
+  }
+  absl::optional<base::Value> dict = base::JSONReader::Read(params);
+  if (!dict || !dict->is_dict()) {
+    VLOG(1) << "Failed to parse field trial params as JSON object: " << params;
+    if (VLOG_IS_ON(1)) {
+      auto err = base::JSONReader::ReadAndReturnValueWithError(params);
+      VLOG(1) << err.error_message << ", line: " << err.error_line
+              << ", col: " << err.error_column;
+    }
+    return;
+  }
+
+  // Read mandatory list of rules.
+  auto* rules = dict->FindDictKey(kConfigRulesKey);
+  if (rules == nullptr || !rules->is_dict()) {
+    VLOG(1) << "Field trial params did not contain rules";
+    return;
+  }
+
+  // Read optional rule for auto correct deny list.
+  auto* ac_domain_denylist = rules->FindDictKey(kAutocorrectDomainDenylistKey);
+  if (ac_domain_denylist == nullptr || !ac_domain_denylist->is_dict()) {
+    VLOG(1) << "Rules from config did not contain "
+            << kAutocorrectDomainDenylistKey;
+  } else {
+    // Read optional list of auto correct denylisted domains.
+    auto* ac_domains_items =
+        ac_domain_denylist->FindListKey(kConfigRuleItemsKey);
+    if (ac_domains_items != nullptr) {
+      for (const auto& domain : ac_domains_items->GetList()) {
+        if (domain.is_string()) {
+          auto_correct_domain_denylist_.push_back(*domain.GetIfString());
+        }
+      }
+    }
+  }
+}
+
+bool ImeRulesConfig::IsAutoCorrectAllowed(const GURL& url) const {
+  for (const auto& domain : auto_correct_domain_denylist_) {
+    if (url.DomainIs(domain)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace input_method
+}  // namespace ash
diff --git a/chrome/browser/ash/input_method/ime_rules_config.h b/chrome/browser/ash/input_method/ime_rules_config.h
new file mode 100644
index 0000000..ca6c6f71
--- /dev/null
+++ b/chrome/browser/ash/input_method/ime_rules_config.h
@@ -0,0 +1,40 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#include <vector>
+
+#include "url/gurl.h"
+
+#ifndef CHROME_BROWSER_ASH_INPUT_METHOD_IME_RULES_CONFIG_H_
+#define CHROME_BROWSER_ASH_INPUT_METHOD_IME_RULES_CONFIG_H_
+
+namespace ash {
+namespace input_method {
+
+// IME config that implements a rule check for IME features.
+class ImeRulesConfig {
+ public:
+  ImeRulesConfig();
+  ~ImeRulesConfig();
+
+  // Runs the rule checkagainst |url|.
+  bool IsAutoCorrectAllowed(const GURL& url) const;
+
+ private:
+  friend class ImeRulesConfigTest;
+
+  // Initializes the config from IME rules trial parameters. If there is
+  // no trial or parsing fails, the rules will be empty and as such always
+  // allow any features.
+  void InitFromTrialParams();
+
+  // The denylist of domains that will turn off auto_correct feature.
+  std::vector<std::string> auto_correct_domain_denylist_;
+};
+
+}  // namespace input_method
+}  // namespace ash
+
+#endif  // CHROME_BROWSER_ASH_INPUT_METHOD_IME_RULES_CONFIG_H_
diff --git a/chrome/browser/ash/input_method/ime_rules_config_unittest.cc b/chrome/browser/ash/input_method/ime_rules_config_unittest.cc
new file mode 100644
index 0000000..6e5430b
--- /dev/null
+++ b/chrome/browser/ash/input_method/ime_rules_config_unittest.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/input_method/ime_rules_config.h"
+
+#include <vector>
+
+#include "ash/constants/ash_features.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/test/scoped_feature_list.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace ash {
+namespace input_method {
+namespace {
+
+const char kNormalAutocorrectRulesParams[] = R"(
+    {
+      "rules":{
+        "ac-domain-denylist":{
+          "items": [
+            "test.com.au",
+            "example.com",
+            "chromium.org",
+            "docs.google.com"
+          ]
+        }
+     }
+    })";
+
+}  // namespace
+
+using ::testing::UnorderedElementsAre;
+
+class ImeRulesConfigTest : public testing::Test {
+ public:
+  ImeRulesConfigTest() = default;
+  ~ImeRulesConfigTest() override = default;
+
+  std::vector<std::string> GetAutocorrectDomainDenylistForTest(
+      const ImeRulesConfig& rules) {
+    return rules.auto_correct_domain_denylist_;
+  }
+};
+
+TEST_F(ImeRulesConfigTest, LoadRulesFromFieldTrial) {
+  auto feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  feature_list->InitAndEnableFeatureWithParameters(
+      ash::features::kImeRuleConfig,
+      {{"json_rules", kNormalAutocorrectRulesParams}});
+
+  ImeRulesConfig rules;
+  EXPECT_THAT(GetAutocorrectDomainDenylistForTest(rules),
+              UnorderedElementsAre("docs.google.com", "chromium.org",
+                                   "example.com", "test.com.au"));
+}
+
+TEST_F(ImeRulesConfigTest, IsAutoCorrectAllowed) {
+  auto feature_list = std::make_unique<base::test::ScopedFeatureList>();
+  feature_list->InitAndEnableFeatureWithParameters(
+      ash::features::kImeRuleConfig,
+      {{"json_rules", kNormalAutocorrectRulesParams}});
+
+  ImeRulesConfig rules;
+  EXPECT_TRUE(rules.IsAutoCorrectAllowed(GURL("http://abc.com")));
+  EXPECT_FALSE(rules.IsAutoCorrectAllowed(GURL("https://www.example.com")));
+  EXPECT_FALSE(rules.IsAutoCorrectAllowed(GURL("https://test.com.au")));
+  EXPECT_FALSE(rules.IsAutoCorrectAllowed(
+      GURL("https://docs.google.com/document/d/documentId/edit")));
+}
+
+}  // namespace input_method
+}  // namespace ash
diff --git a/chrome/browser/ash/input_method/native_input_method_engine.cc b/chrome/browser/ash/input_method/native_input_method_engine.cc
index 9c21f91a..68c90e6a 100644
--- a/chrome/browser/ash/input_method/native_input_method_engine.cc
+++ b/chrome/browser/ash/input_method/native_input_method_engine.cc
@@ -925,7 +925,12 @@
 
 void NativeInputMethodEngine::ImeObserver::SetComposition(
     const std::u16string& text,
-    std::vector<mojom::CompositionSpanPtr> spans) {
+    std::vector<mojom::CompositionSpanPtr> spans,
+    uint32_t new_cursor_position) {
+  if (new_cursor_position > text.length()) {
+    return;
+  }
+
   ui::CompositionText composition;
   composition.text = text;
 
@@ -934,9 +939,9 @@
     composition.ime_text_spans.push_back(CompositionSpanToImeTextSpan(*span));
   }
 
-  GetInputContext()->UpdateCompositionText(
-      std::move(composition), /*cursor_pos=*/composition.text.length(),
-      /*visible=*/true);
+  GetInputContext()->UpdateCompositionText(std::move(composition),
+                                           /*cursor_pos=*/new_cursor_position,
+                                           /*visible=*/true);
 }
 
 void NativeInputMethodEngine::ImeObserver::SetCompositionRange(
diff --git a/chrome/browser/ash/input_method/native_input_method_engine.h b/chrome/browser/ash/input_method/native_input_method_engine.h
index f79cafe..233f8f1 100644
--- a/chrome/browser/ash/input_method/native_input_method_engine.h
+++ b/chrome/browser/ash/input_method/native_input_method_engine.h
@@ -142,7 +142,8 @@
                         cursor_behavior) override;
     void SetComposition(
         const std::u16string& text,
-        std::vector<chromeos::ime::mojom::CompositionSpanPtr> spans) override;
+        std::vector<chromeos::ime::mojom::CompositionSpanPtr> spans,
+        uint32_t new_cursor_position) override;
     void SetCompositionRange(uint32_t start_index, uint32_t end_index) override;
     void FinishComposition() override;
     void DeleteSurroundingText(uint32_t num_before_cursor,
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc
index 9be6f55..8b18f66 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc
+++ b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
 #include "chrome/browser/external_protocol/external_protocol_handler.h"
+#include "chrome/browser/profiles/profile.h"
 #if defined(OS_ANDROID)
 #include "chrome/browser/profiles/profile_android.h"
 #endif
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc
index f44352e..d09a7fd8 100644
--- a/chrome/browser/chrome_navigation_browsertest.cc
+++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -379,15 +379,13 @@
   content::WebContents* new_web_contents =
       browser()->tab_strip_model()->GetWebContentsAt(index_of_new_tab);
 
-  // Verify that the load fails (because of the wrong "scheme" - www.foo.com is
-  // not a real scheme).
-  EXPECT_FALSE(WaitForLoadStop(new_web_contents));
-
   // Verify that the invalid URL was not committed.
   content::NavigationController& navigation_controller =
       new_web_contents->GetController();
-  EXPECT_EQ(nullptr, navigation_controller.GetLastCommittedEntry());
-  EXPECT_EQ(0, navigation_controller.GetEntryCount());
+  WaitForLoadStop(new_web_contents);
+  EXPECT_TRUE(navigation_controller.GetLastCommittedEntry()->IsInitialEntry());
+  EXPECT_EQ(1, navigation_controller.GetEntryCount());
+  EXPECT_NE(new_tab_url, new_web_contents->GetLastCommittedURL());
 
   // Verify that the pending entry is still present, even though the navigation
   // has failed and didn't commit.  We preserve the pending entry if it is a
@@ -445,8 +443,14 @@
     EXPECT_TRUE(ExecuteScript(main_contents, "simulateClick()"));
     content::WebContents* new_contents = new_tab_observer.GetWebContents();
 
-    // The load in the new window should fail.
-    EXPECT_FALSE(WaitForLoadStop(new_contents));
+    // Verify that the invalid URL was not committed.
+    content::NavigationController& navigation_controller =
+        new_contents->GetController();
+    WaitForLoadStop(new_contents);
+    EXPECT_TRUE(
+        navigation_controller.GetLastCommittedEntry()->IsInitialEntry());
+    EXPECT_EQ(1, navigation_controller.GetEntryCount());
+    EXPECT_NE(test_url, new_contents->GetLastCommittedURL());
 
     // Ensure that the omnibox doesn't start with javascript: scheme.
     EXPECT_EQ(test_url, new_contents->GetVisibleURL());
@@ -968,10 +972,10 @@
   }
 }
 
-// Tests scenario where a blank iframe inside a blank popup (a popup with no
-// navigation entry) does a same document navigation. This test was added as a
-// regression test for crbug.com/1237874. The main purpose of this test is to
-// ensure that WebContentsObservers and Chrome features don't crash.
+// Tests scenario where a blank iframe inside a blank popup (a popup with only
+// the initial navigation entry) does a same document navigation. This test was
+// added as a regression test for crbug.com/1237874. The main purpose of this
+// test is to ensure that WebContentsObservers and Chrome features don't crash.
 IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                        SameDocumentNavigationInIframeInBlankDocument) {
   ASSERT_TRUE(ui_test_utils::NavigateToURL(
@@ -988,8 +992,8 @@
     popup = popup_observer.GetWebContents();
   }
   content::RenderFrameHost* popup_main_rfh = popup->GetMainFrame();
-  // Popup shouldn't have a navigation entry.
-  EXPECT_EQ(popup->GetController().GetLastCommittedEntry(), nullptr);
+  // Popup should be on the initial entry.
+  EXPECT_TRUE(popup->GetController().GetLastCommittedEntry()->IsInitialEntry());
 
   // 2. Add blank iframe in popup.
   EXPECT_TRUE(content::ExecJs(popup_main_rfh,
@@ -1007,15 +1011,15 @@
     navigation_manager.WaitForNavigationFinished();
   }
 
-  // Check that same-document navigation doesn't commit a new navigation entry
-  // if no entry existed previously.
-  EXPECT_EQ(popup->GetController().GetLastCommittedEntry(), nullptr);
+  // Check that same-document navigation doesn't commit a new navigation entry,
+  // but instead reuses the initial entry.
+  EXPECT_TRUE(popup->GetController().GetLastCommittedEntry()->IsInitialEntry());
 }
 
 // Test scenario where we attempt a synchronous renderer-initiated same-document
-// navigation inside a blank popup (a popup with no navigation entry).
-// Regression test for crbug.com/1254238. The main purpose of this test is to
-// ensure that WebContentsObservers and Chrome features don't crash.
+// navigation inside a blank popup (a popup with only the initial navigation
+// entry). Regression test for crbug.com/1254238. The main purpose of this test
+// is to ensure that WebContentsObservers and Chrome features don't crash.
 IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                        SameDocumentNavigationInBlankPopup) {
   ASSERT_TRUE(
@@ -1023,7 +1027,7 @@
   content::RenderFrameHost* opener =
       browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame();
 
-  // 1. Create a new blank window that won't create a NavigationEntry.
+  // 1. Create a new blank window that will stay on the initial NavigationEntry.
   content::WebContents* popup = nullptr;
   {
     content::WebContentsAddedObserver popup_observer;
@@ -1032,8 +1036,8 @@
         content::JsReplace("var w = window.open($1, 'my-popup')", GURL())));
     popup = popup_observer.GetWebContents();
   }
-  // Popup shouldn't have a navigation entry.
-  EXPECT_EQ(popup->GetController().GetLastCommittedEntry(), nullptr);
+  // Popup should be on the initial navigation entry.
+  EXPECT_TRUE(popup->GetController().GetLastCommittedEntry()->IsInitialEntry());
 
   // 2. Same-document navigation in popup.
   {
@@ -1043,8 +1047,9 @@
         content::ExecJs(opener, "w.history.replaceState({}, '', '#foo');"));
     navigation_manager.WaitForNavigationFinished();
   }
-  // Popup still shouldn't have a navigation entry.
-  EXPECT_EQ(popup->GetController().GetLastCommittedEntry(), nullptr);
+  // Popup should no longer be on the initial navigation entry.
+  EXPECT_FALSE(
+      popup->GetController().GetLastCommittedEntry()->IsInitialEntry());
 }
 
 class SignInIsolationBrowserTest : public ChromeNavigationBrowserTest {
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 6fc8444..cd38d40 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -555,6 +555,10 @@
     "../ash/accessibility/magnifier_type.h",
     "../ash/accessibility/select_to_speak_event_handler_delegate_impl.cc",
     "../ash/accessibility/select_to_speak_event_handler_delegate_impl.h",
+    "../ash/account_manager/account_apps_availability.cc",
+    "../ash/account_manager/account_apps_availability.h",
+    "../ash/account_manager/account_apps_availability_factory.cc",
+    "../ash/account_manager/account_apps_availability_factory.h",
     "../ash/account_manager/account_manager_edu_coexistence_controller.cc",
     "../ash/account_manager/account_manager_edu_coexistence_controller.h",
     "../ash/account_manager/account_manager_facade_factory_ash.cc",
@@ -1634,6 +1638,8 @@
     "../ash/input_method/grammar_manager.h",
     "../ash/input_method/grammar_service_client.cc",
     "../ash/input_method/grammar_service_client.h",
+    "../ash/input_method/ime_rules_config.cc",
+    "../ash/input_method/ime_rules_config.h",
     "../ash/input_method/ime_service_connector.cc",
     "../ash/input_method/ime_service_connector.h",
     "../ash/input_method/input_host_helper.cc",
@@ -4150,6 +4156,7 @@
     "../ash/input_method/fake_suggestion_handler.h",
     "../ash/input_method/grammar_manager_unittest.cc",
     "../ash/input_method/grammar_service_client_unittest.cc",
+    "../ash/input_method/ime_rules_config_unittest.cc",
     "../ash/input_method/input_method_configuration_unittest.cc",
     "../ash/input_method/input_method_engine_unittest.cc",
     "../ash/input_method/input_method_manager_impl_unittest.cc",
diff --git a/chrome/browser/custom_handlers/chrome_protocol_handler_registry_delegate.cc b/chrome/browser/custom_handlers/chrome_protocol_handler_registry_delegate.cc
new file mode 100644
index 0000000..d3c41af
--- /dev/null
+++ b/chrome/browser/custom_handlers/chrome_protocol_handler_registry_delegate.cc
@@ -0,0 +1,102 @@
+// 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/custom_handlers/chrome_protocol_handler_registry_delegate.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/check_op.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "chrome/browser/profiles/profile_io_data.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "components/user_prefs/user_prefs.h"
+#include "content/public/browser/child_process_security_policy.h"
+
+class PrefService;
+
+using content::BrowserThread;
+using content::ChildProcessSecurityPolicy;
+
+ChromeProtocolHandlerRegistryDelegate::ChromeProtocolHandlerRegistryDelegate() =
+    default;
+
+ChromeProtocolHandlerRegistryDelegate::
+    ~ChromeProtocolHandlerRegistryDelegate() = default;
+
+// ProtocolHandlerRegistry::Delegate:
+void ChromeProtocolHandlerRegistryDelegate::RegisterExternalHandler(
+    const std::string& protocol) {
+  ChildProcessSecurityPolicy* policy =
+      ChildProcessSecurityPolicy::GetInstance();
+  if (!policy->IsWebSafeScheme(protocol)) {
+    policy->RegisterWebSafeScheme(protocol);
+  }
+}
+
+bool ChromeProtocolHandlerRegistryDelegate::IsExternalHandlerRegistered(
+    const std::string& protocol) {
+  // NOTE(koz): This function is safe to call from any thread, despite living
+  // in ProfileIOData.
+  return ProfileIOData::IsHandledProtocol(protocol);
+}
+
+void ChromeProtocolHandlerRegistryDelegate::RegisterWithOSAsDefaultClient(
+    const std::string& protocol,
+    DefaultClientCallback callback) {
+  // The worker pointer is reference counted. While it is running, the
+  // sequence it runs on will hold references it will be automatically freed
+  // once all its tasks have finished.
+  base::MakeRefCounted<shell_integration::DefaultProtocolClientWorker>(protocol)
+      ->StartSetAsDefault(
+          GetDefaultWebClientCallback(protocol, std::move(callback)));
+}
+
+void ChromeProtocolHandlerRegistryDelegate::CheckDefaultClientWithOS(
+    const std::string& protocol,
+    DefaultClientCallback callback) {
+  // The worker pointer is reference counted. While it is running, the
+  // sequence it runs on will hold references it will be automatically freed
+  // once all its tasks have finished.
+  base::MakeRefCounted<shell_integration::DefaultProtocolClientWorker>(protocol)
+      ->StartCheckIsDefault(
+          GetDefaultWebClientCallback(protocol, std::move(callback)));
+}
+
+// If true default protocol handlers will be removed if the OS level
+// registration for a protocol is no longer Chrome.
+bool ChromeProtocolHandlerRegistryDelegate::ShouldRemoveHandlersNotInOS() {
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+  // We don't do this on Linux as the OS registration there is not reliable,
+  // and Chrome OS doesn't have any notion of OS registration.
+  // TODO(benwells): When Linux support is more reliable remove this
+  // difference (http://crbug.com/88255).
+  return false;
+#else
+  return shell_integration::GetDefaultWebClientSetPermission() !=
+         shell_integration::SET_DEFAULT_NOT_ALLOWED;
+#endif
+}
+
+void ChromeProtocolHandlerRegistryDelegate::
+    OnSetAsDefaultProtocolClientFinished(
+        const std::string& protocol,
+        DefaultClientCallback callback,
+        shell_integration::DefaultWebClientState state) {
+  bool is_default = state != shell_integration::NOT_DEFAULT &&
+                    state != shell_integration::OTHER_MODE_IS_DEFAULT;
+  std::move(callback).Run(is_default);
+}
+
+shell_integration::DefaultWebClientWorkerCallback
+ChromeProtocolHandlerRegistryDelegate::GetDefaultWebClientCallback(
+    const std::string& protocol,
+    DefaultClientCallback callback) {
+  return base::BindOnce(&ChromeProtocolHandlerRegistryDelegate::
+                            OnSetAsDefaultProtocolClientFinished,
+                        weak_ptr_factory_.GetWeakPtr(), protocol,
+                        std::move(callback));
+}
diff --git a/chrome/browser/custom_handlers/chrome_protocol_handler_registry_delegate.h b/chrome/browser/custom_handlers/chrome_protocol_handler_registry_delegate.h
new file mode 100644
index 0000000..361b412
--- /dev/null
+++ b/chrome/browser/custom_handlers/chrome_protocol_handler_registry_delegate.h
@@ -0,0 +1,58 @@
+// 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_CUSTOM_HANDLERS_CHROME_PROTOCOL_HANDLER_REGISTRY_DELEGATE_H_
+#define CHROME_BROWSER_CUSTOM_HANDLERS_CHROME_PROTOCOL_HANDLER_REGISTRY_DELEGATE_H_
+
+#include <set>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
+#include "chrome/browser/shell_integration.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+
+// This class implements the ProtocolHandlerRegistry::Delegate
+// abstract class to provide an OS dependent implementation to handle
+// the user preferences and deal with the //shell_integration module.
+class ChromeProtocolHandlerRegistryDelegate
+    : public ProtocolHandlerRegistry::Delegate {
+ public:
+  ChromeProtocolHandlerRegistryDelegate();
+  ~ChromeProtocolHandlerRegistryDelegate() override;
+
+  ChromeProtocolHandlerRegistryDelegate(
+      const ChromeProtocolHandlerRegistryDelegate& other) = delete;
+  ChromeProtocolHandlerRegistryDelegate& operator=(
+      const ChromeProtocolHandlerRegistryDelegate& other) = delete;
+
+  // ProtocolHandlerRegistry::Delegate:
+  void RegisterExternalHandler(const std::string& protocol) override;
+  bool IsExternalHandlerRegistered(const std::string& protocol) override;
+  void RegisterWithOSAsDefaultClient(const std::string& protocol,
+                                     DefaultClientCallback callback) override;
+  void CheckDefaultClientWithOS(const std::string& protocol,
+                                DefaultClientCallback callback) override;
+  bool ShouldRemoveHandlersNotInOS() override;
+
+ private:
+  // Gets the callback for DefaultProtocolClientWorker.
+  shell_integration::DefaultWebClientWorkerCallback GetDefaultWebClientCallback(
+      const std::string& protocol,
+      DefaultClientCallback callback);
+
+  // Called with the default state when the default protocol client worker is
+  // done.
+  void OnSetAsDefaultProtocolClientFinished(
+      const std::string& protocol,
+      DefaultClientCallback callback,
+      shell_integration::DefaultWebClientState state);
+
+  // Makes it possible to invalidate the callback for the
+  // DefaultProtocolClientWorker.
+  base::WeakPtrFactory<ChromeProtocolHandlerRegistryDelegate> weak_ptr_factory_{
+      this};
+};
+
+#endif  // CHROME_BROWSER_CUSTOM_HANDLERS_CHROME_PROTOCOL_HANDLER_REGISTRY_DELEGATE_H_
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.cc b/chrome/browser/custom_handlers/protocol_handler_registry.cc
index 1faead6..eeb76dd 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry.cc
@@ -57,87 +57,6 @@
 
 }  // namespace
 
-// Delegate --------------------------------------------------------------------
-
-ProtocolHandlerRegistry::Delegate::Delegate() = default;
-
-ProtocolHandlerRegistry::Delegate::~Delegate() = default;
-
-void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler(
-    const std::string& protocol) {
-  ChildProcessSecurityPolicy* policy =
-    ChildProcessSecurityPolicy::GetInstance();
-  if (!policy->IsWebSafeScheme(protocol)) {
-    policy->RegisterWebSafeScheme(protocol);
-  }
-}
-
-void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler(
-    const std::string& protocol) {
-}
-
-bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered(
-    const std::string& protocol) {
-  // NOTE(koz): This function is safe to call from any thread, despite living
-  // in ProfileIOData.
-  return ProfileIOData::IsHandledProtocol(protocol);
-}
-
-void ProtocolHandlerRegistry::Delegate::RegisterWithOSAsDefaultClient(
-    const std::string& protocol,
-    DefaultClientCallback callback) {
-  // The worker pointer is reference counted. While it is running, the
-  // sequence it runs on will hold references it will be automatically freed
-  // once all its tasks have finished.
-  base::MakeRefCounted<shell_integration::DefaultProtocolClientWorker>(protocol)
-      ->StartSetAsDefault(
-          GetDefaultWebClientCallback(protocol, std::move(callback)));
-}
-
-void ProtocolHandlerRegistry::Delegate::CheckDefaultClientWithOS(
-    const std::string& protocol,
-    DefaultClientCallback callback) {
-  // The worker pointer is reference counted. While it is running, the
-  // sequence it runs on will hold references it will be automatically freed
-  // once all its tasks have finished.
-  base::MakeRefCounted<shell_integration::DefaultProtocolClientWorker>(protocol)
-      ->StartCheckIsDefault(
-          GetDefaultWebClientCallback(protocol, std::move(callback)));
-}
-
-// If true default protocol handlers will be removed if the OS level
-// registration for a protocol is no longer Chrome.
-bool ProtocolHandlerRegistry::Delegate::ShouldRemoveHandlersNotInOS() {
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
-  // We don't do this on Linux as the OS registration there is not reliable,
-  // and Chrome OS doesn't have any notion of OS registration.
-  // TODO(benwells): When Linux support is more reliable remove this
-  // difference (http://crbug.com/88255).
-  return false;
-#else
-  return shell_integration::GetDefaultWebClientSetPermission() !=
-         shell_integration::SET_DEFAULT_NOT_ALLOWED;
-#endif
-}
-
-shell_integration::DefaultWebClientWorkerCallback
-ProtocolHandlerRegistry::Delegate::GetDefaultWebClientCallback(
-    const std::string& protocol,
-    DefaultClientCallback callback) {
-  return base::BindOnce(
-      &ProtocolHandlerRegistry::Delegate::OnSetAsDefaultProtocolClientFinished,
-      weak_ptr_factory_.GetWeakPtr(), protocol, std::move(callback));
-}
-
-void ProtocolHandlerRegistry::Delegate::OnSetAsDefaultProtocolClientFinished(
-    const std::string& protocol,
-    DefaultClientCallback callback,
-    shell_integration::DefaultWebClientState state) {
-  bool is_default = state != shell_integration::NOT_DEFAULT &&
-                    state != shell_integration::OTHER_MODE_IS_DEFAULT;
-  std::move(callback).Run(is_default);
-}
-
 // ProtocolHandlerRegistry -----------------------------------------------------
 
 ProtocolHandlerRegistry::ProtocolHandlerRegistry(
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.h b/chrome/browser/custom_handlers/protocol_handler_registry.h
index 5c6b14c..c51e957 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry.h
+++ b/chrome/browser/custom_handlers/protocol_handler_registry.h
@@ -15,9 +15,8 @@
 #include "base/observer_list.h"
 #include "base/task/sequenced_task_runner_helpers.h"
 #include "base/values.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/shell_integration.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/custom_handlers/protocol_handler.h"
 
@@ -49,34 +48,19 @@
   // as the default handler for specific protocols.
   class Delegate {
    public:
-    Delegate();
-    virtual ~Delegate();
-    virtual void RegisterExternalHandler(const std::string& protocol);
-    virtual void DeregisterExternalHandler(const std::string& protocol);
-    virtual bool IsExternalHandlerRegistered(const std::string& protocol);
-    virtual void RegisterWithOSAsDefaultClient(const std::string& protocol,
-                                               DefaultClientCallback callback);
-    virtual void CheckDefaultClientWithOS(const std::string& protocol,
-                                          DefaultClientCallback callback);
-    virtual bool ShouldRemoveHandlersNotInOS();
-
-   private:
-    // Gets the callback for DefaultProtocolClientWorker.
-    shell_integration::DefaultWebClientWorkerCallback
-    GetDefaultWebClientCallback(const std::string& protocol,
-                                DefaultClientCallback callback);
-
-    // Called with the default state when the default protocol client worker is
-    // done.
-    void OnSetAsDefaultProtocolClientFinished(
+    virtual ~Delegate() = default;
+    virtual void RegisterExternalHandler(const std::string& protocol) = 0;
+    virtual bool IsExternalHandlerRegistered(const std::string& protocol) = 0;
+    virtual void RegisterWithOSAsDefaultClient(
         const std::string& protocol,
-        DefaultClientCallback callback,
-        shell_integration::DefaultWebClientState state);
+        DefaultClientCallback callback) = 0;
+    virtual void CheckDefaultClientWithOS(const std::string& protocol,
+                                          DefaultClientCallback callback) = 0;
+    virtual bool ShouldRemoveHandlersNotInOS() = 0;
 
-    // Makes it possible to invalidate the callback for the
-    // DefaultProtocolClientWorker.
-    base::WeakPtrFactory<ProtocolHandlerRegistry::Delegate> weak_ptr_factory_{
-        this};
+    // Only implemented by TestProtocolHandlerRegistryDelegate and FakeDelegate,
+    // hence only used for testing purposes.
+    virtual void DeregisterExternalHandler(const std::string& protocol) {}
   };
 
   class Observer : public base::CheckedObserver {
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc b/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc
index 06a1b25..ccb2573 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_factory.cc
@@ -9,6 +9,7 @@
 #include "base/memory/singleton.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
+#include "chrome/browser/custom_handlers/chrome_protocol_handler_registry_delegate.h"
 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
@@ -58,7 +59,7 @@
 KeyedService* ProtocolHandlerRegistryFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   ProtocolHandlerRegistry* registry = new ProtocolHandlerRegistry(
-      context, std::make_unique<ProtocolHandlerRegistry::Delegate>());
+      context, std::make_unique<ChromeProtocolHandlerRegistryDelegate>());
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // If installing defaults, they must be installed prior calling
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
index 37c5f3d..bd5058bd 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
@@ -83,6 +83,11 @@
     return registered_protocols_.find(protocol) != registered_protocols_.end();
   }
 
+  void CheckDefaultClientWithOS(const std::string& protocol,
+                                DefaultClientCallback callback) override {}
+
+  bool ShouldRemoveHandlersNotInOS() override { return true; }
+
   bool IsFakeRegisteredWithOS(const std::string& protocol) {
     return os_registered_protocols_.find(protocol) !=
         os_registered_protocols_.end();
diff --git a/chrome/browser/custom_handlers/test_protocol_handler_registry_delegate.cc b/chrome/browser/custom_handlers/test_protocol_handler_registry_delegate.cc
index 4a0fde00..1aa0760 100644
--- a/chrome/browser/custom_handlers/test_protocol_handler_registry_delegate.cc
+++ b/chrome/browser/custom_handlers/test_protocol_handler_registry_delegate.cc
@@ -48,3 +48,7 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(std::move(callback), true));
 }
+
+bool TestProtocolHandlerRegistryDelegate::ShouldRemoveHandlersNotInOS() {
+  return true;
+}
diff --git a/chrome/browser/custom_handlers/test_protocol_handler_registry_delegate.h b/chrome/browser/custom_handlers/test_protocol_handler_registry_delegate.h
index 7cd82da6..3b348d14 100644
--- a/chrome/browser/custom_handlers/test_protocol_handler_registry_delegate.h
+++ b/chrome/browser/custom_handlers/test_protocol_handler_registry_delegate.h
@@ -31,6 +31,7 @@
                                      DefaultClientCallback callback) override;
   void CheckDefaultClientWithOS(const std::string& protocol,
                                 DefaultClientCallback callback) override;
+  bool ShouldRemoveHandlersNotInOS() override;
 
  private:
   // Holds registered protocols.
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index e5db5bb..e6b9e0a 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -831,7 +831,9 @@
     content::NavigationHandle* handle) {
   WebContents* web_contents = handle->GetWebContents();
   if (!web_contents || !web_contents->HasOriginalOpener() ||
-      web_contents->GetController().GetLastCommittedEntry()) {
+      !web_contents->GetController()
+           .GetLastCommittedEntry()
+           ->IsInitialEntry()) {
     return nullptr;
   }
 
diff --git a/chrome/browser/dom_distiller/tab_utils_browsertest.cc b/chrome/browser/dom_distiller/tab_utils_browsertest.cc
index 7b23101..e8f1322 100644
--- a/chrome/browser/dom_distiller/tab_utils_browsertest.cc
+++ b/chrome/browser/dom_distiller/tab_utils_browsertest.cc
@@ -174,8 +174,9 @@
   GURL article_url_;
 };
 
+// Disabled as flaky: https://crbug.com/1275025
 IN_PROC_BROWSER_TEST_F(DomDistillerTabUtilsBrowserTest,
-                       DistillCurrentPageSwapsWebContents) {
+                       DISABLED_DistillCurrentPageSwapsWebContents) {
   content::WebContents* initial_web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   TestDistillabilityObserver distillability_observer(initial_web_contents);
diff --git a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api_ash.cc b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api_ash.cc
index 0e3707b..473a16e 100644
--- a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api_ash.cc
+++ b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api_ash.cc
@@ -6,7 +6,7 @@
 
 #include "base/values.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
-#include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/browser/ash/crosapi/crosapi_util.h"
 #include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
 #include "chrome/browser/ash/policy/handlers/device_name_policy_handler.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
diff --git a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
index c48465a5..ad44c23 100644
--- a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
+++ b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
@@ -9,6 +9,7 @@
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/api/identity/identity_api.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/signin/public/base/multilogin_parameters.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
@@ -27,10 +28,6 @@
 #include "chrome/browser/ash/account_manager/account_manager_util.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-#include "chrome/browser/lacros/account_manager/account_manager_util.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
-
 namespace extensions {
 
 namespace {
@@ -174,7 +171,7 @@
   DCHECK(ash::IsAccountManagerAvailable(profile_));
   SetAccountsInCookie();
 #elif BUILDFLAG(IS_CHROMEOS_LACROS)
-  if (IsAccountManagerAvailable(profile_))
+  if (AccountConsistencyModeManager::IsMirrorEnabledForProfile(profile_))
     SetAccountsInCookie();
 #endif
 }
diff --git a/chrome/browser/extensions/extension_action_runner.cc b/chrome/browser/extensions/extension_action_runner.cc
index b2861af..18a84d9 100644
--- a/chrome/browser/extensions/extension_action_runner.cc
+++ b/chrome/browser/extensions/extension_action_runner.cc
@@ -263,13 +263,6 @@
     const Extension* extension) {
   DCHECK(extension);
 
-  content::NavigationEntry* visible_entry =
-      web_contents()->GetController().GetVisibleEntry();
-  // Refuse to run if there's no visible entry, because we have no idea of
-  // determining if it's the proper page. This should rarely, if ever, happen.
-  if (!visible_entry)
-    return;
-
   // We add this to the list of permitted extensions and erase pending entries
   // *before* running them to guard against the crazy case where running the
   // callbacks adds more entries.
diff --git a/chrome/browser/favicon/content_favicon_driver_browsertest.cc b/chrome/browser/favicon/content_favicon_driver_browsertest.cc
index 4ef3d2b..1837780d2 100644
--- a/chrome/browser/favicon/content_favicon_driver_browsertest.cc
+++ b/chrome/browser/favicon/content_favicon_driver_browsertest.cc
@@ -31,6 +31,7 @@
 #include "components/favicon/core/favicon_service.h"
 #include "components/network_session_configurator/common/network_switches.h"
 #include "content/public/browser/browsing_data_remover.h"
+#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/browser_test.h"
@@ -342,18 +343,18 @@
   prerender_helper().WaitForRequest(icon_url, 1);
 }
 
-class NoCommittedEntryWebContentsObserver
+class NoCommittedNavigationWebContentsObserver
     : public content::WebContentsObserver {
  public:
-  explicit NoCommittedEntryWebContentsObserver(
+  explicit NoCommittedNavigationWebContentsObserver(
       content::WebContents* web_contents) {
     Observe(web_contents);
   }
 
-  ~NoCommittedEntryWebContentsObserver() override = default;
+  ~NoCommittedNavigationWebContentsObserver() override = default;
 
-  bool DidUpdateFaviconURLWithNoCommittedEntry() const {
-    return did_update_favicon_url_with_no_committed_entry_;
+  bool DidUpdateFaviconURLWithNoCommittedNavigation() const {
+    return did_update_favicon_url_with_no_committed_navigation_;
   }
 
  protected:
@@ -362,28 +363,29 @@
       content::RenderFrameHost* rfh,
       const std::vector<blink::mojom::FaviconURLPtr>& candidates) override {
     auto* web_contents = content::WebContents::FromRenderFrameHost(rfh);
-    if (!web_contents->GetController().GetLastCommittedEntry()) {
-      did_update_favicon_url_with_no_committed_entry_ = true;
+    if (web_contents->GetController()
+            .GetLastCommittedEntry()
+            ->IsInitialEntry()) {
+      did_update_favicon_url_with_no_committed_navigation_ = true;
     }
   }
 
  private:
-  bool did_update_favicon_url_with_no_committed_entry_ = false;
+  bool did_update_favicon_url_with_no_committed_navigation_ = false;
 };
 
 // Observes the creation of new tabs and, upon creation, sets up both a pending
 // task waiter (to ensure that ContentFaviconDriver tasks complete) and a
-// NoCommittedEntryWebContentsObserver (to ensure that we observe the expected
-// function calls).
-class FaviconUpdateNoLastCommittedEntryTabStripObserver
+// NoCommittedNavigationWebContentsObserver (to ensure that we observe the
+// expected function calls).
+class FaviconUpdateOnlyInitialEntryTabStripObserver
     : public TabStripModelObserver {
  public:
-  explicit FaviconUpdateNoLastCommittedEntryTabStripObserver(
-      TabStripModel* model)
+  explicit FaviconUpdateOnlyInitialEntryTabStripObserver(TabStripModel* model)
       : model_(model) {
     model_->AddObserver(this);
   }
-  ~FaviconUpdateNoLastCommittedEntryTabStripObserver() override {
+  ~FaviconUpdateOnlyInitialEntryTabStripObserver() override {
     model_->RemoveObserver(this);
   }
 
@@ -392,8 +394,8 @@
       run_loop_.Run();
   }
 
-  bool DidUpdateFaviconURLWithNoCommittedEntry() const {
-    return observer_->DidUpdateFaviconURLWithNoCommittedEntry();
+  bool DidUpdateFaviconURLWithNoCommittedNavigation() const {
+    return observer_->DidUpdateFaviconURLWithNoCommittedNavigation();
   }
 
   PendingTaskWaiter* pending_task_waiter() {
@@ -410,8 +412,8 @@
       return;
     auto* web_contents = model_->GetActiveWebContents();
     pending_task_waiter_ = std::make_unique<PendingTaskWaiter>(web_contents);
-    observer_ =
-        std::make_unique<NoCommittedEntryWebContentsObserver>(web_contents);
+    observer_ = std::make_unique<NoCommittedNavigationWebContentsObserver>(
+        web_contents);
     run_loop_.Quit();
   }
 
@@ -419,15 +421,15 @@
   base::RunLoop run_loop_;
   raw_ptr<TabStripModel> model_ = nullptr;
   std::unique_ptr<PendingTaskWaiter> pending_task_waiter_;
-  std::unique_ptr<NoCommittedEntryWebContentsObserver> observer_;
+  std::unique_ptr<NoCommittedNavigationWebContentsObserver> observer_;
 };
 
 // Tests that ContentFaviconDriver can handle being sent updated favicon URLs
-// if there is no last committed entry. This occurs when script is injected in
-// about:blank in a newly created window. See crbug.com/520759 for more
-// details.
+// if there is no committed navigation, so it will use the initial
+// NavigationEntry. This occurs when script is injected in the initial empty
+// document of a newly created window. See crbug.com/520759 for more details.
 IN_PROC_BROWSER_TEST_F(ContentFaviconDriverTest,
-                       FaviconUpdateNoLastCommittedEntry) {
+                       FaviconUpdateOnlyInitialEntry) {
   const char kNoContentPath[] = "/nocontent";
   embedded_test_server()->RegisterRequestHandler(
       base::BindRepeating(&NoContentResponseHandler, kNoContentPath));
@@ -436,7 +438,7 @@
   GURL empty_url = embedded_test_server()->GetURL("/empty.html");
   GURL no_content_url = embedded_test_server()->GetURL("/nocontent");
 
-  FaviconUpdateNoLastCommittedEntryTabStripObserver observer(
+  FaviconUpdateOnlyInitialEntryTabStripObserver observer(
       browser()->tab_strip_model());
 
   auto* rfh = ui_test_utils::NavigateToURLWithDisposition(
@@ -459,7 +461,7 @@
   observer.pending_task_waiter()->Wait();
 
   // We expect DidUpdateFaviconURL to be called and for no crash to ensue.
-  EXPECT_TRUE(observer.DidUpdateFaviconURLWithNoCommittedEntry());
+  EXPECT_TRUE(observer.DidUpdateFaviconURLWithNoCommittedNavigation());
 }
 
 // Test that when a user reloads a page ignoring the cache that the favicon is
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 7ca0e1d8..deeecbf 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1028,11 +1028,6 @@
     "expiry_milestone": 100
   },
   {
-    "name": "decode-jpeg-images-to-yuv",
-    "owners": [ "sashamcintosh", "chromeos-gfx@google.com" ],
-    "expiry_milestone": 88
-  },
-  {
     "name": "default-browser-fullscreen-promo-cta-experiment",
     "owners": [ "javierrobles", "bling-flags@google.com" ],
     "expiry_milestone": 93
@@ -3887,11 +3882,6 @@
     "expiry_milestone": 84
   },
   {
-    "name": "multi-profile-account-consistency",
-    "owners": [ "droger", "sinhak", "team-dent@google.com"],
-    "expiry_milestone": 102
-  },
-  {
     "name": "mute-notification-snooze-action",
     "owners": [ "knollr@chromium.org", "peter@chromium.org" ],
     "expiry_milestone": 96
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 9a2d2cca..2da0557 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -589,11 +589,6 @@
     "Enables the dark/light mode of system UI, which includes shelf, launcher, "
     "system tray etc.";
 
-const char kDecodeJpeg420ImagesToYUVName[] = "YUV decoding for JPEG";
-const char kDecodeJpeg420ImagesToYUVDescription[] =
-    "Decode and render 4:2:0 formatted jpeg images from YUV instead of RGB."
-    "This feature requires GPU or OOP rasterization to also be enabled.";
-
 const char kDevicePostureName[] = "Device Posture API";
 const char kDevicePostureDescription[] =
     "Enables Device Posture API (foldable devices)";
@@ -5245,14 +5240,6 @@
 
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-extern const char kMultiProfileAccountConsistencyName[] =
-    "Account consistency for multi-profile.";
-extern const char kMultiProfileAccountConsistencyDescription[] =
-    "Enables integration of secondary profiles with the ChromeOS Account "
-    "Manager.";
-#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
-
 #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
 const char kAllowDefaultWebAppMigrationForChromeOsManagedUsersName[] =
     "Allow default web app migration for Chrome OS managed users";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 294b4f0..ed814e5 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -342,9 +342,6 @@
 extern const char kDarkLightTestName[];
 extern const char kDarkLightTestDescription[];
 
-extern const char kDecodeJpeg420ImagesToYUVName[];
-extern const char kDecodeJpeg420ImagesToYUVDescription[];
-
 extern const char kDetectTargetEmbeddingLookalikesName[];
 extern const char kDetectTargetEmbeddingLookalikesDescription[];
 
@@ -3033,11 +3030,6 @@
 
 #endif  // #if BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-extern const char kMultiProfileAccountConsistencyName[];
-extern const char kMultiProfileAccountConsistencyDescription[];
-#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
-
 #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
 extern const char kAllowDefaultWebAppMigrationForChromeOsManagedUsersName[];
 extern const char
diff --git a/chrome/browser/lacros/account_manager/account_manager_util.cc b/chrome/browser/lacros/account_manager/account_manager_util.cc
index d21cef9..7e46743 100644
--- a/chrome/browser/lacros/account_manager/account_manager_util.cc
+++ b/chrome/browser/lacros/account_manager/account_manager_util.cc
@@ -4,11 +4,15 @@
 
 #include "chrome/browser/lacros/account_manager/account_manager_util.h"
 
+#include <algorithm>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
 #include "base/containers/cxx20_erase.h"
 #include "base/containers/flat_set.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profiles_state.h"
-#include "chrome/browser/signin/signin_features.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 
 namespace {
 
@@ -76,25 +80,6 @@
 
 }  // namespace
 
-bool IsAccountManagerAvailable(const Profile* profile) {
-  // Account Manager / Mirror is only enabled on Lacros's Main Profile for now.
-  if (!profile->IsMainProfile())
-    return base::FeatureList::IsEnabled(kMultiProfileAccountConsistency);
-
-  // TODO(anastasiian): check for Web kiosk mode.
-
-  // Account Manager is unavailable on Guest (Incognito) Sessions.
-  if (profile->IsGuestSession() || profile->IsOffTheRecord())
-    return false;
-
-  // Account Manager is unavailable on Managed Guest Sessions / Public Sessions.
-  if (profiles::IsPublicSession())
-    return false;
-
-  // Available in all other cases.
-  return true;
-}
-
 void GetAccountsAvailableAsPrimary(
     AccountProfileMapper* mapper,
     ProfileAttributesStorage* storage,
diff --git a/chrome/browser/lacros/account_manager/account_manager_util.h b/chrome/browser/lacros/account_manager/account_manager_util.h
index 09d67783..16f65193 100644
--- a/chrome/browser/lacros/account_manager/account_manager_util.h
+++ b/chrome/browser/lacros/account_manager/account_manager_util.h
@@ -7,11 +7,8 @@
 
 #include "chrome/browser/lacros/account_manager/account_profile_mapper.h"
 
-class Profile;
 class ProfileAttributesStorage;
 
-bool IsAccountManagerAvailable(const Profile* profile);
-
 // Lists accounts that are available as primary accounts for a new profile. This
 // passes back all accounts in the OS that are not used as syncing accounts in
 // some other profile. The accounts are returned in an arbitrary order. The only
diff --git a/chrome/browser/lacros/account_manager/account_manager_util_unittest.cc b/chrome/browser/lacros/account_manager/account_manager_util_unittest.cc
index ed1508e8..439ea19a 100644
--- a/chrome/browser/lacros/account_manager/account_manager_util_unittest.cc
+++ b/chrome/browser/lacros/account_manager/account_manager_util_unittest.cc
@@ -12,12 +12,10 @@
 #include "base/containers/flat_map.h"
 #include "base/files/file_path.h"
 #include "base/test/mock_callback.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/account_manager_core/account.h"
@@ -55,8 +53,7 @@
 class AccountManagerUtilTest : public testing::Test {
  public:
   AccountManagerUtilTest()
-      : scoped_feature_list_(kMultiProfileAccountConsistency),
-        testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {
+      : testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {
     CHECK(testing_profile_manager_.SetUp());
     main_path_ = GetProfilePath("Default");
     ON_CALL(mock_facade_, GetPersistentErrorForAccount)
@@ -142,7 +139,6 @@
   }
 
  private:
-  base::test::ScopedFeatureList scoped_feature_list_;
   content::BrowserTaskEnvironment task_environment_;
   testing::NiceMock<account_manager::MockAccountManagerFacade> mock_facade_;
   TestingProfileManager testing_profile_manager_;
diff --git a/chrome/browser/lacros/account_manager/account_profile_mapper.cc b/chrome/browser/lacros/account_manager/account_profile_mapper.cc
index 5e1f49b..af0da36 100644
--- a/chrome/browser/lacros/account_manager/account_profile_mapper.cc
+++ b/chrome/browser/lacros/account_manager/account_profile_mapper.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_metrics.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "components/account_manager_core/account.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher_immediate_error.h"
@@ -49,7 +48,6 @@
       profile_attributes_storage_(storage),
       account_cache_(local_state) {
   DCHECK(profile_attributes_storage_);
-  DCHECK(base::FeatureList::IsEnabled(kMultiProfileAccountConsistency));
 
   // This must be done before OnGetAccountsCompleted() is called, to avoid
   // unnecessary profile deletion.
diff --git a/chrome/browser/lacros/account_manager/account_profile_mapper_unittest.cc b/chrome/browser/lacros/account_manager/account_profile_mapper_unittest.cc
index 53ffc715..4fa5567 100644
--- a/chrome/browser/lacros/account_manager/account_profile_mapper_unittest.cc
+++ b/chrome/browser/lacros/account_manager/account_profile_mapper_unittest.cc
@@ -13,13 +13,11 @@
 #include "base/files/file_path.h"
 #include "base/scoped_observation.h"
 #include "base/test/mock_callback.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_attributes_init_params.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/test/base/profile_waiter.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
@@ -147,8 +145,7 @@
 class AccountProfileMapperTest : public testing::Test {
  public:
   AccountProfileMapperTest()
-      : scoped_feature_list_(kMultiProfileAccountConsistency),
-        testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {
+      : testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {
     CHECK(testing_profile_manager_.SetUp());
     main_path_ = GetProfilePath("Default");
     ON_CALL(mock_facade_, GetPersistentErrorForAccount)
@@ -399,7 +396,6 @@
   }
 
  private:
-  base::test::ScopedFeatureList scoped_feature_list_;
   content::BrowserTaskEnvironment task_environment_;
   account_manager::MockAccountManagerFacade mock_facade_;
   std::queue<base::OnceCallback<void(const std::vector<Account>&)>>
diff --git a/chrome/browser/lacros/account_manager/profile_account_manager_unittest.cc b/chrome/browser/lacros/account_manager/profile_account_manager_unittest.cc
index f11e046..ab8dac8 100644
--- a/chrome/browser/lacros/account_manager/profile_account_manager_unittest.cc
+++ b/chrome/browser/lacros/account_manager/profile_account_manager_unittest.cc
@@ -7,9 +7,7 @@
 #include "base/check.h"
 #include "base/files/file_path.h"
 #include "base/scoped_observation.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/account_manager_core/account.h"
@@ -21,8 +19,7 @@
 class ProfileAccountManagerTest : public testing::Test {
  public:
   ProfileAccountManagerTest()
-      : scoped_feature_list_(kMultiProfileAccountConsistency),
-        testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {
+      : testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {
     CHECK(testing_profile_manager_.SetUp());
     testing_profile_manager_.SetAccountProfileMapper(
         std::make_unique<AccountProfileMapper>(
@@ -41,7 +38,6 @@
                 ->GetProfileAttributesStorage();
   }
 
-  base::test::ScopedFeatureList scoped_feature_list_;
   content::BrowserTaskEnvironment task_environment_;
   account_manager::MockAccountManagerFacade mock_facade_;
   TestingProfileManager testing_profile_manager_;
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/CredentialManagerLauncher.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/CredentialManagerLauncher.java
index 7ac74a2..65e73e2 100644
--- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/CredentialManagerLauncher.java
+++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/CredentialManagerLauncher.java
@@ -38,59 +38,25 @@
      * Retrieves a pending intent that can be used to launch the credential manager. The intent
      * is to either be used immediately or discarded.
      *
-     * TODO(crbug/1255038): Remove once the implementation is removed.
-     *
-     * @param referrer the place that will launch the credential manager
-     * @param accountName the account name that is syncing passwords.
-     * @param successCallback callback called with the intent if the retrieving was successful
-     * @param failureCallback callback called if the retrieving failed with the raised exception
-     */
-    @Deprecated
-    default void getCredentialManagerLaunchIntentForAccount(@ManagePasswordsReferrer int referrer,
-            String accountName, Callback<PendingIntent> successCallback,
-            Callback<Exception> failureCallback) {}
-
-    /**
-     * Retrieves a pending intent that can be used to launch the credential manager. The intent
-     * is to either be used immediately or discarded.
-     *
-     * TODO(crbug/1255038): Remove once the implementation is removed.
-     *
-     * @param referrer the place that will launch the credential manager
-     * @param successCallback callback called with the intent if the retrieving was successful
-     * @param failureCallback callback called if the retrieving failed with the raised exception
-     */
-    @Deprecated
-    default void getCredentialManagerLaunchIntentForLocal(@ManagePasswordsReferrer int referrer,
-            Callback<PendingIntent> successCallback, Callback<Exception> failureCallback) {}
-
-    /**
-     * Retrieves a pending intent that can be used to launch the credential manager. The intent
-     * is to either be used immediately or discarded.
-     *
-     * TODO(crbug/1255038): Change to abstract when implemented.
-     *
      * @param referrer the place that will launch the credential manager
      * @param accountName the account name that is syncing passwords.
      * @param successCallback callback called with the intent if the retrieving was successful
      * @param failureCallback callback called if the retrieving failed with the encountered error.
      *      The error should be a value from {@link CredentialManagerError}.
      */
-    default void getCredentialManagerIntentForAccount(@ManagePasswordsReferrer int referrer,
+    void getCredentialManagerIntentForAccount(@ManagePasswordsReferrer int referrer,
             String accountName, Callback<PendingIntent> successCallback,
-            Callback<Integer> failureCallback) {}
+            Callback<Integer> failureCallback);
 
     /**
      * Retrieves a pending intent that can be used to launch the credential manager. The intent
      * is to either be used immediately or discarded.
      *
-     * TODO(crbug/1255038): Change to abstract when implemented.
-     *
      * @param referrer the place that will launch the credential manager
      * @param successCallback callback called with the intent if the retrieving was successful
      * @param failureCallback callback called if the retrieving failed with the encountered error
      *      The error should be a value from {@link CredentialManagerError}.
      */
-    default void getCredentialManagerIntentForLocal(@ManagePasswordsReferrer int referrer,
-            Callback<PendingIntent> successCallback, Callback<Integer> failureCallback) {}
+    void getCredentialManagerIntentForLocal(@ManagePasswordsReferrer int referrer,
+            Callback<PendingIntent> successCallback, Callback<Integer> failureCallback);
 }
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java
index 7b29fbc0..04e8114 100644
--- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java
+++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java
@@ -8,8 +8,10 @@
 import android.app.PendingIntent.CanceledException;
 import android.content.Context;
 import android.os.Bundle;
+import android.os.SystemClock;
 
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.password_manager.CredentialManagerLauncher.CredentialManagerError;
 import org.chromium.chrome.browser.sync.SyncService;
 import org.chromium.components.browser_ui.settings.SettingsLauncher;
 import org.chromium.components.signin.base.CoreAccountInfo;
@@ -26,6 +28,23 @@
     // |PasswordSettings.class.getName()| once it's modularized.
     private static final String PASSWORD_SETTINGS_CLASS =
             "org.chromium.chrome.browser.password_manager.settings.PasswordSettings";
+    private static final String ACCOUNT_GET_INTENT_LATENCY_HISTOGRAM =
+            "PasswordManager.CredentialManager.Account.GetIntent.Latency";
+    private static final String ACCOUNT_GET_INTENT_SUCCESS_HISTOGRAM =
+            "PasswordManager.CredentialManager.Account.GetIntent.Success";
+    private static final String ACCOUNT_GET_INTENT_ERROR_HISTOGRAM =
+            "PasswordManager.CredentialManager.Account.GetIntent.Error";
+    private static final String ACCOUNT_LAUNCH_CREDENTIAL_MANAGER_SUCCESS_HISTOGRAM =
+            "PasswordManager.CredentialManager.Account.Launch.Success";
+
+    private static final String LOCAL_GET_INTENT_LATENCY_HISTOGRAM =
+            "PasswordManager.CredentialManager.LocalProfile.GetIntent.Latency";
+    private static final String LOCAL_GET_INTENT_SUCCESS_HISTOGRAM =
+            "PasswordManager.CredentialManager.LocalProfile.GetIntent.Success";
+    private static final String LOCAL_GET_INTENT_ERROR_HISTOGRAM =
+            "PasswordManager.CredentialManager.LocalProfile.GetIntent.Error";
+    private static final String LOCAL_LAUNCH_CREDENTIAL_MANAGER_SUCCESS_HISTOGRAM =
+            "PasswordManager.CredentialManager.LocalProfile.Launch.Success";
 
     /**
      * Launches the password settings or, if available, the credential manager from Google Play
@@ -47,14 +66,21 @@
         }
 
         if (hasChosenToSyncPasswords(syncService)) {
-            credentialManagerLauncher.getCredentialManagerLaunchIntentForAccount(referrer,
+            long startTimeMs = SystemClock.elapsedRealtime();
+            credentialManagerLauncher.getCredentialManagerIntentForAccount(referrer,
+
                     CoreAccountInfo.getEmailFrom(syncService.getAccountInfo()),
-                    PasswordManagerHelper::launchCredentialManager,
-                    PasswordManagerHelper::recordFailureMetrics);
+                    (intent)
+                            -> PasswordManagerHelper.launchCredentialManager(
+                                    intent, startTimeMs, true),
+                    (error) -> PasswordManagerHelper.recordFailureMetrics(error, true));
         } else {
-            credentialManagerLauncher.getCredentialManagerLaunchIntentForLocal(referrer,
-                    PasswordManagerHelper::launchCredentialManager,
-                    PasswordManagerHelper::recordFailureMetrics);
+            long startTimeMs = SystemClock.elapsedRealtime();
+            credentialManagerLauncher.getCredentialManagerIntentForLocal(referrer,
+                    (intent)
+                            -> PasswordManagerHelper.launchCredentialManager(
+                                    intent, startTimeMs, false),
+                    (error) -> PasswordManagerHelper.recordFailureMetrics(error, false));
         }
     }
 
@@ -96,15 +122,40 @@
         return true;
     }
 
-    private static void recordFailureMetrics(Exception exception) {
-        // TODO(crbug.com/1255038): Record metrics.
+    private static void recordFailureMetrics(
+            @CredentialManagerError int error, boolean forAccount) {
+        final String kGetIntentSuccessHistogram = forAccount ? ACCOUNT_GET_INTENT_SUCCESS_HISTOGRAM
+                                                             : LOCAL_GET_INTENT_SUCCESS_HISTOGRAM;
+        final String kGetIntentErrorHistogram =
+                forAccount ? ACCOUNT_GET_INTENT_ERROR_HISTOGRAM : LOCAL_GET_INTENT_ERROR_HISTOGRAM;
+        RecordHistogram.recordBooleanHistogram(kGetIntentSuccessHistogram, false);
+        RecordHistogram.recordEnumeratedHistogram(
+                kGetIntentErrorHistogram, error, CredentialManagerError.COUNT);
     }
 
-    private static void launchCredentialManager(PendingIntent intent) {
+    private static void launchCredentialManager(
+            PendingIntent intent, long startTimeMs, boolean forAccount) {
+        recordSuccessMetrics(SystemClock.elapsedRealtime() - startTimeMs, forAccount);
+
+        boolean launchIntentSuccessfully = true;
         try {
             intent.send();
         } catch (CanceledException e) {
-            // TODO(crbug.com/1255038): Record metrics.
+            launchIntentSuccessfully = false;
         }
+        RecordHistogram.recordBooleanHistogram(forAccount
+                        ? ACCOUNT_LAUNCH_CREDENTIAL_MANAGER_SUCCESS_HISTOGRAM
+                        : LOCAL_LAUNCH_CREDENTIAL_MANAGER_SUCCESS_HISTOGRAM,
+                launchIntentSuccessfully);
+    }
+
+    private static void recordSuccessMetrics(long elapsedTimeMs, boolean forAccount) {
+        final String kGetIntentLatencyHistogram = forAccount ? ACCOUNT_GET_INTENT_LATENCY_HISTOGRAM
+                                                             : LOCAL_GET_INTENT_LATENCY_HISTOGRAM;
+        final String kGetIntentSuccessHistogram = forAccount ? ACCOUNT_GET_INTENT_SUCCESS_HISTOGRAM
+                                                             : LOCAL_GET_INTENT_SUCCESS_HISTOGRAM;
+
+        RecordHistogram.recordTimesHistogram(kGetIntentLatencyHistogram, elapsedTimeMs);
+        RecordHistogram.recordBooleanHistogram(kGetIntentSuccessHistogram, true);
     }
 }
diff --git a/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelperTest.java b/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelperTest.java
index a0e65cd..ce50a52 100644
--- a/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelperTest.java
+++ b/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelperTest.java
@@ -5,10 +5,15 @@
 package org.chromium.chrome.browser.password_manager;
 
 import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -16,12 +21,16 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowSystemClock;
 
 import org.chromium.base.Callback;
 import org.chromium.base.CollectionUtil;
 import org.chromium.base.ContextUtils;
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.metrics.test.ShadowRecordHistogram;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Batch;
+import org.chromium.chrome.browser.password_manager.CredentialManagerLauncher.CredentialManagerError;
 import org.chromium.chrome.browser.sync.SyncService;
 import org.chromium.components.browser_ui.settings.SettingsLauncher;
 import org.chromium.components.signin.base.CoreAccountInfo;
@@ -31,10 +40,27 @@
 
 /** Tests for password manager helper methods. */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
+@Config(manifest = Config.NONE, shadows = {ShadowSystemClock.class, ShadowRecordHistogram.class})
 @Batch(Batch.PER_CLASS)
 public class PasswordManagerHelperTest {
     private static final String TEST_EMAIL_ADDRESS = "test@email.com";
+    private static final String ACCOUNT_GET_INTENT_LATENCY_HISTOGRAM =
+            "PasswordManager.CredentialManager.Account.GetIntent.Latency";
+    private static final String ACCOUNT_GET_INTENT_SUCCESS_HISTOGRAM =
+            "PasswordManager.CredentialManager.Account.GetIntent.Success";
+    private static final String ACCOUNT_GET_INTENT_ERROR_HISTOGRAM =
+            "PasswordManager.CredentialManager.Account.GetIntent.Error";
+    private static final String ACCOUNT_LAUNCH_CREDENTIAL_MANAGER_SUCCESS_HISTOGRAM =
+            "PasswordManager.CredentialManager.Account.Launch.Success";
+
+    private static final String LOCAL_GET_INTENT_LATENCY_HISTOGRAM =
+            "PasswordManager.CredentialManager.LocalProfile.GetIntent.Latency";
+    private static final String LOCAL_GET_INTENT_SUCCESS_HISTOGRAM =
+            "PasswordManager.CredentialManager.LocalProfile.GetIntent.Success";
+    private static final String LOCAL_GET_INTENT_ERROR_HISTOGRAM =
+            "PasswordManager.CredentialManager.LocalProfile.GetIntent.Error";
+    private static final String LOCAL_LAUNCH_CREDENTIAL_MANAGER_SUCCESS_HISTOGRAM =
+            "PasswordManager.CredentialManager.LocalProfile.Launch.Success";
 
     @Mock
     private CredentialManagerLauncher mCredentialManagerLauncherMock;
@@ -45,8 +71,12 @@
     @Mock
     private SettingsLauncher mSettingsLauncherMock;
 
+    @Mock
+    private PendingIntent mPendingIntentMock;
+
     @Before
     public void setUp() {
+        ShadowRecordHistogram.reset();
         MockitoAnnotations.initMocks(this);
     }
 
@@ -115,20 +145,15 @@
 
     @Test
     public void testLaunchesCredentialManagerSync() {
-        when(mSyncServiceMock.isSyncFeatureEnabled()).thenReturn(true);
-        when(mSyncServiceMock.getChosenDataTypes())
-                .thenReturn(CollectionUtil.newHashSet(ModelType.PASSWORDS));
-        when(mSyncServiceMock.getAccountInfo())
-                .thenReturn(CoreAccountInfo.createFromEmailAndGaiaId(TEST_EMAIL_ADDRESS, "0"));
+        chooseToSyncPasswordsWithoutCustomPassphrase();
 
         PasswordManagerHelper.showPasswordSettings(ContextUtils.getApplicationContext(),
                 ManagePasswordsReferrer.CHROME_SETTINGS, mSettingsLauncherMock,
                 mCredentialManagerLauncherMock, mSyncServiceMock);
 
         verify(mCredentialManagerLauncherMock)
-                .getCredentialManagerLaunchIntentForAccount(
-                        eq(ManagePasswordsReferrer.CHROME_SETTINGS), eq(TEST_EMAIL_ADDRESS),
-                        any(Callback.class), any(Callback.class));
+                .getCredentialManagerIntentForAccount(eq(ManagePasswordsReferrer.CHROME_SETTINGS),
+                        eq(TEST_EMAIL_ADDRESS), any(Callback.class), any(Callback.class));
     }
 
     @Test
@@ -139,8 +164,195 @@
                 mCredentialManagerLauncherMock, mSyncServiceMock);
 
         verify(mCredentialManagerLauncherMock)
-                .getCredentialManagerLaunchIntentForLocal(
-                        eq(ManagePasswordsReferrer.CHROME_SETTINGS), any(Callback.class),
-                        any(Callback.class));
+                .getCredentialManagerIntentForLocal(eq(ManagePasswordsReferrer.CHROME_SETTINGS),
+                        any(Callback.class), any(Callback.class));
     }
-}
\ No newline at end of file
+
+    @Test
+    public void testRecordsSuccessMetricsForAccountIntent() {
+        chooseToSyncPasswordsWithoutCustomPassphrase();
+        setUpSuccessfulIntentFetchingForAccount();
+
+        PasswordManagerHelper.showPasswordSettings(ContextUtils.getApplicationContext(),
+                ManagePasswordsReferrer.CHROME_SETTINGS, mSettingsLauncherMock,
+                mCredentialManagerLauncherMock, mSyncServiceMock);
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        ACCOUNT_GET_INTENT_LATENCY_HISTOGRAM, 0));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        ACCOUNT_GET_INTENT_SUCCESS_HISTOGRAM, 1));
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        ACCOUNT_GET_INTENT_ERROR_HISTOGRAM));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        ACCOUNT_LAUNCH_CREDENTIAL_MANAGER_SUCCESS_HISTOGRAM, 1));
+    }
+
+    @Test
+    public void testRecordsErrorMetricsForAccountIntent() {
+        chooseToSyncPasswordsWithoutCustomPassphrase();
+        returnErrorWhenFetchingIntentForAccount(CredentialManagerError.API_ERROR);
+
+        PasswordManagerHelper.showPasswordSettings(ContextUtils.getApplicationContext(),
+                ManagePasswordsReferrer.CHROME_SETTINGS, mSettingsLauncherMock,
+                mCredentialManagerLauncherMock, mSyncServiceMock);
+
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        ACCOUNT_GET_INTENT_ERROR_HISTOGRAM, CredentialManagerError.API_ERROR));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        ACCOUNT_GET_INTENT_SUCCESS_HISTOGRAM, 0));
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        ACCOUNT_GET_INTENT_LATENCY_HISTOGRAM));
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        ACCOUNT_LAUNCH_CREDENTIAL_MANAGER_SUCCESS_HISTOGRAM));
+    }
+
+    @Test
+    public void testRecordsMetricsWhenAccountIntentFails() throws CanceledException {
+        chooseToSyncPasswordsWithoutCustomPassphrase();
+        setUpSuccessfulIntentFetchingForAccount();
+        doThrow(CanceledException.class).when(mPendingIntentMock).send();
+
+        PasswordManagerHelper.showPasswordSettings(ContextUtils.getApplicationContext(),
+                ManagePasswordsReferrer.CHROME_SETTINGS, mSettingsLauncherMock,
+                mCredentialManagerLauncherMock, mSyncServiceMock);
+
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        ACCOUNT_GET_INTENT_LATENCY_HISTOGRAM, 0));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        ACCOUNT_GET_INTENT_SUCCESS_HISTOGRAM, 1));
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        ACCOUNT_GET_INTENT_ERROR_HISTOGRAM));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        ACCOUNT_LAUNCH_CREDENTIAL_MANAGER_SUCCESS_HISTOGRAM, 0));
+    }
+
+    @Test
+    public void testRecordsSuccessMetricsForLocalIntent() {
+        when(mSyncServiceMock.isSyncFeatureEnabled()).thenReturn(false);
+        setUpSuccessfulIntentFetchingForLocal();
+
+        PasswordManagerHelper.showPasswordSettings(ContextUtils.getApplicationContext(),
+                ManagePasswordsReferrer.CHROME_SETTINGS, mSettingsLauncherMock,
+                mCredentialManagerLauncherMock, mSyncServiceMock);
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        LOCAL_GET_INTENT_LATENCY_HISTOGRAM, 0));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        LOCAL_GET_INTENT_SUCCESS_HISTOGRAM, 1));
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramTotalCountForTesting(LOCAL_GET_INTENT_ERROR_HISTOGRAM));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        LOCAL_LAUNCH_CREDENTIAL_MANAGER_SUCCESS_HISTOGRAM, 1));
+    }
+
+    @Test
+    public void testRecordsErrorMetricsForLocalIntent() {
+        when(mSyncServiceMock.isSyncFeatureEnabled()).thenReturn(false);
+        returnErrorWhenFetchingIntentForLocal(CredentialManagerError.API_ERROR);
+
+        PasswordManagerHelper.showPasswordSettings(ContextUtils.getApplicationContext(),
+                ManagePasswordsReferrer.CHROME_SETTINGS, mSettingsLauncherMock,
+                mCredentialManagerLauncherMock, mSyncServiceMock);
+
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        LOCAL_GET_INTENT_ERROR_HISTOGRAM, CredentialManagerError.API_ERROR));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        LOCAL_GET_INTENT_SUCCESS_HISTOGRAM, 0));
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        LOCAL_GET_INTENT_LATENCY_HISTOGRAM));
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        LOCAL_LAUNCH_CREDENTIAL_MANAGER_SUCCESS_HISTOGRAM));
+    }
+
+    @Test
+    public void testRecordsMetricsWhenLocalIntentFails() throws CanceledException {
+        when(mSyncServiceMock.isSyncFeatureEnabled()).thenReturn(false);
+        setUpSuccessfulIntentFetchingForLocal();
+        doThrow(CanceledException.class).when(mPendingIntentMock).send();
+
+        PasswordManagerHelper.showPasswordSettings(ContextUtils.getApplicationContext(),
+                ManagePasswordsReferrer.CHROME_SETTINGS, mSettingsLauncherMock,
+                mCredentialManagerLauncherMock, mSyncServiceMock);
+
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        LOCAL_GET_INTENT_LATENCY_HISTOGRAM, 0));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        LOCAL_GET_INTENT_SUCCESS_HISTOGRAM, 1));
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramTotalCountForTesting(LOCAL_GET_INTENT_ERROR_HISTOGRAM));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        LOCAL_LAUNCH_CREDENTIAL_MANAGER_SUCCESS_HISTOGRAM, 0));
+    }
+
+    private void chooseToSyncPasswordsWithoutCustomPassphrase() {
+        when(mSyncServiceMock.isSyncFeatureEnabled()).thenReturn(true);
+        when(mSyncServiceMock.getChosenDataTypes())
+                .thenReturn(CollectionUtil.newHashSet(ModelType.PASSWORDS));
+        when(mSyncServiceMock.getAccountInfo())
+                .thenReturn(CoreAccountInfo.createFromEmailAndGaiaId(TEST_EMAIL_ADDRESS, "0"));
+    }
+
+    private void setUpSuccessfulIntentFetchingForAccount() {
+        doAnswer(invocation -> {
+            Callback<PendingIntent> cb = invocation.getArgument(2);
+            cb.onResult(mPendingIntentMock);
+            return true;
+        })
+                .when(mCredentialManagerLauncherMock)
+                .getCredentialManagerIntentForAccount(eq(ManagePasswordsReferrer.CHROME_SETTINGS),
+                        eq(TEST_EMAIL_ADDRESS), any(Callback.class), any(Callback.class));
+    }
+
+    private void setUpSuccessfulIntentFetchingForLocal() {
+        doAnswer(invocation -> {
+            Callback<PendingIntent> cb = invocation.getArgument(1);
+            cb.onResult(mPendingIntentMock);
+            return true;
+        })
+                .when(mCredentialManagerLauncherMock)
+                .getCredentialManagerIntentForLocal(eq(ManagePasswordsReferrer.CHROME_SETTINGS),
+                        any(Callback.class), any(Callback.class));
+    }
+
+    private void returnErrorWhenFetchingIntentForAccount(@CredentialManagerError int error) {
+        doAnswer(invocation -> {
+            Callback<Integer> cb = invocation.getArgument(3);
+            cb.onResult(error);
+            return true;
+        })
+                .when(mCredentialManagerLauncherMock)
+                .getCredentialManagerIntentForAccount(eq(ManagePasswordsReferrer.CHROME_SETTINGS),
+                        eq(TEST_EMAIL_ADDRESS), any(Callback.class), any(Callback.class));
+    }
+
+    private void returnErrorWhenFetchingIntentForLocal(@CredentialManagerError int error) {
+        doAnswer(invocation -> {
+            Callback<Integer> cb = invocation.getArgument(2);
+            cb.onResult(error);
+            return true;
+        })
+                .when(mCredentialManagerLauncherMock)
+                .getCredentialManagerIntentForLocal(eq(ManagePasswordsReferrer.CHROME_SETTINGS),
+                        any(Callback.class), any(Callback.class));
+    }
+}
diff --git a/chrome/browser/password_manager/android/password_store_android_backend.cc b/chrome/browser/password_manager/android/password_store_android_backend.cc
index aaaac8a..4c20254 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend.cc
+++ b/chrome/browser/password_manager/android/password_store_android_backend.cc
@@ -24,6 +24,7 @@
 #include "components/sync/model/model_type_controller_delegate.h"
 #include "components/sync/model/proxy_model_type_controller_delegate.h"
 #include "components/sync/model/type_entities_count.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace password_manager {
 
@@ -74,14 +75,34 @@
 PasswordStoreAndroidBackend::JobReturnHandler::~JobReturnHandler() = default;
 
 void PasswordStoreAndroidBackend::JobReturnHandler::RecordMetrics(
-    WasSuccess success) const {
+    absl::optional<AndroidBackendError> error) const {
   auto BuildMetricName = [this](base::StringPiece suffix) {
     return base::StrCat({"PasswordManager.PasswordStoreAndroidBackend.",
                          *metric_infix_, ".", suffix});
   };
   base::TimeDelta duration = base::Time::Now() - start_;
   base::UmaHistogramMediumTimes(BuildMetricName("Latency"), duration);
-  base::UmaHistogramBoolean(BuildMetricName("Success"), *success);
+  base::UmaHistogramBoolean(BuildMetricName("Success"), !error.has_value());
+  if (!error.has_value())
+    return;
+
+  // In case of error, we report additional metrics.
+  base::UmaHistogramEnumeration(
+      "PasswordManager.PasswordStoreAndroidBackend.ErrorCode",
+      error.value().type);
+  base::UmaHistogramEnumeration(BuildMetricName("ErrorCode"),
+                                error.value().type);
+  if (error.value().type == AndroidBackendErrorType::kExternalError) {
+    DCHECK(error.value().api_error_code.has_value());
+    base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
+        "PasswordManager.PasswordStoreAndroidBackend.APIError",
+        base::HistogramBase::kUmaTargetedHistogramFlag);
+    histogram->Add(error.value().api_error_code.value());
+    histogram = base::SparseHistogram::FactoryGet(
+        BuildMetricName("APIError"),
+        base::HistogramBase::kUmaTargetedHistogramFlag);
+    histogram->Add(error.value().api_error_code.value());
+  }
 }
 
 PasswordStoreAndroidBackend::SyncModelTypeControllerDelegate::
@@ -361,7 +382,7 @@
     std::vector<PasswordForm> passwords) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
   JobReturnHandler reply = GetAndEraseJob(job_id);
-  reply.RecordMetrics(JobReturnHandler::WasSuccess(true));
+  reply.RecordMetrics(/*error=*/absl::nullopt);
   DCHECK(reply.Holds<LoginsOrErrorReply>());
   main_task_runner_->PostTask(
       FROM_HERE,
@@ -374,7 +395,7 @@
     const PasswordStoreChangeList& changes) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
   JobReturnHandler reply = GetAndEraseJob(job_id);
-  reply.RecordMetrics(JobReturnHandler::WasSuccess(true));
+  reply.RecordMetrics(/*error=*/absl::nullopt);
   DCHECK(reply.Holds<PasswordStoreChangeListReply>());
 
   main_task_runner_->PostTask(
@@ -387,7 +408,7 @@
                                           AndroidBackendError error) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
   JobReturnHandler reply = GetAndEraseJob(job_id);
-  reply.RecordMetrics(JobReturnHandler::WasSuccess(false));
+  reply.RecordMetrics(std::move(error));
   if (reply.Holds<LoginsOrErrorReply>()) {
     main_task_runner_->PostTask(
         FROM_HERE, base::BindOnce(std::move(reply).Get<LoginsOrErrorReply>(),
@@ -399,16 +420,6 @@
         base::BindOnce(std::move(reply).Get<PasswordStoreChangeListReply>(),
                        PasswordStoreChangeList()));
   }
-
-  base::UmaHistogramEnumeration(
-      "PasswordManager.PasswordStoreAndroidBackend.ErrorCode", error.type);
-  if (error.type == AndroidBackendErrorType::kExternalError) {
-    DCHECK(error.api_error_code.has_value());
-    base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
-        "PasswordManager.PasswordStoreAndroidBackend.APIError",
-        base::HistogramBase::kUmaTargetedHistogramFlag);
-    histogram->Add(error.api_error_code.value());
-  }
 }
 
 base::WeakPtr<syncer::ModelTypeControllerDelegate>
diff --git a/chrome/browser/password_manager/android/password_store_android_backend.h b/chrome/browser/password_manager/android/password_store_android_backend.h
index 0037778..2dc9a46 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend.h
+++ b/chrome/browser/password_manager/android/password_store_android_backend.h
@@ -87,7 +87,6 @@
    public:
     using ErrorReply = base::OnceClosure;
     using MetricInfix = base::StrongAlias<struct MetricNameTag, std::string>;
-    using WasSuccess = base::StrongAlias<struct WasSuccessTag, bool>;
 
     JobReturnHandler();
     JobReturnHandler(LoginsOrErrorReply callback, MetricInfix metric_name);
@@ -110,7 +109,12 @@
     // Records metrics for this job:
     // - "PasswordManager.PasswordStoreAndroidBackend.<metric_infix_>.Latency"
     // - "PasswordManager.PasswordStoreAndroidBackend.<metric_infix_>.Success"
-    void RecordMetrics(WasSuccess success) const;
+    // In case of failure. the following are recorded in addition:
+    // - "PasswordManager.PasswordStoreAndroidBackend.APIError"
+    // - "PasswordManager.PasswordStoreAndroidBackend.ErrorCode"
+    // - "PasswordManager.PasswordStoreAndroidBackend.<metric_infix_>.APIError"
+    // - "PasswordManager.PasswordStoreAndroidBackend.<metric_infix_>.ErrorCode"
+    void RecordMetrics(absl::optional<AndroidBackendError> error) const;
 
    private:
     absl::variant<LoginsOrErrorReply, PasswordStoreChangeListReply>
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc b/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc
index e5f140b..d5307642 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc
+++ b/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc
@@ -323,6 +323,8 @@
       "PasswordManager.PasswordStoreAndroidBackend.GetAllLoginsAsync.Success";
   const char kErrorCodeMetric[] =
       "PasswordManager.PasswordStoreAndroidBackend.ErrorCode";
+  const char kPerApiErrorCodeMetric[] =
+      "PasswordManager.PasswordStoreAndroidBackend.GetAllLoginsAsync.ErrorCode";
   base::HistogramTester histogram_tester;
   base::MockCallback<LoginsOrErrorReply> mock_reply;
   EXPECT_CALL(*bridge(), GetAllLogins).WillOnce(Return(kJobId));
@@ -342,6 +344,7 @@
   histogram_tester.ExpectBucketCount(kSuccessMetric, false, !ShouldSucceed());
   if (!ShouldSucceed()) {
     histogram_tester.ExpectBucketCount(kErrorCodeMetric, 0, 1);
+    histogram_tester.ExpectBucketCount(kPerApiErrorCodeMetric, 0, 1);
   }
 }
 
@@ -359,6 +362,8 @@
       "PasswordManager.PasswordStoreAndroidBackend.AddLoginAsync.Success";
   const char kErrorCodeMetric[] =
       "PasswordManager.PasswordStoreAndroidBackend.ErrorCode";
+  const char kPerApiErrorCodeMetric[] =
+      "PasswordManager.PasswordStoreAndroidBackend.AddLoginAsync.ErrorCode";
   base::HistogramTester histogram_tester;
 
   base::MockCallback<PasswordStoreChangeListReply> mock_reply;
@@ -384,6 +389,7 @@
   histogram_tester.ExpectBucketCount(kSuccessMetric, false, !ShouldSucceed());
   if (!ShouldSucceed()) {
     histogram_tester.ExpectBucketCount(kErrorCodeMetric, 0, 1);
+    histogram_tester.ExpectBucketCount(kPerApiErrorCodeMetric, 0, 1);
   }
 }
 
@@ -401,6 +407,8 @@
       "PasswordManager.PasswordStoreAndroidBackend.UpdateLoginAsync.Success";
   const char kErrorCodeMetric[] =
       "PasswordManager.PasswordStoreAndroidBackend.ErrorCode";
+  const char kPerApiErrorCodeMetric[] =
+      "PasswordManager.PasswordStoreAndroidBackend.UpdateLoginAsync.ErrorCode";
   base::HistogramTester histogram_tester;
 
   base::MockCallback<PasswordStoreChangeListReply> mock_reply;
@@ -426,6 +434,7 @@
   histogram_tester.ExpectBucketCount(kSuccessMetric, false, !ShouldSucceed());
   if (!ShouldSucceed()) {
     histogram_tester.ExpectBucketCount(kErrorCodeMetric, 0, 1);
+    histogram_tester.ExpectBucketCount(kPerApiErrorCodeMetric, 0, 1);
   }
 }
 
@@ -443,6 +452,8 @@
       "PasswordManager.PasswordStoreAndroidBackend.RemoveLoginAsync.Success";
   const char kErrorCodeMetric[] =
       "PasswordManager.PasswordStoreAndroidBackend.ErrorCode";
+  const char kPerApiErrorCodeMetric[] =
+      "PasswordManager.PasswordStoreAndroidBackend.RemoveLoginAsync.ErrorCode";
   base::HistogramTester histogram_tester;
 
   base::MockCallback<PasswordStoreChangeListReply> mock_reply;
@@ -468,6 +479,7 @@
   histogram_tester.ExpectBucketCount(kSuccessMetric, false, !ShouldSucceed());
   if (!ShouldSucceed()) {
     histogram_tester.ExpectBucketCount(kErrorCodeMetric, 0, 1);
+    histogram_tester.ExpectBucketCount(kPerApiErrorCodeMetric, 0, 1);
   }
 }
 
diff --git a/chrome/browser/password_manager/multi_profile_credentials_filter_unittest.cc b/chrome/browser/password_manager/multi_profile_credentials_filter_unittest.cc
index 18c6c5ec..9e75bab 100644
--- a/chrome/browser/password_manager/multi_profile_credentials_filter_unittest.cc
+++ b/chrome/browser/password_manager/multi_profile_credentials_filter_unittest.cc
@@ -9,10 +9,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
-#include "base/feature_list.h"
 #include "base/memory/raw_ptr.h"
-#include "build/buildflag.h"
-#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
@@ -20,7 +17,6 @@
 #include "chrome/browser/signin/chrome_signin_client_test_util.h"
 #include "chrome/browser/signin/dice_web_signin_interceptor.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
@@ -117,12 +113,6 @@
     dice_web_signin_interceptor_ = std::make_unique<DiceWebSigninInterceptor>(
         profile(), std::make_unique<TestDiceWebSigninInterceptorDelegate>());
 
-// TODO(crbug.com/1198523): Remove this once Lacros no longer supports DICE.
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-    if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-      GTEST_SKIP();
-#endif
-
     test_password_manager_client_.set_identity_manager(
         identity_test_env()->identity_manager());
 
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 8373de12..05080883 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -155,6 +155,7 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/ash/account_manager/account_apps_availability_factory.h"
 #include "chrome/browser/ash/browser_context_keyed_service_factories.h"
 #include "chrome/browser/ash/login/security_token_session_controller_factory.h"
 #include "chrome/browser/ash/system_extensions/system_extensions_provider.h"
@@ -270,6 +271,7 @@
   AdaptiveQuietNotificationPermissionUiEnabler::Factory::GetInstance();
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   app_list::AppListSyncableServiceFactory::GetInstance();
+  ash::AccountAppsAvailabilityFactory::GetInstance();
 #endif
 #if !defined(OS_ANDROID)
   apps::AppServiceProxyFactory::GetInstance();
@@ -478,7 +480,9 @@
   SigninProfileAttributesUpdaterFactory::GetInstance();
   if (site_engagement::SiteEngagementService::IsEnabled())
     site_engagement::SiteEngagementServiceFactory::GetInstance();
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+// TODO(https://crbug.com/1198523: Remove Lacros check once Dice is no longer
+// supported on Lacros.
+#if BUILDFLAG(ENABLE_DICE_SUPPORT) && !BUILDFLAG(IS_CHROMEOS_LACROS)
   SigninManagerFactory::GetInstance();
 #endif
 #if BUILDFLAG(ENABLE_SPELLCHECK)
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index d3dd496..1199176 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -70,7 +70,6 @@
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/signin/account_reconcilor_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/signin/signin_util.h"
 #include "chrome/browser/sync/sync_service_factory.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
@@ -1017,8 +1016,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
 AccountProfileMapper* ProfileManager::GetAccountProfileMapper() {
-  if (!account_profile_mapper_ &&
-      base::FeatureList::IsEnabled(kMultiProfileAccountConsistency)) {
+  if (!account_profile_mapper_) {
     account_profile_mapper_ = std::make_unique<AccountProfileMapper>(
         GetAccountManagerFacade(/*profile_path=*/std::string()),
         &GetProfileAttributesStorage(), g_browser_process->local_state());
diff --git a/chrome/browser/resource_coordinator/tab_load_tracker.cc b/chrome/browser/resource_coordinator/tab_load_tracker.cc
index 24859f5..2633d27 100644
--- a/chrome/browser/resource_coordinator/tab_load_tracker.cc
+++ b/chrome/browser/resource_coordinator/tab_load_tracker.cc
@@ -230,11 +230,12 @@
     loading_state = LOADING;
   } else {
     // Determine if the WebContents is already loaded. A loaded WebContents has
-    // a committed navigation entry, is not in an initial navigation, and
-    // doesn't require a reload. This can occur during prerendering, when an
-    // already rendered WebContents is swapped in at the moment of a navigation.
+    // a committed navigation entry that is not the initial entry, is not in an
+    // initial navigation, and doesn't require a reload. This can occur during
+    // prerendering, when an already rendered WebContents is swapped in at the
+    // moment of a navigation.
     content::NavigationController& controller = web_contents->GetController();
-    if (controller.GetLastCommittedEntry() != nullptr &&
+    if (!controller.GetLastCommittedEntry()->IsInitialEntry() &&
         !controller.IsInitialNavigation() && !controller.NeedsReload()) {
       loading_state = LOADED;
     }
diff --git a/chrome/browser/resources/read_later/BUILD.gn b/chrome/browser/resources/read_later/BUILD.gn
index 823dd97..fb42859d5 100644
--- a/chrome/browser/resources/read_later/BUILD.gn
+++ b/chrome/browser/resources/read_later/BUILD.gn
@@ -45,7 +45,7 @@
 preprocess_if_expr("preprocess") {
   in_folder = "./"
   out_folder = "$target_gen_dir/$preprocess_folder"
-  in_files = [ "read_later_api_proxy.js" ]
+  in_files = [ "read_later_api_proxy.ts" ]
 }
 
 preprocess_if_expr("preprocess_mojo") {
@@ -78,10 +78,11 @@
   tsconfig_base = "tsconfig_base.json"
   root_dir = "$target_gen_dir/$preprocess_folder"
   out_dir = "$target_gen_dir/tsc"
+  composite = true
   in_files = [
     "app.ts",
     "icons.ts",
-    "read_later_api_proxy.js",
+    "read_later_api_proxy.ts",
     "read_later_item.ts",
     "read_later.mojom-webui.js",
 
diff --git a/chrome/browser/resources/read_later/app.ts b/chrome/browser/resources/read_later/app.ts
index 0269191..f0ca10a 100644
--- a/chrome/browser/resources/read_later/app.ts
+++ b/chrome/browser/resources/read_later/app.ts
@@ -228,4 +228,10 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'read-later-app': ReadLaterAppElement;
+  }
+}
+
 customElements.define(ReadLaterAppElement.is, ReadLaterAppElement);
diff --git a/chrome/browser/resources/read_later/read_later_api_proxy.js b/chrome/browser/resources/read_later/read_later_api_proxy.js
deleted file mode 100644
index 9b34dbc..0000000
--- a/chrome/browser/resources/read_later/read_later_api_proxy.js
+++ /dev/null
@@ -1,129 +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.
-
-import {ClickModifiers} from 'chrome://resources/mojo/ui/base/mojom/window_open_disposition.mojom-webui.js';
-import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
-import {PageCallbackRouter, PageHandlerFactory, PageHandlerRemote, ReadLaterEntriesByStatus} from './read_later.mojom-webui.js';
-
-/** @type {?ReadLaterApiProxy} */
-let instance = null;
-
-/** @interface */
-export class ReadLaterApiProxy {
-  /**
-   * @return {!Promise<!{entries: !ReadLaterEntriesByStatus}>}
-   */
-  getReadLaterEntries() {}
-
-  /**
-   * @param {!Url} url
-   * @param {boolean} mark_as_read
-   * @param {!ClickModifiers} click_modifiers
-   */
-  openURL(url, mark_as_read, click_modifiers) {}
-
-  /**
-   * @param {!Url} url
-   * @param {boolean} read
-   */
-  updateReadStatus(url, read) {}
-
-  addCurrentTab() {}
-
-  /** @param {!Url} url */
-  removeEntry(url) {}
-
-  /**
-   * @param {!Url} url
-   * @param {number} locationX
-   * @param {number} locationY
-   */
-  showContextMenuForURL(url, locationX, locationY) {}
-
-  updateCurrentPageActionButtonState() {}
-
-  showUI() {}
-
-  closeUI() {}
-
-  /** @return {!PageCallbackRouter} */
-  getCallbackRouter() {}
-}
-
-/** @implements {ReadLaterApiProxy} */
-export class ReadLaterApiProxyImpl {
-  constructor() {
-    /** @type {!PageCallbackRouter} */
-    this.callbackRouter = new PageCallbackRouter();
-
-    /** @type {!PageHandlerRemote} */
-    this.handler = new PageHandlerRemote();
-
-    const factory = PageHandlerFactory.getRemote();
-    factory.createPageHandler(
-        this.callbackRouter.$.bindNewPipeAndPassRemote(),
-        this.handler.$.bindNewPipeAndPassReceiver());
-  }
-
-  /** @override */
-  getReadLaterEntries() {
-    return this.handler.getReadLaterEntries();
-  }
-
-  /** @override */
-  openURL(url, mark_as_read, click_info) {
-    this.handler.openURL(url, mark_as_read, click_info);
-  }
-
-  /** @override */
-  updateReadStatus(url, read) {
-    this.handler.updateReadStatus(url, read);
-  }
-
-  /** @override */
-  addCurrentTab() {
-    this.handler.addCurrentTab();
-  }
-
-  /** @override */
-  removeEntry(url) {
-    this.handler.removeEntry(url);
-  }
-
-  /** @override */
-  showContextMenuForURL(url, locationX, locationY) {
-    this.handler.showContextMenuForURL(url, locationX, locationY);
-  }
-
-  /** @override */
-  updateCurrentPageActionButtonState() {
-    this.handler.updateCurrentPageActionButtonState();
-  }
-
-  /** @override */
-  showUI() {
-    this.handler.showUI();
-  }
-
-  /** @override */
-  closeUI() {
-    this.handler.closeUI();
-  }
-
-  /** @override */
-  getCallbackRouter() {
-    return this.callbackRouter;
-  }
-
-  /** @return {!ReadLaterApiProxy} */
-  static getInstance() {
-    return instance || (instance = new ReadLaterApiProxyImpl());
-  }
-
-  /** @param {!ReadLaterApiProxy} obj */
-  static setInstance(obj) {
-    instance = obj;
-  }
-}
-
diff --git a/chrome/browser/resources/read_later/read_later_api_proxy.ts b/chrome/browser/resources/read_later/read_later_api_proxy.ts
new file mode 100644
index 0000000..e9eba57
--- /dev/null
+++ b/chrome/browser/resources/read_later/read_later_api_proxy.ts
@@ -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.
+
+import {ClickModifiers} from 'chrome://resources/mojo/ui/base/mojom/window_open_disposition.mojom-webui.js';
+import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
+import {PageCallbackRouter, PageHandlerFactory, PageHandlerRemote, ReadLaterEntriesByStatus} from './read_later.mojom-webui.js';
+
+let instance: ReadLaterApiProxy|null = null;
+
+export interface ReadLaterApiProxy {
+  getReadLaterEntries(): Promise<{entries: ReadLaterEntriesByStatus}>;
+
+  openURL(url: Url, markAsRead: boolean, clickModifiers: ClickModifiers): void;
+
+  updateReadStatus(url: Url, read: boolean): void;
+
+  addCurrentTab(): void;
+
+  removeEntry(url: Url): void;
+
+  showContextMenuForURL(url: Url, locationX: number, locationY: number): void;
+
+  updateCurrentPageActionButtonState(): void;
+
+  showUI(): void;
+
+  closeUI(): void;
+
+  getCallbackRouter(): PageCallbackRouter;
+}
+
+export class ReadLaterApiProxyImpl implements ReadLaterApiProxy {
+  private callbackRouter: PageCallbackRouter = new PageCallbackRouter();
+  private handler: PageHandlerRemote = new PageHandlerRemote();
+
+  constructor() {
+    this.callbackRouter = new PageCallbackRouter();
+
+    this.handler = new PageHandlerRemote();
+
+    const factory = PageHandlerFactory.getRemote();
+    factory.createPageHandler(
+        this.callbackRouter.$.bindNewPipeAndPassRemote(),
+        this.handler.$.bindNewPipeAndPassReceiver());
+  }
+
+  getReadLaterEntries() {
+    return this.handler.getReadLaterEntries();
+  }
+
+  openURL(url: Url, markAsRead: boolean, clickModifiers: ClickModifiers) {
+    this.handler.openURL(url, markAsRead, clickModifiers);
+  }
+
+  updateReadStatus(url: Url, read: boolean) {
+    this.handler.updateReadStatus(url, read);
+  }
+
+  addCurrentTab() {
+    this.handler.addCurrentTab();
+  }
+
+  removeEntry(url: Url) {
+    this.handler.removeEntry(url);
+  }
+
+  showContextMenuForURL(url: Url, locationX: number, locationY: number) {
+    this.handler.showContextMenuForURL(url, locationX, locationY);
+  }
+
+  updateCurrentPageActionButtonState() {
+    this.handler.updateCurrentPageActionButtonState();
+  }
+
+  showUI() {
+    this.handler.showUI();
+  }
+
+  closeUI() {
+    this.handler.closeUI();
+  }
+
+  getCallbackRouter() {
+    return this.callbackRouter;
+  }
+
+  static getInstance(): ReadLaterApiProxy {
+    return instance || (instance = new ReadLaterApiProxyImpl());
+  }
+
+  static setInstance(obj: ReadLaterApiProxy) {
+    instance = obj;
+  }
+}
diff --git a/chrome/browser/resources/read_later/read_later_item.ts b/chrome/browser/resources/read_later/read_later_item.ts
index 89e7596..4978f3c 100644
--- a/chrome/browser/resources/read_later/read_later_item.ts
+++ b/chrome/browser/resources/read_later/read_later_item.ts
@@ -157,4 +157,10 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'read-later-item': ReadLaterItemElement;
+  }
+}
+
 customElements.define(ReadLaterItemElement.is, ReadLaterItemElement);
diff --git a/chrome/browser/resources/read_later/side_panel/bookmark_folder.ts b/chrome/browser/resources/read_later/side_panel/bookmark_folder.ts
index d974df8..f18975f 100644
--- a/chrome/browser/resources/read_later/side_panel/bookmark_folder.ts
+++ b/chrome/browser/resources/read_later/side_panel/bookmark_folder.ts
@@ -11,7 +11,7 @@
 
 import {ReadLaterApiProxy, ReadLaterApiProxyImpl} from '../read_later_api_proxy.js';
 
-import {BookmarksApiProxy} from './bookmarks_api_proxy.js';
+import {BookmarksApiProxy, BookmarksApiProxyImpl} from './bookmarks_api_proxy.js';
 
 /** Event interface for dom-repeat. */
 interface RepeaterMouseEvent extends MouseEvent {
@@ -70,7 +70,8 @@
   folder: chrome.bookmarks.BookmarkTreeNode;
   private open_: boolean;
   openFolders: string[];
-  private bookmarksApi_: BookmarksApiProxy = BookmarksApiProxy.getInstance();
+  private bookmarksApi_: BookmarksApiProxy =
+      BookmarksApiProxyImpl.getInstance();
 
   static get observers() {
     return [
@@ -261,4 +262,4 @@
 
 export function isBookmarkFolderElement(element: HTMLElement): boolean {
   return element.id === 'folder';
-}
\ No newline at end of file
+}
diff --git a/chrome/browser/resources/read_later/side_panel/bookmarks_api_proxy.ts b/chrome/browser/resources/read_later/side_panel/bookmarks_api_proxy.ts
index 0c7b5fb..4b3704e 100644
--- a/chrome/browser/resources/read_later/side_panel/bookmarks_api_proxy.ts
+++ b/chrome/browser/resources/read_later/side_panel/bookmarks_api_proxy.ts
@@ -12,7 +12,18 @@
 
 let instance: BookmarksApiProxy|null = null;
 
-export class BookmarksApiProxy {
+export interface BookmarksApiProxy {
+  callbackRouter: {[key: string]: ChromeEvent<Function>};
+  cutBookmark(id: string): void;
+  copyBookmark(id: string): Promise<void>;
+  getFolders(): Promise<chrome.bookmarks.BookmarkTreeNode[]>;
+  openBookmark(url: string, depth: number, clickModifiers: ClickModifiers):
+      void;
+  pasteToBookmark(parentId: string, destinationId?: string): Promise<void>;
+  showContextMenu(id: string, x: number, y: number): void;
+}
+
+export class BookmarksApiProxyImpl implements BookmarksApiProxy {
   callbackRouter: {[key: string]: ChromeEvent<Function>};
   handler: BookmarksPageHandlerRemote;
 
@@ -32,34 +43,34 @@
         this.handler.$.bindNewPipeAndPassReceiver());
   }
 
-  cutBookmark(id: string): Promise<void> {
+  cutBookmark(id: string) {
     chrome.bookmarkManagerPrivate.cut([id]);
-    return Promise.resolve();
   }
 
-  copyBookmark(id: string): Promise<void> {
-    return new Promise(resolve => {
+  copyBookmark(id: string) {
+    return new Promise<void>(resolve => {
       chrome.bookmarkManagerPrivate.copy([id], resolve);
     });
   }
 
-  getFolders(): Promise<chrome.bookmarks.BookmarkTreeNode[]> {
-    return new Promise(resolve => chrome.bookmarks.getTree(results => {
-      if (results[0] && results[0].children) {
-        resolve(results[0].children);
-        return;
-      }
-      resolve([]);
-    }));
+  getFolders() {
+    return new Promise<chrome.bookmarks.BookmarkTreeNode[]>(
+        resolve => chrome.bookmarks.getTree(results => {
+          if (results[0] && results[0].children) {
+            resolve(results[0].children);
+            return;
+          }
+          resolve([]);
+        }));
   }
 
   openBookmark(url: string, depth: number, clickModifiers: ClickModifiers) {
     this.handler.openBookmark({url}, depth, clickModifiers);
   }
 
-  pasteToBookmark(parentId: string, destinationId?: string): Promise<void> {
+  pasteToBookmark(parentId: string, destinationId?: string) {
     const destination = destinationId ? [destinationId] : [];
-    return new Promise(resolve => {
+    return new Promise<void>(resolve => {
       chrome.bookmarkManagerPrivate.paste(parentId, destination, resolve);
     });
   }
@@ -68,11 +79,11 @@
     this.handler.showContextMenu(id, {x, y});
   }
 
-  static getInstance() {
-    return instance || (instance = new BookmarksApiProxy());
+  static getInstance(): BookmarksApiProxy {
+    return instance || (instance = new BookmarksApiProxyImpl());
   }
 
   static setInstance(obj: BookmarksApiProxy) {
     instance = obj;
   }
-}
\ No newline at end of file
+}
diff --git a/chrome/browser/resources/read_later/side_panel/bookmarks_list.ts b/chrome/browser/resources/read_later/side_panel/bookmarks_list.ts
index b6bf4121..5d347ac 100644
--- a/chrome/browser/resources/read_later/side_panel/bookmarks_list.ts
+++ b/chrome/browser/resources/read_later/side_panel/bookmarks_list.ts
@@ -5,7 +5,7 @@
 import {afterNextRender, html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {BookmarkFolderElement, FOLDER_OPEN_CHANGED_EVENT, getBookmarkFromElement, isBookmarkFolderElement} from './bookmark_folder.js';
-import {BookmarksApiProxy} from './bookmarks_api_proxy.js';
+import {BookmarksApiProxy, BookmarksApiProxyImpl} from './bookmarks_api_proxy.js';
 import {BookmarksDragManager} from './bookmarks_drag_manager.js';
 
 // Key for localStorage object that refers to all the open folders.
@@ -34,7 +34,8 @@
     };
   }
 
-  private bookmarksApi_: BookmarksApiProxy = BookmarksApiProxy.getInstance();
+  private bookmarksApi_: BookmarksApiProxy =
+      BookmarksApiProxyImpl.getInstance();
   private bookmarksDragManager_: BookmarksDragManager =
       new BookmarksDragManager(this);
   private listeners_ = new Map<string, Function>();
diff --git a/chrome/browser/resources/settings/autofill_page/autofill_section.ts b/chrome/browser/resources/settings/autofill_page/autofill_section.ts
index 02858005..d2b8bdb7 100644
--- a/chrome/browser/resources/settings/autofill_page/autofill_section.ts
+++ b/chrome/browser/resources/settings/autofill_page/autofill_section.ts
@@ -20,11 +20,11 @@
 import './address_remove_confirmation_dialog.js';
 import './passwords_shared_css.js';
 
-import {I18nMixin, I18nMixinInterface} from '//resources/js/i18n_mixin.js';
+import {I18nMixin} from '//resources/js/i18n_mixin.js';
 import {CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
-import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../i18n_setup.js';
 
@@ -120,9 +120,7 @@
   };
 }
 
-const SettingsAutofillSectionElementBase =
-    mixinBehaviors([], I18nMixin(PolymerElement)) as
-    {new (): PolymerElement & I18nMixinInterface};
+const SettingsAutofillSectionElementBase = I18nMixin(PolymerElement);
 
 class SettingsAutofillSectionElement extends
     SettingsAutofillSectionElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index d8df5ecc..8de5a9d3 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -283,6 +283,7 @@
     "chromeos/os_about_page/device_name_util.js",
     "chromeos/os_reset_page/os_reset_browser_proxy.js",
     "chromeos/os_settings.js",
+    "chromeos/parental_controls_page/parental_controls_browser_proxy.js",
     "chromeos/personalization_page/change_picture_browser_proxy.js",
     "chromeos/personalization_page/wallpaper_browser_proxy.js",
     "chromeos/prefs_behavior.js",
@@ -568,11 +569,10 @@
     "chromeos/os_settings_search_box/os_search_result_row.js",
     "chromeos/os_settings_search_box/os_settings_search_box.js",
     "chromeos/os_toolbar/os_toolbar.js",
-    "chromeos/parental_controls_page/parental_controls_browser_proxy.m.js",
-    "chromeos/parental_controls_page/parental_controls_page.m.js",
-    "chromeos/personalization_page/change_picture.m.js",
-    "chromeos/personalization_page/dark_mode_subpage.m.js",
-    "chromeos/personalization_page/personalization_page.m.js",
+    "chromeos/parental_controls_page/parental_controls_page.js",
+    "chromeos/personalization_page/change_picture.js",
+    "chromeos/personalization_page/dark_mode_subpage.js",
+    "chromeos/personalization_page/personalization_page.js",
     "chromeos/pref_to_setting_metric_converter.m.js",
     "chromeos/route_origin_behavior.m.js",
     "chromeos/search_handler.m.js",
@@ -793,8 +793,8 @@
     "os_settings_search_box:web_components",
     "os_settings_ui:web_components",
     "os_toolbar:web_components",
-    "parental_controls_page:polymer3_elements",
-    "personalization_page:polymer3_elements",
+    "parental_controls_page:web_components",
+    "personalization_page:web_components",
     "settings_scheduler_slider:web_components",
 
     # Local targets
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn
index a76c19e..ff74d017 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn
@@ -143,7 +143,7 @@
     "..:os_route.m",
     "..:route_observer_behavior",
     "../..:router",
-    "../parental_controls_page:parental_controls_page.m",
+    "../parental_controls_page:parental_controls_page",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/webui/resources/cr_components/chromeos/localized_link:localized_link",
     "//ui/webui/resources/cr_components/chromeos/quick_unlock:lock_screen_constants.m",
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni
index cebf194..ab87a25 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.gni
+++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -486,6 +486,11 @@
                                  "chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.html",
                                  "chrome/browser/resources/settings/chromeos/personalization_page/change_picture_browser_proxy.html",
                                  "chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_browser_proxy.html",
+                                 "chrome/browser/resources/settings/chromeos/personalization_page/change_picture.html",
+                                 "chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html",
+                                 "chrome/browser/resources/settings/chromeos/personalization_page/dark_mode_subpage.html",
+                                 "chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_browser_proxy.html",
+                                 "chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.html",
                                  "chrome/browser/resources/settings/chromeos/route_observer_behavior.html",
                                  "chrome/browser/resources/settings/chromeos/settings_scheduler_slider/settings_scheduler_slider.html",
                                  "chrome/browser/resources/settings/chromeos/keyboard_shortcut_banner/keyboard_shortcut_banner.html",
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.js b/chrome/browser/resources/settings/chromeos/os_settings.js
index 88a761c..5d7f180 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.js
+++ b/chrome/browser/resources/settings/chromeos/os_settings.js
@@ -37,9 +37,9 @@
 import './multidevice_page/multidevice_page.m.js';
 import './nearby_share_page/nearby_share_receive_dialog.m.js';
 import './nearby_share_page/nearby_share_subpage.m.js';
-import './personalization_page/change_picture.m.js';
-import './personalization_page/dark_mode_subpage.m.js';
-import './personalization_page/personalization_page.m.js';
+import './personalization_page/change_picture.js';
+import './personalization_page/dark_mode_subpage.js';
+import './personalization_page/personalization_page.js';
 import './os_a11y_page/change_dictation_locale_dialog.js';
 import './os_about_page/channel_switcher_dialog.js';
 import './os_about_page/detailed_build_info.js';
@@ -91,7 +91,7 @@
 import './os_settings_search_box/os_search_result_row.js';
 import './os_settings_search_box/os_settings_search_box.js';
 import './os_toolbar/os_toolbar.js';
-import './parental_controls_page/parental_controls_page.m.js';
+import './parental_controls_page/parental_controls_page.js';
 import './settings_scheduler_slider/settings_scheduler_slider.js';
 
 export {LifetimeBrowserProxyImpl} from '../lifetime_browser_proxy.js';
@@ -149,7 +149,7 @@
 export {OsResetBrowserProxyImpl} from './os_reset_page/os_reset_browser_proxy.js';
 export {routes} from './os_route.m.js';
 export {SearchEngine, SearchEnginesBrowserProxy, SearchEnginesBrowserProxyImpl, SearchEnginesInfo} from './os_search_page/search_engines_browser_proxy.js';
-export {ParentalControlsBrowserProxy, ParentalControlsBrowserProxyImpl} from './parental_controls_page/parental_controls_browser_proxy.m.js';
+export {ParentalControlsBrowserProxy, ParentalControlsBrowserProxyImpl} from './parental_controls_page/parental_controls_browser_proxy.js';
 export {ChangePictureBrowserProxy, ChangePictureBrowserProxyImpl} from './personalization_page/change_picture_browser_proxy.js';
 export {WallpaperBrowserProxyImpl} from './personalization_page/wallpaper_browser_proxy.js';
 export {getSearchHandler, setSearchHandlerForTesting} from './search_handler.m.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_settings_page/BUILD.gn
index 8f70422..17a96d04 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_page/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/os_settings_page/BUILD.gn
@@ -38,7 +38,7 @@
     "../os_printing_page:os_printing_page",
     "../os_privacy_page:os_privacy_page",
     "../os_search_page:os_search_page",
-    "../personalization_page:personalization_page.m",
+    "../personalization_page:personalization_page",
     "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
     "//ui/webui/resources/js:assert.m",
     "//ui/webui/resources/js:load_time_data.m",
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.js b/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.js
index 63d20e98..0f6017f6 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.js
+++ b/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.js
@@ -18,7 +18,7 @@
 import '../os_privacy_page/os_privacy_page.js';
 import '../os_printing_page/os_printing_page.js';
 import '../os_search_page/os_search_page.js';
-import '../personalization_page/personalization_page.m.js';
+import '../personalization_page/personalization_page.js';
 import '../../settings_page/settings_section.js';
 import '../../settings_page_css.js';
 import '../bluetooth_page/bluetooth_page.js';
diff --git a/chrome/browser/resources/settings/chromeos/parental_controls_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/parental_controls_page/BUILD.gn
index 8979a804..3a0b0454 100644
--- a/chrome/browser/resources/settings/chromeos/parental_controls_page/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/parental_controls_page/BUILD.gn
@@ -3,53 +3,32 @@
 # 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("//tools/polymer/html_to_js.gni")
 import("../os_settings.gni")
 
 js_type_check("closure_compile_module") {
   closure_flags = os_settings_closure_flags
   is_polymer3 = true
   deps = [
-    ":parental_controls_browser_proxy.m",
-    ":parental_controls_page.m",
+    ":parental_controls_browser_proxy",
+    ":parental_controls_page",
   ]
 }
 
-js_library("parental_controls_browser_proxy.m") {
-  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_browser_proxy.m.js" ]
-  extra_deps = [ ":modulize" ]
+js_library("parental_controls_browser_proxy") {
+  deps = [ "//ui/webui/resources/js:cr.m" ]
 }
 
-js_library("parental_controls_page.m") {
-  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.m.js" ]
+js_library("parental_controls_page") {
   deps = [
-    ":parental_controls_browser_proxy.m",
+    ":parental_controls_browser_proxy",
     "../..:router",
     "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
     "//ui/webui/resources/js:i18n_behavior.m",
     "//ui/webui/resources/js:web_ui_listener_behavior.m",
   ]
-  extra_deps = [ ":parental_controls_page_module" ]
 }
 
-group("polymer3_elements") {
-  public_deps = [
-    ":modulize",
-    ":parental_controls_page_module",
-  ]
-}
-
-polymer_modulizer("parental_controls_page") {
-  js_file = "parental_controls_page.js"
-  html_file = "parental_controls_page.html"
-  html_type = "dom-module"
-  migrated_imports = os_settings_migrated_imports
-  namespace_rewrites = os_settings_namespace_rewrites
-  auto_imports = os_settings_auto_imports
-}
-
-js_modulizer("modulize") {
-  input_files = [ "parental_controls_browser_proxy.js" ]
-  namespace_rewrites = os_settings_namespace_rewrites
+html_to_js("web_components") {
+  js_files = [ "parental_controls_page.js" ]
 }
diff --git a/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_browser_proxy.js b/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_browser_proxy.js
index af24c80..f70f55a 100644
--- a/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_browser_proxy.js
+++ b/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_browser_proxy.js
@@ -2,47 +2,39 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// #import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
+import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
 
 /**
  * @fileoverview
  * Browser Proxy for Parental Controls functions.
  */
 
-cr.define('parental_controls', function() {
   /** @interface */
-  /* #export */ class ParentalControlsBrowserProxy {
-    /**
-     * Shows the Add Supervsion dialog.
-     */
-    showAddSupervisionDialog() {}
+export class ParentalControlsBrowserProxy {
+  /**
+   * Shows the Add Supervsion dialog.
+   */
+  showAddSupervisionDialog() {}
 
-    /**
-     * Launches an app that shows the Family Link Settings.  Depending
-     * on whether the Family Link Helper app is available, this might
-     * launch the app, or take some kind of backup/default action.
-     */
-    launchFamilyLinkSettings() {}
+  /**
+   * Launches an app that shows the Family Link Settings.  Depending
+   * on whether the Family Link Helper app is available, this might
+   * launch the app, or take some kind of backup/default action.
+   */
+  launchFamilyLinkSettings() {}
+}
+
+/** @implements {ParentalControlsBrowserProxy} */
+export class ParentalControlsBrowserProxyImpl {
+  /** @override */
+  showAddSupervisionDialog() {
+    chrome.send('showAddSupervisionDialog');
   }
 
-  /** @implements {parental_controls.ParentalControlsBrowserProxy} */
-  /* #export */ class ParentalControlsBrowserProxyImpl {
-    /** @override */
-    showAddSupervisionDialog() {
-      chrome.send('showAddSupervisionDialog');
-    }
-
-    /** @override */
-    launchFamilyLinkSettings() {
-      chrome.send('launchFamilyLinkSettings');
-    }
+  /** @override */
+  launchFamilyLinkSettings() {
+    chrome.send('launchFamilyLinkSettings');
   }
+}
 
-  cr.addSingletonGetter(ParentalControlsBrowserProxyImpl);
-
-  // #cr_define_end
-  return {
-    ParentalControlsBrowserProxy: ParentalControlsBrowserProxy,
-    ParentalControlsBrowserProxyImpl: ParentalControlsBrowserProxyImpl,
-  };
-});
+addSingletonGetter(ParentalControlsBrowserProxyImpl);
diff --git a/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.html b/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.html
index 1d7454d..2cf06ac0a 100644
--- a/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.html
+++ b/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.html
@@ -1,55 +1,37 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
-<link rel="import" href="chrome://resources/cr_elements/icons.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="parental_controls_browser_proxy.html">
-<link rel="import" href="../../i18n_setup.html">
-<link rel="import" href="../os_route.html">
-<link rel="import" href="../../settings_page/settings_animated_pages.html">
-<link rel="import" href="../../settings_page/settings_subpage.html">
-<link rel="import" href="../../settings_shared_css.html">
-
-<dom-module id="settings-parental-controls-page">
-  <template>
-    <style include="settings-shared">
-      cr-link-row {
-        --cr-section-padding: 0;
-      }
-      /* The same width as in cr-link-row */
-      .start-icon {
-        width: var(--cr-link-row-icon-width, var(--cr-icon-size));
-      }
-    </style>
-    <div id="parental-controls-item" class="settings-box two-line">
-      <template is="dom-if" if="[[isChild_]]">
-        <cr-link-row on-click="handleFamilyLinkButtonClick_"
-            start-icon="cr20:kite"
-            label="$i18n{parentalControlsPageTitle}"
-            sub-label="$i18n{parentalControlsPageViewSettingsLabel}"
-            external>
-        </cr-link-row>
-      </template>
-      <template is="dom-if" if="[[!isChild_]]">
-        <iron-icon class="start-icon" icon="cr20:kite"></iron-icon>
-        <div class="middle settings-box-text">
-          <div id="label" aria-hidden="true">
-            $i18n{parentalControlsPageTitle}
-          </div>
-          <div class="secondary" id="sub-label" aria-hidden="true">
-            [[getSetupLabelText_(online_)]]
-          </div>
-        </div>
-        <div class="separator"></div>
-        <cr-button id="setupButton" on-click="handleSetupButtonClick_"
-            disabled$="[[!online_]]" aria-labelledby="label"
-            aria-describedby="sub-label"
-            aria-roledescription="$i18n{parentalControlsSetUpButtonRole}">
-          $i18n{parentalControlsSetUpButtonLabel}
-        </cr-button>
-      </template>
-    </div>
+<style include="settings-shared">
+  cr-link-row {
+    --cr-section-padding: 0;
+  }
+  /* The same width as in cr-link-row */
+  .start-icon {
+    width: var(--cr-link-row-icon-width, var(--cr-icon-size));
+  }
+</style>
+<div id="parental-controls-item" class="settings-box two-line">
+  <template is="dom-if" if="[[isChild_]]">
+    <cr-link-row on-click="handleFamilyLinkButtonClick_"
+        start-icon="cr20:kite"
+        label="$i18n{parentalControlsPageTitle}"
+        sub-label="$i18n{parentalControlsPageViewSettingsLabel}"
+        external>
+    </cr-link-row>
   </template>
-  <script src="parental_controls_page.js"></script>
-</dom-module>
+  <template is="dom-if" if="[[!isChild_]]">
+    <iron-icon class="start-icon" icon="cr20:kite"></iron-icon>
+    <div class="middle settings-box-text">
+      <div id="label" aria-hidden="true">
+        $i18n{parentalControlsPageTitle}
+      </div>
+      <div class="secondary" id="sub-label" aria-hidden="true">
+        [[getSetupLabelText_(online_)]]
+      </div>
+    </div>
+    <div class="separator"></div>
+    <cr-button id="setupButton" on-click="handleSetupButtonClick_"
+        disabled$="[[!online_]]" aria-labelledby="label"
+        aria-describedby="sub-label"
+        aria-roledescription="$i18n{parentalControlsSetUpButtonRole}">
+      $i18n{parentalControlsSetUpButtonLabel}
+    </cr-button>
+  </template>
+</div>
diff --git a/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.js b/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.js
index 809f2458..eb94f3a 100644
--- a/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.js
+++ b/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.js
@@ -7,7 +7,23 @@
  * Settings page for managing Parental Controls features.
  */
 
+import '//resources/cr_elements/cr_button/cr_button.m.js';
+import '//resources/cr_elements/icons.m.js';
+import '../../settings_page/settings_animated_pages.js';
+import '../../settings_page/settings_subpage.js';
+import '../../settings_shared_css.js';
+
+import {addWebUIListener, removeWebUIListener, sendWithPromise, WebUIListener} from '//resources/js/cr.m.js';
+import {I18nBehavior} from '//resources/js/i18n_behavior.m.js';
+import {afterNextRender, flush, html, Polymer, TemplateInstanceBase, Templatizer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {loadTimeData} from '../../i18n_setup.js';
+import {routes} from '../os_route.m.js';
+
+import {ParentalControlsBrowserProxy, ParentalControlsBrowserProxyImpl} from './parental_controls_browser_proxy.js';
+
 Polymer({
+  _template: html`{__html_template__}`,
   is: 'settings-parental-controls-page',
 
   behaviors: [
@@ -34,7 +50,7 @@
 
   /** @override */
   created() {
-    this.browserProxy_ = parental_controls.ParentalControlsBrowserProxyImpl.getInstance();
+    this.browserProxy_ = ParentalControlsBrowserProxyImpl.getInstance();
   },
 
   /** @override */
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn
index f19d9de7..3b7024da 100644
--- a/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn
@@ -3,23 +3,22 @@
 # found in the LICENSE file.
 
 import("//third_party/closure_compiler/compile_js.gni")
-import("//tools/polymer/polymer.gni")
+import("//tools/polymer/html_to_js.gni")
 import("../os_settings.gni")
 
 js_type_check("closure_compile_module") {
   closure_flags = os_settings_closure_flags
   is_polymer3 = true
   deps = [
-    ":change_picture.m",
+    ":change_picture",
     ":change_picture_browser_proxy",
-    ":dark_mode_subpage.m",
-    ":personalization_page.m",
+    ":dark_mode_subpage",
+    ":personalization_page",
     ":wallpaper_browser_proxy",
   ]
 }
 
-js_library("change_picture.m") {
-  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.m.js" ]
+js_library("change_picture") {
   deps = [
     ":change_picture_browser_proxy",
     "..:deep_linking_behavior.m",
@@ -40,16 +39,13 @@
     "//ui/webui/resources/js:util.m",
     "//ui/webui/resources/js:web_ui_listener_behavior.m",
   ]
-  extra_deps = [ ":change_picture_module" ]
 }
 
 js_library("change_picture_browser_proxy") {
   deps = [ "//ui/webui/resources/js:cr.m" ]
 }
 
-js_library("dark_mode_subpage.m") {
-  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/personalization_page/dark_mode_subpage.m.js" ]
-
+js_library("dark_mode_subpage") {
   deps = [
     "..:os_route.m",
     "..:prefs_behavior",
@@ -57,11 +53,9 @@
     "../..:router",
     "//ui/webui/resources/js:load_time_data",
   ]
-  extra_deps = [ ":dark_mode_subpage_module" ]
 }
 
-js_library("personalization_page.m") {
-  sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.m.js" ]
+js_library("personalization_page") {
   deps = [
     ":wallpaper_browser_proxy",
     "..:deep_linking_behavior.m",
@@ -72,7 +66,6 @@
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/webui/resources/js:load_time_data.m",
   ]
-  extra_deps = [ ":personalization_page_module" ]
 }
 
 js_library("wallpaper_browser_proxy") {
@@ -80,40 +73,10 @@
   externs_list = [ "$externs_path/chrome_send.js" ]
 }
 
-group("polymer3_elements") {
-  public_deps = [
-    ":change_picture_module",
-    ":dark_mode_subpage_module",
-    ":personalization_page_module",
+html_to_js("web_components") {
+  js_files = [
+    "change_picture.js",
+    "dark_mode_subpage.js",
+    "personalization_page.js",
   ]
 }
-
-polymer_modulizer("change_picture") {
-  js_file = "change_picture.js"
-  html_file = "change_picture.html"
-  html_type = "dom-module"
-  migrated_imports = os_settings_migrated_imports
-  namespace_rewrites = os_settings_namespace_rewrites
-  auto_imports = os_settings_auto_imports + [
-                   "ui/webui/resources/html/assert.html|assert,assertNotReached",
-                   "ui/webui/resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.html|IronA11yAnnouncer",
-                 ]
-}
-
-polymer_modulizer("dark_mode_subpage") {
-  js_file = "dark_mode_subpage.js"
-  html_file = "dark_mode_subpage.html"
-  html_type = "dom-module"
-  migrated_imports = os_settings_migrated_imports
-  namespace_rewrites = os_settings_namespace_rewrites
-  auto_imports = os_settings_auto_imports
-}
-
-polymer_modulizer("personalization_page") {
-  js_file = "personalization_page.js"
-  html_file = "personalization_page.html"
-  html_type = "dom-module"
-  migrated_imports = os_settings_migrated_imports
-  namespace_rewrites = os_settings_namespace_rewrites
-  auto_imports = os_settings_auto_imports
-}
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.html b/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.html
index 6fd763ed..3c2d96b 100644
--- a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.html
+++ b/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.html
@@ -1,122 +1,98 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="settings-shared">
+  :host {
+    /* #headerLine height + padding */
+    --cr-settings-header-height: calc(62px + 1.34em);
+    --title-height: 2em;
+    --title-padding: 16px;
+    display: block;
+    min-height: 328px;
+  }
 
-<link rel="import" href="chrome://resources/cr_elements/chromeos/cr_picture/cr_picture_list.html">
-<link rel="import" href="chrome://resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html">
-<link rel="import" href="chrome://resources/cr_elements/chromeos/cr_picture/cr_picture_types.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-announcer/iron-a11y-announcer.html">
-<link rel="import" href="chrome://resources/cr_elements/chromeos/cr_picture/png.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="../../i18n_setup.html">
-<link rel="import" href="../deep_linking_behavior.html">
-<link rel="import" href="../os_route.html">
-<link rel="import" href="../../router.html">
-<link rel="import" href="../route_observer_behavior.html">
-<link rel="import" href="../../settings_shared_css.html">
-<link rel="import" href="change_picture_browser_proxy.html">
-<link rel="import" href="../metrics_recorder.html">
+  #title {
+    height: var(--title-height);
+    margin-inline-start: 20px;
+    padding-top: var(--title-padding);
+  }
 
-<dom-module id="settings-change-picture">
-  <template>
-    <style include="settings-shared">
-      :host {
-        /* #headerLine height + padding */
-        --cr-settings-header-height: calc(62px + 1.34em);
-        --title-height: 2em;
-        --title-padding: 16px;
-        display: block;
-        min-height: 328px;
-      }
+  #container {
+    align-items: flex-start;
+    display: flex;
+    margin-inline-start: 20px;
+    position: absolute;
+    top: calc(var(--cr-settings-header-height) +
+              var(--title-padding) +
+              var(--title-height));
+    user-select: none;
+  }
 
-      #title {
-        height: var(--title-height);
-        margin-inline-start: 20px;
-        padding-top: var(--title-padding);
-      }
+  #picturePane {
+    --cr-picture-image-size: 192px;
+    flex-shrink: 0;
+    height: 288px;
+    margin-inline-end: 24px;
+    margin-top: 6px;
+    position: relative;
+    width: 288px;
+  }
 
-      #container {
-        align-items: flex-start;
-        display: flex;
-        margin-inline-start: 20px;
-        position: absolute;
-        top: calc(var(--cr-settings-header-height) +
-                  var(--title-padding) +
-                  var(--title-height));
-        user-select: none;
-      }
+  #sourceInfo {
+    color: var(--cros-text-color-disabled);
+    display: flex;
+    flex-direction: column;
+    margin-top: 20px;
+  }
 
-      #picturePane {
-        --cr-picture-image-size: 192px;
-        flex-shrink: 0;
-        height: 288px;
-        margin-inline-end: 24px;
-        margin-top: 6px;
-        position: relative;
-        width: 288px;
-      }
+  #pictureList {
+    /* TODO(reveman): Find a way to have height align to viewport
+        without using fixed position. */
+    height: calc(100vh -
+        var(--cr-toolbar-height) -
+        var(--cr-toolbar-padding-top) -
+        var(--cr-settings-header-height) -
+        var(--title-padding) -
+        var(--title-height));
+    margin-inline-end: 16px;
+    margin-top: 0;
+    min-height: 332px;
+    overflow-x: hidden;
+    overflow-y: auto;
+    position: relative;
+  }
 
-      #sourceInfo {
-        color: var(--cros-text-color-disabled);
-        display: flex;
-        flex-direction: column;
-        margin-top: 20px;
-      }
-
-      #pictureList {
-        /* TODO(reveman): Find a way to have height align to viewport
-           without using fixed position. */
-        height: calc(100vh -
-            var(--cr-toolbar-height) -
-            var(--cr-toolbar-padding-top) -
-            var(--cr-settings-header-height) -
-            var(--title-padding) -
-            var(--title-height));
-        margin-inline-end: 16px;
-        margin-top: 0;
-        min-height: 332px;
-        overflow-x: hidden;
-        overflow-y: auto;
-        position: relative;
-      }
-
-    </style>
-    <div id="title">$i18n{changePicturePageDescription}</div>
-    <div id="container">
-      <div>
-        <cr-picture-pane id="picturePane"
-            camera-present="[[cameraPresent_]]",
-            image-src="[[getImageSrc_(selectedItem_)]]"
-            image-type="[[getImageType_(selectedItem_)]]"
-            discard-image-label="$i18n{discardPhoto}"
-            preview-alt-text="$i18n{previewAltText}"
-            take-photo-label="$i18n{takePhoto}"
-            capture-video-label="$i18n{captureVideo}"
-            switch-mode-to-camera-label="$i18n{switchModeToCamera}"
-            switch-mode-to-video-label="$i18n{switchModeToVideo}"
-            camera-video-mode-enabled="[[cameraVideoModeEnabled_]]"
-            on-keys-pressed="onCameraPaneKeysPressed_">
-        </cr-picture-pane>
-        <div id="sourceInfo"
-            hidden="[[!shouldShowSourceInfo_(selectedItem_, authorInfo_, websiteInfo_)]]">
-          [[authorInfo_]]
-          <a href="[[websiteInfo_]]" target="_blank">
-            [[websiteInfo_]]
-          </a>
-        </div>
-      </div>
-      <cr-picture-list id="pictureList"
-          hidden="[[!currentDefaultImages_]]"
-          camera-present="[[cameraPresent_]]"
-          default-images="[[currentDefaultImages_]]"
-          selected-item="{{selectedItem_}}"
-          choose-file-label="$i18n{chooseFile}"
-          old-image-label="[[oldImageLabel_]]"
-          profile-image-label="$i18n{profilePhoto}"
-          take-photo-label="$i18n{takePhoto}"
-          capture-video-label="$i18n{captureVideo}">
-      </cr-picture-list>
+</style>
+<div id="title">$i18n{changePicturePageDescription}</div>
+<div id="container">
+  <div>
+    <cr-picture-pane id="picturePane"
+        camera-present="[[cameraPresent_]]",
+        image-src="[[getImageSrc_(selectedItem_)]]"
+        image-type="[[getImageType_(selectedItem_)]]"
+        discard-image-label="$i18n{discardPhoto}"
+        preview-alt-text="$i18n{previewAltText}"
+        take-photo-label="$i18n{takePhoto}"
+        capture-video-label="$i18n{captureVideo}"
+        switch-mode-to-camera-label="$i18n{switchModeToCamera}"
+        switch-mode-to-video-label="$i18n{switchModeToVideo}"
+        camera-video-mode-enabled="[[cameraVideoModeEnabled_]]"
+        on-keys-pressed="onCameraPaneKeysPressed_">
+    </cr-picture-pane>
+    <div id="sourceInfo"
+        hidden="[[!shouldShowSourceInfo_(selectedItem_, authorInfo_, websiteInfo_)]]">
+      [[authorInfo_]]
+      <a href="[[websiteInfo_]]" target="_blank">
+        [[websiteInfo_]]
+      </a>
     </div>
-  </template>
-  <script src="change_picture.js"></script>
-</dom-module>
+  </div>
+  <cr-picture-list id="pictureList"
+      hidden="[[!currentDefaultImages_]]"
+      camera-present="[[cameraPresent_]]"
+      default-images="[[currentDefaultImages_]]"
+      selected-item="{{selectedItem_}}"
+      choose-file-label="$i18n{chooseFile}"
+      old-image-label="[[oldImageLabel_]]"
+      profile-image-label="$i18n{profilePhoto}"
+      take-photo-label="$i18n{takePhoto}"
+      capture-video-label="$i18n{captureVideo}">
+  </cr-picture-list>
+</div>
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.js b/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.js
index 8af31828..648b5fa 100644
--- a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.js
+++ b/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.js
@@ -7,12 +7,34 @@
  * 'settings-change-picture' is the settings subpage containing controls to
  * edit a ChromeOS user's picture.
  */
+import '//resources/cr_elements/chromeos/cr_picture/cr_picture_list.js';
+import '//resources/cr_elements/chromeos/cr_picture/cr_picture_pane.js';
+import '../../settings_shared_css.js';
+
+import {CrPicture} from '//resources/cr_elements/chromeos/cr_picture/cr_picture_types.js';
+import {convertImageSequenceToPng, isEncodedPngDataUrlAnimated} from '//resources/cr_elements/chromeos/cr_picture/png.js';
+import {assert, assertNotReached} from '//resources/js/assert.m.js';
+import {I18nBehavior} from '//resources/js/i18n_behavior.m.js';
+import {WebUIListenerBehavior} from '//resources/js/web_ui_listener_behavior.m.js';
+import {IronA11yAnnouncer} from '//resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
+import {afterNextRender, flush, html, Polymer, TemplateInstanceBase, Templatizer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {loadTimeData} from '../../i18n_setup.js';
+import {Route, Router} from '../../router.js';
+import {DeepLinkingBehavior} from '../deep_linking_behavior.m.js';
+import {recordClick, recordNavigation, recordPageBlur, recordPageFocus, recordSearch, recordSettingChange, setUserActionRecorderForTesting} from '../metrics_recorder.m.js';
+import {routes} from '../os_route.m.js';
+import {RouteObserverBehavior} from '../route_observer_behavior.js';
+
+import {ChangePictureBrowserProxy, ChangePictureBrowserProxyImpl, DefaultImage} from './change_picture_browser_proxy.js';
+
 Polymer({
+  _template: html`{__html_template__}`,
   is: 'settings-change-picture',
 
   behaviors: [
     DeepLinkingBehavior,
-    settings.RouteObserverBehavior,
+    RouteObserverBehavior,
     I18nBehavior,
     WebUIListenerBehavior,
   ],
@@ -40,7 +62,7 @@
 
     /**
      * The current set of the default user images.
-     * @private {?Array<!settings.DefaultImage>}
+     * @private {?Array<!DefaultImage>}
      */
     currentDefaultImages_: {
       type: Object,
@@ -93,7 +115,7 @@
     'switch-mode': 'onSwitchMode_',
   },
 
-  /** @private {?settings.ChangePictureBrowserProxy} */
+  /** @private {?ChangePictureBrowserProxy} */
   browserProxy_: null,
 
   /** @private {?CrPictureListElement} */
@@ -104,7 +126,7 @@
 
   /** @override */
   ready() {
-    this.browserProxy_ = settings.ChangePictureBrowserProxyImpl.getInstance();
+    this.browserProxy_ = ChangePictureBrowserProxyImpl.getInstance();
     this.pictureList_ =
         /** @type {CrPictureListElement} */ (this.$.pictureList);
   },
@@ -126,7 +148,7 @@
         'camera-presence-changed', this.receiveCameraPresence_.bind(this));
 
     // Initialize the announcer once.
-    Polymer.IronA11yAnnouncer.requestAvailability();
+    IronA11yAnnouncer.requestAvailability();
   },
 
   /**
@@ -146,7 +168,7 @@
 
   /** @protected */
   currentRouteChanged(newRoute) {
-    if (newRoute === settings.routes.CHANGE_PICTURE) {
+    if (newRoute === routes.CHANGE_PICTURE) {
       this.browserProxy_.initialize();
       this.browserProxy_.requestSelectedImage();
       this.pictureList_.setFocus();
@@ -159,7 +181,7 @@
 
   /**
    * Handler for the 'default-images-changed' event.
-   * @param {{current_default_images: !Array<!settings.DefaultImage>}} info
+   * @param {{current_default_images: !Array<!DefaultImage>}} info
    * @private
    */
   receiveDefaultImages_(info) {
@@ -185,7 +207,7 @@
    */
   receiveOldImage_(imageUrl) {
     this.oldImageLabel_ = this.i18n(
-        cr.png.isEncodedPngDataUrlAnimated(imageUrl) ? 'oldVideo' : 'oldPhoto');
+        isEncodedPngDataUrlAnimated(imageUrl) ? 'oldVideo' : 'oldPhoto');
     this.oldImagePending_ = false;
     this.pictureList_.setOldImageUrl(imageUrl);
   },
@@ -248,19 +270,19 @@
         break;
       case CrPicture.SelectionTypes.FILE:
         this.browserProxy_.chooseFile();
-        settings.recordSettingChange();
+        recordSettingChange();
         break;
       case CrPicture.SelectionTypes.PROFILE:
         this.browserProxy_.selectProfileImage();
-        settings.recordSettingChange();
+        recordSettingChange();
         break;
       case CrPicture.SelectionTypes.OLD:
         this.browserProxy_.selectOldImage();
-        settings.recordSettingChange();
+        recordSettingChange();
         break;
       case CrPicture.SelectionTypes.DEFAULT:
         this.browserProxy_.selectDefaultImage(image.dataset.url);
-        settings.recordSettingChange();
+        recordSettingChange();
         break;
       default:
         assertNotReached('Selected unknown image type');
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/dark_mode_subpage.html b/chrome/browser/resources/settings/chromeos/personalization_page/dark_mode_subpage.html
index 90de6ba..948becf 100644
--- a/chrome/browser/resources/settings/chromeos/personalization_page/dark_mode_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/personalization_page/dark_mode_subpage.html
@@ -1,57 +1,39 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="../../controls/settings_radio_group.html">
-<link rel="import" href="../../controls/settings_toggle_button.html">
-<link rel="import" href="../../prefs/prefs.html">
-<link rel="import" href="../prefs_behavior.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="../deep_linking_behavior.html">
-<link rel="import" href="../../router.html">
-<link rel="import" href="../route_observer_behavior.html">
-<link rel="import" href="../os_route.html">
-
-<dom-module id="settings-dark-mode-subpage">
-  <template>
-    <style include="settings-shared"></style>
-    <div id="darkModeEnablerDiv">
-      <settings-toggle-button
-          id="darkModeToggleButton"
-          class="hr"
-          pref="{{prefs.ash.dark_mode.enabled}}"
-          label="[[getDarkModeOnOffLabel_(prefs.ash.dark_mode.enabled.value)]]"
-          deep-link-focus-id$="[[Setting.kDarkModeOnOff]]">
-      </settings-toggle-button>
-    </div>
-    <div id="darkModeThemedDiv">
-      <div class="settings-box">
-        <div class="settings-box-text start" aria-hidden="true">
-          <div id="darkModeThemedLabel" class="label">
-            $i18n{darkModeThemedRadioGroupTitle}
-          </div>
-          <div id="darkModeThemedSubLabel" class="secondary label">
-            $i18n{darkModeThemedRadioGroupDescription}
-          </div>
-        </div>
+<style include="settings-shared"></style>
+<div id="darkModeEnablerDiv">
+  <settings-toggle-button
+      id="darkModeToggleButton"
+      class="hr"
+      pref="{{prefs.ash.dark_mode.enabled}}"
+      label="[[getDarkModeOnOffLabel_(prefs.ash.dark_mode.enabled.value)]]"
+      deep-link-focus-id$="[[Setting.kDarkModeOnOff]]">
+  </settings-toggle-button>
+</div>
+<div id="darkModeThemedDiv">
+  <div class="settings-box">
+    <div class="settings-box-text start" aria-hidden="true">
+      <div id="darkModeThemedLabel" class="label">
+        $i18n{darkModeThemedRadioGroupTitle}
       </div>
-      <div class="list-frame">
-        <settings-radio-group id="darkModeThemedRadioGroup"
-            pref="{{prefs.ash.dark_mode.color_mode_themed}}"
-            group-aria-label="$i18n{darkModeThemedRadioGroupTitle}"
-            deep-link-focus-id$="[[Setting.kDarkModeThemed]]">
-          <cr-radio-button id="darkModeThemedOn"
-              name="true" class="list-item underbar"
-              pref="[[prefs.ash.dark_mode.color_mode_themed]]"
-              label="$i18n{darkModeThemedOn}">
-          </cr-radio-button>
-          <cr-radio-button id="darkModeThemedOff"
-              name="false" class="list-item"
-              pref="[[prefs.ash.dark_mode.color_mode_themed]]"
-              label="$i18n{darkModeThemedOff}">
-          </cr-radio-button>
-        </settings-radio-group>
+      <div id="darkModeThemedSubLabel" class="secondary label">
+        $i18n{darkModeThemedRadioGroupDescription}
       </div>
     </div>
-  </template>
-  <script src="dark_mode_subpage.js"></script>
-</dom-module>
+  </div>
+  <div class="list-frame">
+    <settings-radio-group id="darkModeThemedRadioGroup"
+        pref="{{prefs.ash.dark_mode.color_mode_themed}}"
+        group-aria-label="$i18n{darkModeThemedRadioGroupTitle}"
+        deep-link-focus-id$="[[Setting.kDarkModeThemed]]">
+      <cr-radio-button id="darkModeThemedOn"
+          name="true" class="list-item underbar"
+          pref="[[prefs.ash.dark_mode.color_mode_themed]]"
+          label="$i18n{darkModeThemedOn}">
+      </cr-radio-button>
+      <cr-radio-button id="darkModeThemedOff"
+          name="false" class="list-item"
+          pref="[[prefs.ash.dark_mode.color_mode_themed]]"
+          label="$i18n{darkModeThemedOff}">
+      </cr-radio-button>
+    </settings-radio-group>
+  </div>
+</div>
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/dark_mode_subpage.js b/chrome/browser/resources/settings/chromeos/personalization_page/dark_mode_subpage.js
index 6178340..61cd31a 100644
--- a/chrome/browser/resources/settings/chromeos/personalization_page/dark_mode_subpage.js
+++ b/chrome/browser/resources/settings/chromeos/personalization_page/dark_mode_subpage.js
@@ -7,11 +7,26 @@
  *  dark mode settings to switch between dark and light mode, theming,
  *  and a scheduler.
  */
+import '../../controls/settings_radio_group.js';
+import '../../controls/settings_toggle_button.js';
+import '../../prefs/prefs.js';
+import '//resources/cr_elements/cr_radio_button/cr_radio_button.m.js';
+
+import {I18nBehavior} from '//resources/js/i18n_behavior.m.js';
+import {afterNextRender, flush, html, Polymer, TemplateInstanceBase, Templatizer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {Route, Router} from '../../router.js';
+import {DeepLinkingBehavior} from '../deep_linking_behavior.m.js';
+import {routes} from '../os_route.m.js';
+import {PrefsBehavior} from '../prefs_behavior.js';
+import {RouteObserverBehavior} from '../route_observer_behavior.js';
+
 Polymer({
+  _template: html`{__html_template__}`,
   is: 'settings-dark-mode-subpage',
 
   behaviors: [
-    settings.RouteObserverBehavior,
+    RouteObserverBehavior,
     DeepLinkingBehavior,
     I18nBehavior,
     PrefsBehavior,
@@ -39,13 +54,13 @@
   },
 
   /**
-   * settings.RouteObserverBehavior
-   * @param {!settings.Route} route
-   * @param {!settings.Route} oldRoute
+   * RouteObserverBehavior
+   * @param {!Route} route
+   * @param {!Route} oldRoute
    * @protected
    */
   currentRouteChanged(route, oldRoute) {
-    if (route !== settings.routes.DARK_MODE) {
+    if (route !== routes.DARK_MODE) {
       return;
     }
     this.attemptDeepLink();
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html
index b2efaf59..39338683 100644
--- a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html
+++ b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html
@@ -1,100 +1,77 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="../ambient_mode_page/ambient_mode_page.html">
-<link rel="import" href="../ambient_mode_page/ambient_mode_photos_page.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="change_picture.html">
-<link rel="import" href="dark_mode_subpage.html">
-<link rel="import" href="../deep_linking_behavior.html">
-<link rel="import" href="../os_route.html">
-<link rel="import" href="../../router.html">
-<link rel="import" href="../route_observer_behavior.html">
-<link rel="import" href="../../i18n_setup.html">
-<link rel="import" href="../../settings_page/settings_animated_pages.html">
-<link rel="import" href="../../settings_page/settings_subpage.html">
-<link rel="import" href="../../settings_shared_css.html">
-<link rel="import" href="wallpaper_browser_proxy.html">
-
-<dom-module id="settings-personalization-page">
-  <template>
-    <style include="settings-shared"></style>
-    <settings-animated-pages id="pages" section="personalization"
-        focus-config="[[focusConfig_]]">
-      <div route-path="default">
-        <cr-link-row id="changePictureRow"
-            label="$i18n{changePictureTitle}"
-            on-click="navigateToChangePicture_"
-            role-description="$i18n{subpageArrowRoleDescription}">
-        </cr-link-row>
-        <cr-link-row class="hr" id="wallpaperButton"
-            hidden="[[!showWallpaperRow_]]"
-            on-click="openWallpaperManager_" label="$i18n{setWallpaper}"
-            sub-label="$i18n{openWallpaperApp}"
-            disabled="[[isWallpaperPolicyControlled_]]" external
-            deep-link-focus-id$="[[Setting.kOpenWallpaper]]">
-          <template is="dom-if" if="[[isWallpaperPolicyControlled_]]">
-            <cr-policy-indicator id="wallpaperPolicyIndicator"
-                indicator-type="devicePolicy">
-            </cr-policy-indicator>
-          </template>
-        </cr-link-row>
-
-        <!-- Ambient mode -->
-        <template is="dom-if" if="[[isAmbientModeEnabled_]]">
-          <cr-link-row
-              class="hr"
-              id="ambientModeRow"
-              label="$i18n{ambientModeTitle}"
-              sub-label="[[getAmbientModeRowSubLabel_(
-                  prefs.settings.ambient_mode.enabled.value)]]"
-              on-click="navigateToAmbientMode_"
-              role-description="$i18n{subpageArrowRoleDescription}">
-          </cr-link-row>
-        </template>
-
-        <!-- Dark mode -->
-        <template is="dom-if" if="[[isDarkModeAllowed_]]">
-          <cr-link-row
-              class="hr"
-              id="darkModeRow"
-              label="$i18n{darkModeTitle}"
-              on-click="navigateToDarkMode_"
-              role-description="$i18n{subpageArrowRoleDescription}">
-          </cr-link-row>
-        </template>
-      </div>
-
-      <template is="dom-if" route-path="/changePicture">
-        <settings-subpage page-title="$i18n{changePictureTitle}">
-          <settings-change-picture></settings-change-picture>
-        </settings-subpage>
+<style include="settings-shared"></style>
+<settings-animated-pages id="pages" section="personalization"
+    focus-config="[[focusConfig_]]">
+  <div route-path="default">
+    <cr-link-row id="changePictureRow"
+        label="$i18n{changePictureTitle}"
+        on-click="navigateToChangePicture_"
+        role-description="$i18n{subpageArrowRoleDescription}">
+    </cr-link-row>
+    <cr-link-row class="hr" id="wallpaperButton"
+        hidden="[[!showWallpaperRow_]]"
+        on-click="openWallpaperManager_" label="$i18n{setWallpaper}"
+        sub-label="$i18n{openWallpaperApp}"
+        disabled="[[isWallpaperPolicyControlled_]]" external
+        deep-link-focus-id$="[[Setting.kOpenWallpaper]]">
+      <template is="dom-if" if="[[isWallpaperPolicyControlled_]]">
+        <cr-policy-indicator id="wallpaperPolicyIndicator"
+            indicator-type="devicePolicy">
+        </cr-policy-indicator>
       </template>
+    </cr-link-row>
 
-      <template is="dom-if" if="[[isAmbientModeEnabled_]]">
-        <template is="dom-if" route-path="/ambientMode">
-          <settings-subpage page-title="$i18n{ambientModeTitle}">
-            <settings-ambient-mode-page prefs="{{prefs}}">
-            </settings-ambient-mode-page>
-          </settings-subpage>
-        </template>
+    <!-- Ambient mode -->
+    <template is="dom-if" if="[[isAmbientModeEnabled_]]">
+      <cr-link-row
+          class="hr"
+          id="ambientModeRow"
+          label="$i18n{ambientModeTitle}"
+          sub-label="[[getAmbientModeRowSubLabel_(
+              prefs.settings.ambient_mode.enabled.value)]]"
+          on-click="navigateToAmbientMode_"
+          role-description="$i18n{subpageArrowRoleDescription}">
+      </cr-link-row>
+    </template>
 
-        <template is="dom-if" route-path="/ambientMode/photos">
-          <settings-subpage>
-            <settings-ambient-mode-photos-page>
-            </settings-ambient-mode-photos-page>
-          </settings-subpage>
-        </template>
+    <!-- Dark mode -->
+    <template is="dom-if" if="[[isDarkModeAllowed_]]">
+      <cr-link-row
+          class="hr"
+          id="darkModeRow"
+          label="$i18n{darkModeTitle}"
+          on-click="navigateToDarkMode_"
+          role-description="$i18n{subpageArrowRoleDescription}">
+      </cr-link-row>
+    </template>
+  </div>
 
-      </template>
-
-      <template is="dom-if" route-path="/darkMode">
-        <settings-subpage page-title="$i18n{darkModeTitle}">
-          <settings-dark-mode-subpage prefs="{{prefs}}">
-          </settings-dark-mode-subpage>
-        </settings-subpage>
-      </template>
-    </settings-animated-pages>
+  <template is="dom-if" route-path="/changePicture">
+    <settings-subpage page-title="$i18n{changePictureTitle}">
+      <settings-change-picture></settings-change-picture>
+    </settings-subpage>
   </template>
-  <script src="personalization_page.js"></script>
-</dom-module>
+
+  <template is="dom-if" if="[[isAmbientModeEnabled_]]">
+    <template is="dom-if" route-path="/ambientMode">
+      <settings-subpage page-title="$i18n{ambientModeTitle}">
+        <settings-ambient-mode-page prefs="{{prefs}}">
+        </settings-ambient-mode-page>
+      </settings-subpage>
+    </template>
+
+    <template is="dom-if" route-path="/ambientMode/photos">
+      <settings-subpage>
+        <settings-ambient-mode-photos-page>
+        </settings-ambient-mode-photos-page>
+      </settings-subpage>
+    </template>
+
+  </template>
+
+  <template is="dom-if" route-path="/darkMode">
+    <settings-subpage page-title="$i18n{darkModeTitle}">
+      <settings-dark-mode-subpage prefs="{{prefs}}">
+      </settings-dark-mode-subpage>
+    </settings-subpage>
+  </template>
+</settings-animated-pages>
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js
index 3e76805..cd9f6bd 100644
--- a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js
+++ b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js
@@ -6,13 +6,34 @@
  * 'settings-personalization-page' is the settings page containing
  * personalization settings.
  */
+import '../ambient_mode_page/ambient_mode_page.js';
+import '../ambient_mode_page/ambient_mode_photos_page.js';
+import '//resources/cr_elements/cr_link_row/cr_link_row.js';
+import './change_picture.js';
+import './dark_mode_subpage.js';
+import '../../settings_page/settings_animated_pages.js';
+import '../../settings_page/settings_subpage.js';
+import '../../settings_shared_css.js';
+
+import {I18nBehavior} from '//resources/js/i18n_behavior.m.js';
+import {afterNextRender, flush, html, Polymer, TemplateInstanceBase, Templatizer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {loadTimeData} from '../../i18n_setup.js';
+import {Route, Router} from '../../router.js';
+import {DeepLinkingBehavior} from '../deep_linking_behavior.m.js';
+import {routes} from '../os_route.m.js';
+import {RouteObserverBehavior} from '../route_observer_behavior.js';
+
+import {WallpaperBrowserProxy, WallpaperBrowserProxyImpl} from './wallpaper_browser_proxy.js';
+
 Polymer({
+  _template: html`{__html_template__}`,
   is: 'settings-personalization-page',
 
   behaviors: [
     DeepLinkingBehavior,
     I18nBehavior,
-    settings.RouteObserverBehavior,
+    RouteObserverBehavior,
   ],
 
   properties: {
@@ -50,10 +71,10 @@
       type: Object,
       value() {
         const map = new Map();
-        if (settings.routes.CHANGE_PICTURE) {
-          map.set(settings.routes.CHANGE_PICTURE.path, '#changePictureRow');
-        } else if (settings.routes.AMBIENT_MODE) {
-          map.set(settings.routes.AMBIENT_MODE.path, '#ambientModeRow');
+        if (routes.CHANGE_PICTURE) {
+          map.set(routes.CHANGE_PICTURE.path, '#changePictureRow');
+        } else if (routes.AMBIENT_MODE) {
+          map.set(routes.AMBIENT_MODE.path, '#ambientModeRow');
         }
 
         return map;
@@ -70,12 +91,12 @@
     },
   },
 
-  /** @private {?settings.WallpaperBrowserProxy} */
+  /** @private {?WallpaperBrowserProxy} */
   browserProxy_: null,
 
   /** @override */
   created() {
-    this.browserProxy_ = settings.WallpaperBrowserProxyImpl.getInstance();
+    this.browserProxy_ = WallpaperBrowserProxyImpl.getInstance();
   },
 
   /** @override */
@@ -91,12 +112,12 @@
   },
 
   /**
-   * @param {!settings.Route} route
-   * @param {!settings.Route} oldRoute
+   * @param {!Route} route
+   * @param {!Route} oldRoute
    */
   currentRouteChanged(route, oldRoute) {
     // Does not apply to this page.
-    if (route !== settings.routes.PERSONALIZATION) {
+    if (route !== routes.PERSONALIZATION) {
       return;
     }
 
@@ -112,17 +133,17 @@
 
   /** @private */
   navigateToChangePicture_() {
-    settings.Router.getInstance().navigateTo(settings.routes.CHANGE_PICTURE);
+    Router.getInstance().navigateTo(routes.CHANGE_PICTURE);
   },
 
   /** @private */
   navigateToAmbientMode_() {
-    settings.Router.getInstance().navigateTo(settings.routes.AMBIENT_MODE);
+    Router.getInstance().navigateTo(routes.AMBIENT_MODE);
   },
 
   /** @private */
   navigateToDarkMode_() {
-    settings.Router.getInstance().navigateTo(settings.routes.DARK_MODE);
+    Router.getInstance().navigateTo(routes.DARK_MODE);
   },
 
   /**
diff --git a/chrome/browser/resources/settings/people_page/sync_account_control.ts b/chrome/browser/resources/settings/people_page/sync_account_control.ts
index 1d41429b9..d1b80f0 100644
--- a/chrome/browser/resources/settings/people_page/sync_account_control.ts
+++ b/chrome/browser/resources/settings/people_page/sync_account_control.ts
@@ -318,13 +318,13 @@
       return false;
     }
     // </if>
+
     // <if expr="lacros">
-    if (!loadTimeData.getBoolean('isSignoutSupported')) {
-      // On Lacros the primary account doesn't support turning off sync yet.
-      // TODO(https://crbug.com/1217645): Remove after adding sync off state.
-      return false;
-    }
+    // On Lacros the primary account doesn't support turning off sync yet.
+    // TODO(https://crbug.com/1217645): Remove after adding sync off state.
+    return false;
     // </if>
+
     return !this.hideButtons && !this.showSetupButtons_ &&
         !!this.syncStatus.signedIn;
   }
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/profile_type_choice.ts b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/profile_type_choice.ts
index 164432e..259b3028 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/profile_type_choice.ts
+++ b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/profile_type_choice.ts
@@ -119,9 +119,7 @@
 
   private onSignInClick_() {
     // <if expr="lacros">
-    if (loadTimeData.getBoolean(
-            'isMultiProfileAccountConsistentcyLacrosEnabled') &&
-        this.hasAvailableAccounts_) {
+    if (this.hasAvailableAccounts_) {
       navigateTo(Routes.ACCOUNT_SELECTION_LACROS);
       return;
     }
diff --git a/chrome/browser/resources/sync_file_system_internals/main.html b/chrome/browser/resources/sync_file_system_internals/main.html
index 57ec91d3..1a82485 100644
--- a/chrome/browser/resources/sync_file_system_internals/main.html
+++ b/chrome/browser/resources/sync_file_system_internals/main.html
@@ -14,6 +14,7 @@
 <script type="module" src="task_log.js"></script>
 <script type="module" src="extension_statuses.js"></script>
 <script type="module" src="dump_database.js"></script>
+<script type="module" src="file_metadata.js"></script>
 
 <body>
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index c4b43ad..ac182b7 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -867,9 +867,10 @@
                                       base::NullCallback());
   WebContents* new_tab_contents = web_contents_added_observer.GetWebContents();
   content::RenderFrameHost* new_tab_rfh = new_tab_contents->GetMainFrame();
-  // A fresh WebContents should not have any NavigationEntries yet. (See
-  // https://crbug.com/524208.)
-  EXPECT_EQ(nullptr, new_tab_contents->GetController().GetLastCommittedEntry());
+  // A fresh WebContents should be on the initial NavigationEntry.
+  EXPECT_TRUE(new_tab_contents->GetController()
+                  .GetLastCommittedEntry()
+                  ->IsInitialEntry());
   EXPECT_EQ(nullptr, new_tab_contents->GetController().GetPendingEntry());
 
   // Run javascript in the blank new tab to load the malware image.
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc
index 901ee16..c9573b71 100644
--- a/chrome/browser/safe_browsing/threat_details_unittest.cc
+++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -32,6 +32,7 @@
 #include "components/security_interstitials/core/unsafe_resource.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/global_routing_id.h"
+#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
@@ -1546,9 +1547,8 @@
 }
 
 TEST_F(ThreatDetailsTest, ThreatOnFreshTab) {
-  // A fresh WebContents should not have any NavigationEntries yet. (See
-  // https://crbug.com/524208.)
-  EXPECT_EQ(nullptr, controller().GetLastCommittedEntry());
+  // A fresh WebContents should be on the initial NavigationEntry.
+  EXPECT_TRUE(controller().GetLastCommittedEntry()->IsInitialEntry());
   EXPECT_EQ(nullptr, controller().GetPendingEntry());
 
   // Initiate the connection to a (pretend) renderer process.
diff --git a/chrome/browser/sessions/session_data_deleter.cc b/chrome/browser/sessions/session_data_deleter.cc
index 79f4e5ac..acc99c9 100644
--- a/chrome/browser/sessions/session_data_deleter.cc
+++ b/chrome/browser/sessions/session_data_deleter.cc
@@ -121,13 +121,8 @@
         // Fire and forget. Session cookies will be cleaned up on start as well.
         // (SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup)
         base::DoNothing());
-
-    // If the permissions policy feature is enabled, delete the client hint
-    // preferences
-    if (base::FeatureList::IsEnabled(features::kFeaturePolicyForClientHints)) {
-      host_content_settings_map->ClearSettingsForOneType(
-          ContentSettingsType::CLIENT_HINTS);
-    }
+    host_content_settings_map->ClearSettingsForOneType(
+        ContentSettingsType::CLIENT_HINTS);
   }
 
   if (!storage_policy_.get() || !storage_policy_->HasSessionOnlyOrigins())
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc
index 480a947..28c3a27c 100644
--- a/chrome/browser/sessions/session_restore_browsertest.cc
+++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -2711,6 +2711,43 @@
       subframe_instance_c->IsRelatedSiteInstance(subframe->GetSiteInstance()));
 }
 
+// Tests that an initial NavigationEntry does not get restored.
+IN_PROC_BROWSER_TEST_F(MultiOriginSessionRestoreTest, RestoreInitialEntry) {
+  GURL main_url = embedded_test_server()->GetURL("foo.com", "/title1.html");
+  url::Origin main_origin = url::Origin::Create(main_url);
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_url));
+  content::WebContents* old_popup = nullptr;
+  {
+    // Open a new window that stays on the initial NavigationEntry.
+    content::WebContents* tab1 = GetTab(browser(), 0);
+    content::WebContentsAddedObserver popup_observer;
+    ASSERT_TRUE(ExecJs(tab1, "window.open('/nocontent')"));
+    old_popup = popup_observer.GetWebContents();
+    EXPECT_EQ(GURL::EmptyGURL(),
+              old_popup->GetMainFrame()->GetLastCommittedURL());
+    EXPECT_EQ(main_origin, old_popup->GetMainFrame()->GetLastCommittedOrigin());
+    EXPECT_TRUE(
+        old_popup->GetController().GetLastCommittedEntry()->IsInitialEntry());
+  }
+
+  // Kill the original browser then open a new one to trigger a restore.
+  Browser* new_browser = QuitBrowserAndRestore(browser());
+  ASSERT_EQ(1u, active_browser_list_->size());
+  // We only restore 1 tab, the main tab.
+  ASSERT_EQ(1, new_browser->tab_strip_model()->count());
+  content::WebContents* new_browser_tab = GetTab(new_browser, 0);
+  old_popup = nullptr;
+
+  // Verify that the restored tab is the main tab instead of the initial
+  // NavigationEntry tab.
+  EXPECT_EQ(main_url, new_browser_tab->GetMainFrame()->GetLastCommittedURL());
+  EXPECT_EQ(main_origin,
+            new_browser_tab->GetMainFrame()->GetLastCommittedOrigin());
+  EXPECT_FALSE(new_browser_tab->GetController()
+                   .GetLastCommittedEntry()
+                   ->IsInitialEntry());
+}
+
 // Check that TabManager.TimeSinceTabClosedUntilRestored histogram is not
 // recorded on session restore.
 IN_PROC_BROWSER_TEST_F(SessionRestoreTest,
diff --git a/chrome/browser/signin/account_consistency_mode_manager.cc b/chrome/browser/signin/account_consistency_mode_manager.cc
index 559f167..2aafbe3d 100644
--- a/chrome/browser/signin/account_consistency_mode_manager.cc
+++ b/chrome/browser/signin/account_consistency_mode_manager.cc
@@ -13,6 +13,7 @@
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/signin/account_consistency_mode_manager_factory.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/common/pref_names.h"
@@ -26,10 +27,6 @@
 #include "chrome/browser/ash/account_manager/account_manager_util.h"
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-#include "chrome/browser/lacros/account_manager/account_manager_util.h"
-#endif
-
 using signin::AccountConsistencyMethod;
 
 namespace {
@@ -188,8 +185,13 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-  // Mirror / Account Manager is available only for the first / Main Profile.
-  if (IsAccountManagerAvailable(profile))
+  bool is_account_manager_available = true;
+  // Account consistency is unavailable on Managed Guest Sessions and Public
+  // Sessions.
+  if (profiles::IsPublicSession())
+    is_account_manager_available = false;
+
+  if (is_account_manager_available)
     return AccountConsistencyMethod::kMirror;
     // else: Fall through to ENABLE_DICE_SUPPORT section below.
     // TODO(crbug.com/1198490): Return `AccountConsistencyMethod::kDisabled` if
diff --git a/chrome/browser/signin/account_consistency_mode_manager_unittest.cc b/chrome/browser/signin/account_consistency_mode_manager_unittest.cc
index ca8f880..139ee8aeb 100644
--- a/chrome/browser/signin/account_consistency_mode_manager_unittest.cc
+++ b/chrome/browser/signin/account_consistency_mode_manager_unittest.cc
@@ -8,13 +8,11 @@
 #include <utility>
 
 #include "base/command_line.h"
-#include "base/feature_list.h"
 #include "base/test/scoped_command_line.h"
 #include "build/build_config.h"
 #include "build/buildflag.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/prefs/browser_prefs.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/supervised_user/supervised_user_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
@@ -46,12 +44,9 @@
       BuildTestingProfile(/*is_new_profile=*/false);
 
   signin::AccountConsistencyMethod method =
-#if BUILDFLAG(ENABLE_MIRROR) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(ENABLE_MIRROR) || BUILDFLAG(IS_CHROMEOS_ASH) || \
+    BUILDFLAG(IS_CHROMEOS_LACROS)
       signin::AccountConsistencyMethod::kMirror;
-#elif BUILDFLAG(IS_CHROMEOS_LACROS)
-      base::FeatureList::IsEnabled(kMultiProfileAccountConsistency)
-          ? signin::AccountConsistencyMethod::kMirror
-          : signin::AccountConsistencyMethod::kDice;
 #elif BUILDFLAG(ENABLE_DICE_SUPPORT)
       signin::AccountConsistencyMethod::kDice;
 #else
@@ -213,11 +208,6 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
 // Mirror is enabled by default on Chrome OS, unless specified otherwise.
 TEST(AccountConsistencyModeManagerTest, MirrorEnabledByDefault) {
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  if (!base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-    GTEST_SKIP();
-#endif
-
   // Creation of this object sets the current thread's id as UI thread.
   content::BrowserTaskEnvironment task_environment;
 
@@ -231,11 +221,6 @@
 }
 
 TEST(AccountConsistencyModeManagerTest, MirrorDisabledForGuestSession) {
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  if (!base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-    GTEST_SKIP();
-#endif
-
   // Creation of this object sets the current thread's id as UI thread.
   content::BrowserTaskEnvironment task_environment;
 
@@ -250,11 +235,6 @@
 }
 
 TEST(AccountConsistencyModeManagerTest, MirrorDisabledForOffTheRecordProfile) {
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  if (!base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-    GTEST_SKIP();
-#endif
-
   // Creation of this object sets the current thread's id as UI thread.
   content::BrowserTaskEnvironment task_environment;
 
diff --git a/chrome/browser/signin/chrome_signin_helper.cc b/chrome/browser/signin/chrome_signin_helper.cc
index ed0aae3..00a7ce5a 100644
--- a/chrome/browser/signin/chrome_signin_helper.cc
+++ b/chrome/browser/signin/chrome_signin_helper.cc
@@ -340,22 +340,19 @@
   // 3. Displaying an account addition window.
   if (service_type == GAIA_SERVICE_TYPE_ADDSESSION) {
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-    if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency)) {
-      AccountProfileMapper* mapper =
-          g_browser_process->profile_manager()->GetAccountProfileMapper();
-      GetAccountsAvailableAsSecondary(
-          mapper, profile->GetPath(),
-          // It's safe to bind raw `mapper`, the callback gets called iff
-          // `mapper` is still valid.
-          base::BindOnce(&OnLacrosAccountsAvailableAsSecondaryFetched, mapper,
-                         profile->GetPath()));
-      return;
-    }
-#endif
-
+    AccountProfileMapper* mapper =
+        g_browser_process->profile_manager()->GetAccountProfileMapper();
+    GetAccountsAvailableAsSecondary(
+        mapper, profile->GetPath(),
+        // It's safe to bind raw `mapper`, the callback gets called iff
+        // `mapper` is still valid.
+        base::BindOnce(&OnLacrosAccountsAvailableAsSecondaryFetched, mapper,
+                       profile->GetPath()));
+#else
     ::GetAccountManagerFacade(profile->GetPath().value())
         ->ShowAddAccountDialog(account_manager::AccountManagerFacade::
                                    AccountAdditionSource::kOgbAddAccount);
+#endif
     return;
   }
 
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc b/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc
index 2fa6f19..1f66d5d 100644
--- a/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc
+++ b/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "base/callback.h"
-#include "base/feature_list.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -190,11 +189,6 @@
 
     // Create the first tab so that web_contents() exists.
     AddTab(browser(), GURL("http://foo/1"));
-
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-    if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-      GTEST_SKIP();
-#endif
   }
 
   void TearDown() override {
diff --git a/chrome/browser/signin/identity_manager_factory.cc b/chrome/browser/signin/identity_manager_factory.cc
index 01a572b..3fa73700 100644
--- a/chrome/browser/signin/identity_manager_factory.cc
+++ b/chrome/browser/signin/identity_manager_factory.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <utility>
 
-#include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -17,7 +16,6 @@
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/identity_manager_provider.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/pref_registry/pref_registry_syncable.h"
@@ -64,8 +62,7 @@
   DependsOn(WebDataServiceFactory::GetInstance());
 #endif
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-  if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-    DependsOn(ProfileAccountManagerFactory::GetInstance());
+  DependsOn(ProfileAccountManagerFactory::GetInstance());
 #endif
   DependsOn(ChromeSigninClientFactory::GetInstance());
   signin::SetIdentityManagerProvider(
@@ -145,7 +142,6 @@
   // The system and (original profile of the) guest profiles are not regular.
   const bool is_regular_profile = profile->IsRegularProfile();
   const bool use_profile_account_manager =
-      base::FeatureList::IsEnabled(kMultiProfileAccountConsistency) &&
       is_regular_profile &&
       // `ProfileManager` may be null in tests, and is required for account
       // consistency.
diff --git a/chrome/browser/signin/signin_features.cc b/chrome/browser/signin/signin_features.cc
index 3ecff10..b193280 100644
--- a/chrome/browser/signin/signin_features.cc
+++ b/chrome/browser/signin/signin_features.cc
@@ -14,9 +14,3 @@
 // the profile picker.
 const base::Feature kAccountPoliciesLoadedWithoutSync{
     "AccountPoliciesLoadedWithoutSync", base::FEATURE_DISABLED_BY_DEFAULT};
-
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-// Enable support for account consistency across multiple profiles.
-const base::Feature kMultiProfileAccountConsistency{
-    "MultiProfileAccountConsistency", base::FEATURE_ENABLED_BY_DEFAULT};
-#endif
diff --git a/chrome/browser/signin/signin_features.h b/chrome/browser/signin/signin_features.h
index 7232a9e..47c61c2 100644
--- a/chrome/browser/signin/signin_features.h
+++ b/chrome/browser/signin/signin_features.h
@@ -12,8 +12,4 @@
 
 extern const base::Feature kAccountPoliciesLoadedWithoutSync;
 
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-extern const base::Feature kMultiProfileAccountConsistency;
-#endif
-
 #endif  // CHROME_BROWSER_SIGNIN_SIGNIN_FEATURES_H_
diff --git a/chrome/browser/signin/signin_manager_factory.cc b/chrome/browser/signin/signin_manager_factory.cc
index 25b251d6..788dbee 100644
--- a/chrome/browser/signin/signin_manager_factory.cc
+++ b/chrome/browser/signin/signin_manager_factory.cc
@@ -4,10 +4,8 @@
 
 #include "chrome/browser/signin/signin_manager_factory.h"
 
-#include "base/feature_list.h"
 #include "base/logging.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_features.h"
@@ -36,16 +34,6 @@
 
 KeyedService* SigninManagerFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  // On Lacros with Mirror, signed-out profiles are not supported yet. Disable
-  // the `SigninManager` so that it does not remove the primary account.
-  // TODO(https://crbug.com/1259872): Revisit this once Dice is no longer
-  // supported on Lacros, and see if the SigninManager can be removed from the
-  // build entirely.
-  if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-    return nullptr;
-#endif
-
   Profile* profile = Profile::FromBrowserContext(context);
   return new SigninManager(profile->GetPrefs(),
                            IdentityManagerFactory::GetForProfile(profile));
diff --git a/chrome/browser/signin/signin_ui_util.cc b/chrome/browser/signin/signin_ui_util.cc
index 6ee3f45..a045ab2 100644
--- a/chrome/browser/signin/signin_ui_util.cc
+++ b/chrome/browser/signin/signin_ui_util.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/ui/browser.h"
@@ -52,7 +53,6 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-#include "chrome/browser/lacros/account_manager/account_manager_util.h"
 #include "components/account_manager_core/account_manager_facade.h"
 #include "components/account_manager_core/chromeos/account_manager_facade_factory.h"
 #endif
@@ -232,12 +232,16 @@
 void ShowExtensionSigninPrompt(Profile* profile,
                                bool enable_sync,
                                const std::string& email_hint) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  NOTREACHED();
+#else
   internal::ShowExtensionSigninPrompt(
       profile,
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
       ::GetAccountManagerFacade(profile->GetPath().value()),
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
       enable_sync, email_hint);
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 namespace internal {
@@ -247,25 +251,20 @@
     signin_metrics::AccessPoint access_point,
     account_manager::AccountManagerFacade* account_manager_facade) {
   Profile* profile = browser->profile();
-  if (IsAccountManagerAvailable(profile)) {
-    signin::IdentityManager* identity_manager =
-        IdentityManagerFactory::GetForProfile(profile);
-    CoreAccountInfo primary_account_info =
-        identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin);
-    DCHECK(!primary_account_info.IsEmpty());
-    DCHECK(identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
-        primary_account_info.account_id));
-    account_manager_facade->ShowReauthAccountDialog(
-        GetAccountReauthSourceFromAccessPoint(access_point),
-        primary_account_info.email);
-  } else {
-    DCHECK(!base::FeatureList::IsEnabled(kMultiProfileAccountConsistency));
-    browser->signin_view_controller()->ShowSignin(
-        profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, access_point);
-  }
+  signin::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(profile);
+  CoreAccountInfo primary_account_info =
+      identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin);
+  DCHECK(!primary_account_info.IsEmpty());
+  DCHECK(identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
+      primary_account_info.account_id));
+  account_manager_facade->ShowReauthAccountDialog(
+      GetAccountReauthSourceFromAccessPoint(access_point),
+      primary_account_info.email);
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 void ShowExtensionSigninPrompt(
     Profile* profile,
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
@@ -273,9 +272,6 @@
 #endif
     bool enable_sync,
     const std::string& email_hint) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  NOTREACHED();
-#else
   // There is no sign-in flow for guest or system profile.
   if (profile->IsGuestSession() || profile->IsSystemProfile())
     return;
@@ -289,32 +285,27 @@
   }
 
   // This may be called in incognito. Redirect to the original profile.
-  Profile* original_profile = profile->GetOriginalProfile();
+  profile = profile->GetOriginalProfile();
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-  // TODO(https://crbug.com/1233933): remove the fallback to DICE once the
-  // feature is deleted.
-  if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency)) {
-    // There is no sign-in without an account manager.
-    if (!IsAccountManagerAvailable(original_profile))
-      return;
+  // There is no sign-in without Mirror.
+  if (!AccountConsistencyModeManager::IsMirrorEnabledForProfile(profile))
+    return;
 
-    if (email_hint.empty()) {
-      // Add a new account.
-      // TODO(https://crbug.com/1260291): add support for signed out profiles.
-      NOTREACHED() << "Lacros doesn't support signed-out profiles yet.";
-      return;
-    }
-
-    // Re-authenticate an existing account.
-    account_manager_facade->ShowReauthAccountDialog(
-        account_manager::AccountManagerFacade::AccountAdditionSource::
-            kChromeExtensionReauth,
-        email_hint);
+  if (email_hint.empty()) {
+    // Add a new account.
+    // TODO(https://crbug.com/1260291): add support for signed out profiles.
+    NOTREACHED() << "Lacros doesn't support signed-out profiles yet.";
     return;
   }
-#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
-  chrome::ScopedTabbedBrowserDisplayer displayer(original_profile);
+
+  // Re-authenticate an existing account.
+  account_manager_facade->ShowReauthAccountDialog(
+      account_manager::AccountManagerFacade::AccountAdditionSource::
+          kChromeExtensionReauth,
+      email_hint);
+#elif BUILDFLAG(ENABLE_DICE_SUPPORT)
+  chrome::ScopedTabbedBrowserDisplayer displayer(profile);
   Browser* browser = displayer.browser();
 
   // Cannot sign in if browser cannot be displayed.
@@ -331,8 +322,10 @@
     browser->signin_view_controller()->ShowDiceAddAccountTab(
         signin_metrics::AccessPoint::ACCESS_POINT_EXTENSIONS, email_hint);
   }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 }
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
+
 }  // namespace internal
 
 void EnableSyncFromSingleAccountPromo(
diff --git a/chrome/browser/signin/signin_ui_util.h b/chrome/browser/signin/signin_ui_util.h
index 95b0699..075952e 100644
--- a/chrome/browser/signin/signin_ui_util.h
+++ b/chrome/browser/signin/signin_ui_util.h
@@ -71,6 +71,7 @@
     account_manager::AccountManagerFacade* account_manager_facade);
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 void ShowExtensionSigninPrompt(
     Profile* profile,
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
@@ -78,6 +79,7 @@
 #endif
     bool enable_sync,
     const std::string& email_hint);
+#endif
 }  // namespace internal
 
 // This function is used to enable sync for a given account:
diff --git a/chrome/browser/signin/signin_ui_util_browsertest.cc b/chrome/browser/signin/signin_ui_util_browsertest.cc
index 2b701e7d..299e455 100644
--- a/chrome/browser/signin/signin_ui_util_browsertest.cc
+++ b/chrome/browser/signin/signin_ui_util_browsertest.cc
@@ -9,10 +9,9 @@
 
 #include "base/callback_helpers.h"
 #include "base/test/bind.h"
-#include "base/test/scoped_feature_list.h"
+#include "build/buildflag.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -29,11 +28,7 @@
 
 class DiceSigninUiUtilBrowserTest : public InProcessBrowserTest {
  public:
-  DiceSigninUiUtilBrowserTest() {
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-    scoped_feature_list_.InitAndDisableFeature(kMultiProfileAccountConsistency);
-#endif
-  }
+  DiceSigninUiUtilBrowserTest() = default;
   ~DiceSigninUiUtilBrowserTest() override = default;
 
   Profile* CreateProfile() {
@@ -55,9 +50,6 @@
   }
 
  private:
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  base::test::ScopedFeatureList scoped_feature_list_;
-#endif
 };
 
 // Tests that `ShowExtensionSigninPrompt()` doesn't crash when it cannot create
diff --git a/chrome/browser/signin/signin_ui_util_unittest.cc b/chrome/browser/signin/signin_ui_util_unittest.cc
index ea96e431..59397971 100644
--- a/chrome/browser/signin/signin_ui_util_unittest.cc
+++ b/chrome/browser/signin/signin_ui_util_unittest.cc
@@ -5,11 +5,9 @@
 #include "chrome/browser/signin/signin_ui_util.h"
 
 #include "base/bind.h"
-#include "base/feature_list.h"
 #include "base/memory/raw_ptr.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/metrics/user_action_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "build/build_config.h"
 #include "build/buildflag.h"
@@ -18,7 +16,6 @@
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/signin/signin_util.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -42,6 +39,13 @@
 
 namespace signin_ui_util {
 
+namespace {
+const char kMainEmail[] = "main_email@example.com";
+const char kMainGaiaID[] = "main_gaia_id";
+const char kSecondaryEmail[] = "secondary_email@example.com";
+const char kSecondaryGaiaID[] = "secondary_gaia_id";
+}  // namespace
+
 class GetAllowedDomainTest : public ::testing::Test {};
 
 TEST_F(GetAllowedDomainTest, WithInvalidPattern) {
@@ -67,15 +71,12 @@
   EXPECT_EQ("example-1.com", GetAllowedDomain("email@example-1.com"));
 }
 
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+// TODO(https://crbug.com/1198523: Remove Lacros check once Dice is no longer
+// supported on Lacros.
+#if BUILDFLAG(ENABLE_DICE_SUPPORT) && !BUILDFLAG(IS_CHROMEOS_LACROS)
 
 namespace {
 
-const char kMainEmail[] = "main_email@example.com";
-const char kMainGaiaID[] = "main_gaia_id";
-const char kSecondaryEmail[] = "secondary_email@example.com";
-const char kSecondaryGaiaID[] = "secondary_gaia_id";
-
 class SigninUiUtilTestBrowserWindow : public TestBrowserWindow {
  public:
   SigninUiUtilTestBrowserWindow() = default;
@@ -105,11 +106,7 @@
 
 class DiceSigninUiUtilTest : public BrowserWithTestWindowTest {
  public:
-  DiceSigninUiUtilTest() {
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-    scoped_feature_list_.InitAndDisableFeature(kMultiProfileAccountConsistency);
-#endif
-  }
+  DiceSigninUiUtilTest() = default;
   ~DiceSigninUiUtilTest() override = default;
 
   struct CreateDiceTurnSyncOnHelperParams {
@@ -154,11 +151,6 @@
     BrowserWithTestWindowTest::SetUp();
     static_cast<SigninUiUtilTestBrowserWindow*>(browser()->window())
         ->set_browser(browser());
-
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-    if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-      GTEST_SKIP();
-#endif
   }
 
   // BrowserWithTestWindowTest:
@@ -266,9 +258,6 @@
 
   bool create_dice_turn_sync_on_helper_called_ = false;
   CreateDiceTurnSyncOnHelperParams create_dice_turn_sync_on_helper_params_;
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  base::test::ScopedFeatureList scoped_feature_list_;
-#endif
 };
 
 TEST_F(DiceSigninUiUtilTest, EnableSyncWithExistingAccount) {
@@ -629,8 +618,7 @@
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
 class MirrorSigninUiUtilTest : public BrowserWithTestWindowTest {
  public:
-  MirrorSigninUiUtilTest()
-      : scoped_feature_list_(kMultiProfileAccountConsistency) {}
+  MirrorSigninUiUtilTest() = default;
   ~MirrorSigninUiUtilTest() override = default;
 
   // BrowserWithTestWindowTest:
@@ -638,9 +626,6 @@
     return IdentityTestEnvironmentProfileAdaptor::
         GetIdentityTestEnvironmentFactories();
   }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 TEST_F(MirrorSigninUiUtilTest, ShowReauthDialog) {
diff --git a/chrome/browser/sync/test/integration/single_client_offer_sync_test.cc b/chrome/browser/sync/test/integration/single_client_offer_sync_test.cc
index fe9385d..64b60cf8 100644
--- a/chrome/browser/sync/test/integration/single_client_offer_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_offer_sync_test.cc
@@ -5,7 +5,6 @@
 #include "base/feature_list.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/sync/test/integration/autofill_helper.h"
 #include "chrome/browser/sync/test/integration/offer_helper.h"
 #include "chrome/browser/sync/test/integration/sync_service_impl_harness.h"
@@ -152,16 +151,16 @@
 
 // ChromeOS does not sign out, so the test below does not apply.
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
-// Offer data should get cleared from the database when the user signs out.
-IN_PROC_BROWSER_TEST_F(SingleClientOfferSyncTest, ClearOnSignOut) {
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  // On Lacros, signout is not supported with Mirror account consistency.
-  // TODO(https://crbug.com/1260291): Enable this test once signout is
-  // supported.
-  if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-    GTEST_SKIP();
-#endif
 
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+// On Lacros, signout is not supported with Mirror account consistency.
+// TODO(https://crbug.com/1260291): Enable this test once signout is supported.
+#define MAYBE_ClearOnSignOut DISABLED_ClearOnSignOut
+#else
+#define MAYBE_ClearOnSignOut ClearOnSignOut
+#endif
+// Offer data should get cleared from the database when the user signs out.
+IN_PROC_BROWSER_TEST_F(SingleClientOfferSyncTest, MAYBE_ClearOnSignOut) {
   GetFakeServer()->SetOfferData({CreateDefaultSyncCardLinkedOffer()});
   ASSERT_TRUE(SetupSync());
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
diff --git a/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc b/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc
index af8438a..58a5ee02 100644
--- a/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc
@@ -6,7 +6,6 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/sync/test/integration/encryption_helper.h"
 #include "chrome/browser/sync/test/integration/passwords_helper.h"
 #include "chrome/browser/sync/test/integration/secondary_account_helper.h"
@@ -360,17 +359,18 @@
 
 // ChromeOS does not support signing out of a primary account.
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
-// Sanity check: The profile database should *not* get cleared on signout.
-IN_PROC_BROWSER_TEST_F(SingleClientPasswordsWithAccountStorageSyncTest,
-                       DoesNotClearProfileDBOnSignout) {
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  // On Lacros, signout is not supported with Mirror account consistency.
-  // TODO(https://crbug.com/1260291): Enable this test once signout is
-  // supported.
-  if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-    GTEST_SKIP();
-#endif
 
+// Sanity check: The profile database should *not* get cleared on signout.
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+// On Lacros, signout is not supported with Mirror account consistency.
+// TODO(https://crbug.com/1260291): Enable this test once signout is supported.
+#define MAYBE_DoesNotClearProfileDBOnSignout \
+  DISABLED_DoesNotClearProfileDBOnSignout
+#else
+#define MAYBE_DoesNotClearProfileDBOnSignout DoesNotClearProfileDBOnSignout
+#endif
+IN_PROC_BROWSER_TEST_F(SingleClientPasswordsWithAccountStorageSyncTest,
+                       MAYBE_DoesNotClearProfileDBOnSignout) {
   AddTestPasswordToFakeServer();
 
   // Sign in and enable Sync.
@@ -523,14 +523,10 @@
   EXPECT_EQ(passwords_helper::GetAllLogins(profile_store).size(), 1u);
   EXPECT_EQ(passwords_helper::GetAllLogins(account_store).size(), 0u);
 
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  // On Lacros, signout is not supported with Mirror account consistency.
-  // TODO(https://crbug.com/1260291): Enable this test once signout is
-  // supported.
-  if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-    return;
-#endif
-
+// On Lacros, signout is not supported with Mirror account consistency.
+// TODO(https://crbug.com/1260291): Enable this part of the test once signout is
+// supported.
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
   // Clear the primary account to put Sync into transport mode again.
   // Note: Clearing the primary account without also signing out isn't exposed
   // to the user, so this shouldn't happen. Still best to cover it here.
@@ -548,6 +544,7 @@
   // cleared when Sync gets disabled.
   EXPECT_EQ(passwords_helper::GetAllLogins(profile_store).size(), 1u);
   EXPECT_EQ(passwords_helper::GetAllLogins(account_store).size(), 1u);
+#endif
 }
 
 // Regression test for crbug.com/1076378.
diff --git a/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc b/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc
index b4f0f98a..d7a7e563 100644
--- a/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc
@@ -6,7 +6,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
 #include "build/chromeos_buildflags.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/sync/device_info_sync_service_factory.h"
 #include "chrome/browser/sync/sync_invalidations_service_factory.h"
 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
@@ -496,17 +495,17 @@
 
 // ChromeOS doesn't have the concept of sign-out.
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
+
+// On Lacros, signout is not supported with Mirror account consistency.
+// TODO(https://crbug.com/1260291): Enable this test once signout is supported.
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#define MAYBE_SignoutAndSignin DISABLED_SignoutAndSignin
+#else
+#define MAYBE_SignoutAndSignin SignoutAndSignin
+#endif
 IN_PROC_BROWSER_TEST_F(
     SingleClientWithUseSyncInvalidationsForWalletAndOfferTest,
-    SignoutAndSignin) {
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  // On Lacros, signout is not supported with Mirror account consistency.
-  // TODO(https://crbug.com/1260291): Enable this test once signout is
-  // supported.
-  if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-    GTEST_SKIP();
-#endif
-
+    MAYBE_SignoutAndSignin) {
   ASSERT_TRUE(SetupSync());
 
   // The local device should eventually be committed to the server. The FCM
@@ -545,7 +544,7 @@
                                                 HasInstanceIdToken(new_token)))
           .Wait());
 }
-#endif  // !OS_CHROMEOS
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 class SingleClientSyncInvalidationsTestWithPreDisabledSendInterestedDataTypes
     : public SyncTest {
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index de56822..4994f4d 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -9,7 +9,6 @@
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/sync/test/integration/autofill_helper.h"
 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
 #include "chrome/browser/sync/test/integration/secondary_account_helper.h"
@@ -351,14 +350,10 @@
 
   ExpectDefaultCreditCardValues(*cards[0]);
 
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  // On Lacros, signout is not supported with Mirror account consistency.
-  // TODO(https://crbug.com/1260291): Enable this test once signout is
-  // supported.
-  if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-    return;
-#endif
-
+// On Lacros, signout is not supported with Mirror account consistency.
+// TODO(https://crbug.com/1260291): Enable this part of the test once signout is
+// supported.
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
   // Now sign back out.
   GetClient(0)->SignOutPrimaryAccount();
 
@@ -373,21 +368,23 @@
 
   // Check directly in the DB that the account storage is now cleared.
   EXPECT_EQ(0U, GetServerCards(account_data).size());
+#endif
 }
 
 // Wallet data should get cleared from the database when the user signs out and
 // different data should get downstreamed when the user signs in with a
 // different account.
-IN_PROC_BROWSER_TEST_F(SingleClientWalletWithAccountStorageSyncTest,
-                       ClearOnSignOutAndDownstreamOnSignIn) {
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-  // On Lacros, signout is not supported with Mirror account consistency.
-  // TODO(https://crbug.com/1260291): Enable this test once signout is
-  // supported.
-  if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-    GTEST_SKIP();
+// On Lacros, signout is not supported with Mirror account consistency.
+// TODO(https://crbug.com/1260291): Enable this test once signout is supported.
+#define MAYBE_ClearOnSignOutAndDownstreamOnSignIn \
+  DISABLED_ClearOnSignOutAndDownstreamOnSignIn
+#else
+#define MAYBE_ClearOnSignOutAndDownstreamOnSignIn \
+  ClearOnSignOutAndDownstreamOnSignIn
 #endif
-
+IN_PROC_BROWSER_TEST_F(SingleClientWalletWithAccountStorageSyncTest,
+                       MAYBE_ClearOnSignOutAndDownstreamOnSignIn) {
   ASSERT_TRUE(SetupClients());
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   ASSERT_NE(nullptr, pdm);
@@ -548,16 +545,16 @@
 
 // ChromeOS does not sign out, so the test below does not apply.
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
-// Wallet data should get cleared from the database when the user signs out.
-IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, ClearOnSignOut) {
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  // On Lacros, signout is not supported with Mirror account consistency.
-  // TODO(https://crbug.com/1260291): Enable this test once signout is
-  // supported.
-  if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency))
-    GTEST_SKIP();
-#endif
 
+// Wallet data should get cleared from the database when the user signs out.
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+// On Lacros, signout is not supported with Mirror account consistency.
+// TODO(https://crbug.com/1260291): Enable this test once signout is supported.
+#define MAYBE_ClearOnSignOut DISABLED_ClearOnSignOut
+#else
+#define MAYBE_ClearOnSignOut ClearOnSignOut
+#endif
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, MAYBE_ClearOnSignOut) {
   GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress(),
                                   CreateDefaultSyncWalletCard(),
                                   CreateDefaultSyncPaymentsCustomerData(),
diff --git a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc
index adbdc82f..9e1ac38 100644
--- a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc
+++ b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "build/build_config.h"
 #include "chrome/browser/sync/test/integration/two_client_web_apps_integration_test_base.h"
 #include "content/public/test/browser_test.h"
 
@@ -801,9 +802,17 @@
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
 }
 
+// TODO(crbug.com/1273666): Test failed on Mac ASAN.
+#if defined(OS_MAC) && defined(ADDRESS_SANITIZER)
+#define MAYBE_WebAppIntegration_InstCrtShctTabbedSiteA_InListTabbedSiteA_SwitchProfileClientClient2_InListNotLclyInstSiteA_TurnSyncOff_UninstallFromMenuSiteA_TurnSyncOn_InListNotLclyInstSiteA \
+  DISABLED_WebAppIntegration_InstCrtShctTabbedSiteA_InListTabbedSiteA_SwitchProfileClientClient2_InListNotLclyInstSiteA_TurnSyncOff_UninstallFromMenuSiteA_TurnSyncOn_InListNotLclyInstSiteA
+#else
+#define MAYBE_WebAppIntegration_InstCrtShctTabbedSiteA_InListTabbedSiteA_SwitchProfileClientClient2_InListNotLclyInstSiteA_TurnSyncOff_UninstallFromMenuSiteA_TurnSyncOn_InListNotLclyInstSiteA \
+  WebAppIntegration_InstCrtShctTabbedSiteA_InListTabbedSiteA_SwitchProfileClientClient2_InListNotLclyInstSiteA_TurnSyncOff_UninstallFromMenuSiteA_TurnSyncOn_InListNotLclyInstSiteA
+#endif
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestMacWinLinux,
-    WebAppIntegration_InstCrtShctTabbedSiteA_InListTabbedSiteA_SwitchProfileClientClient2_InListNotLclyInstSiteA_TurnSyncOff_UninstallFromMenuSiteA_TurnSyncOn_InListNotLclyInstSiteA) {
+    MAYBE_WebAppIntegration_InstCrtShctTabbedSiteA_InListTabbedSiteA_SwitchProfileClientClient2_InListNotLclyInstSiteA_TurnSyncOff_UninstallFromMenuSiteA_TurnSyncOn_InListNotLclyInstSiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
diff --git a/chrome/browser/sync_file_system/sync_file_system_service.cc b/chrome/browser/sync_file_system/sync_file_system_service.cc
index 37975ab..5011258e 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service.cc
+++ b/chrome/browser/sync_file_system/sync_file_system_service.cc
@@ -310,12 +310,12 @@
                      AsWeakPtr(), std::move(callback)));
 }
 
-void SyncFileSystemService::DumpFiles(const GURL& origin,
-                                      DumpFilesCallback callback) {
+void SyncFileSystemService::DumpFiles(
+    content::StoragePartition* storage_partition,
+    const GURL& origin,
+    DumpFilesCallback callback) {
   DCHECK(!origin.is_empty());
 
-  content::StoragePartition* storage_partition =
-      profile_->GetStoragePartitionForUrl(origin);
   storage::FileSystemContext* file_system_context =
       storage_partition->GetFileSystemContext();
   local_service_->MaybeInitializeFileSystemContext(
diff --git a/chrome/browser/sync_file_system/sync_file_system_service.h b/chrome/browser/sync_file_system/sync_file_system_service.h
index 9375cdd7..e798056 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service.h
+++ b/chrome/browser/sync_file_system/sync_file_system_service.h
@@ -28,6 +28,10 @@
 
 class Profile;
 
+namespace content {
+class StoragePartition;
+}
+
 namespace storage {
 class FileSystemContext;
 }
@@ -66,7 +70,9 @@
                         SyncStatusCallback callback);
 
   void GetExtensionStatusMap(ExtensionStatusMapCallback callback);
-  void DumpFiles(const GURL& origin, DumpFilesCallback callback);
+  void DumpFiles(content::StoragePartition* storage_partition,
+                 const GURL& origin,
+                 DumpFilesCallback callback);
   void DumpDatabase(DumpFilesCallback callback);
 
   // Returns the file |url|'s sync status.
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/NavigationPopup.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/NavigationPopup.java
index 19ddf914..90754ea 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/NavigationPopup.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/NavigationPopup.java
@@ -128,7 +128,8 @@
         if (!shouldUseIncognitoResources()) {
             mHistory.addEntry(new NavigationEntry(FULL_HISTORY_ENTRY_INDEX,
                     new GURL(UrlConstants.HISTORY_URL), GURL.emptyGURL(), GURL.emptyGURL(),
-                    GURL.emptyGURL(), resources.getString(R.string.show_full_history), null, 0, 0));
+                    GURL.emptyGURL(), resources.getString(R.string.show_full_history), null, 0, 0,
+                    /*isInitialEntry=*/false));
         }
 
         mAdapter = new NavigationAdapter();
diff --git a/chrome/browser/ui/ash/shelf/browser_status_monitor.cc b/chrome/browser/ui/ash/shelf/browser_status_monitor.cc
index fa9c319..6d295d4 100644
--- a/chrome/browser/ui/ash/shelf/browser_status_monitor.cc
+++ b/chrome/browser/ui/ash/shelf/browser_status_monitor.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/web_applications/web_app_utils.h"
 #include "chrome/common/chrome_features.h"
 #include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -402,11 +403,12 @@
                                          content::WebContents* contents) {
   if (!web_app::IsWebAppsCrosapiEnabled()) {
     UpdateAppItemState(contents, false /*remove*/);
-    // If the contents does not have a visible navigation entry, wait until a
-    // navigation status changes before setting the browser window Shelf ID
-    // (done by the web contents observer added by AddWebContentsObserver()).
+    // If the contents does not have a visible navigation entry that is not the
+    // initial entry, wait until a navigation status changes before setting the
+    // browser window Shelf ID (done by the web contents observer added by
+    // AddWebContentsObserver()).
     if (tab_strip_model->GetActiveWebContents() == contents &&
-        contents->GetController().GetVisibleEntry()) {
+        !contents->GetController().GetVisibleEntry()->IsInitialEntry()) {
       Browser* browser = chrome::FindBrowserWithWebContents(contents);
       SetShelfIDForBrowserWindowContents(browser, contents);
     }
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc
index 8d2b2eb..a350201 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc
@@ -93,6 +93,7 @@
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/browser/web_applications/web_app_shortcut_manager.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
+#include "chrome/browser/web_applications/web_app_utils.h"
 #include "chrome/browser/web_applications/web_application_info.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
@@ -644,15 +645,19 @@
 };
 
 IN_PROC_BROWSER_TEST_F(UnpinnedBrowserShortcutTest, UnpinnedBrowserShortcut) {
+  DCHECK(web_app::IsWebAppsCrosapiEnabled());
+
   EXPECT_EQ(-1, shelf_model()->GetItemIndexForType(ash::TYPE_BROWSER_SHORTCUT));
   EXPECT_EQ(-1, shelf_model()->GetItemIndexForType(
                     ash::TYPE_UNPINNED_BROWSER_SHORTCUT));
+  EXPECT_EQ(-1, shelf_model()->GetItemIndexForType(ash::TYPE_APP));
 
   CreateBrowser(profile());
 
   EXPECT_EQ(-1, shelf_model()->GetItemIndexForType(ash::TYPE_BROWSER_SHORTCUT));
-  EXPECT_NE(-1, shelf_model()->GetItemIndexForType(
+  EXPECT_EQ(-1, shelf_model()->GetItemIndexForType(
                     ash::TYPE_UNPINNED_BROWSER_SHORTCUT));
+  EXPECT_NE(-1, shelf_model()->GetItemIndexForType(ash::TYPE_APP));
 }
 
 // Test that we can launch a platform app with more than one window.
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
index 8540edf..cc8cbc96 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
@@ -597,6 +597,7 @@
   ChromeShelfController* CreateShelfController() {
     shelf_item_factory_ =
         std::make_unique<FakeChromeShelfItemFactory>(profile());
+    model_->SetShelfItemFactory(shelf_item_factory_.get());
     shelf_controller_ = std::make_unique<ChromeShelfController>(
         profile(), model_.get(), shelf_item_factory_.get());
     shelf_controller_->SetProfileForTest(profile());
diff --git a/chrome/browser/ui/ash/shelf/shelf_context_menu_unittest.cc b/chrome/browser/ui/ash/shelf/shelf_context_menu_unittest.cc
index 20bbb62..2cfbf3ca1 100644
--- a/chrome/browser/ui/ash/shelf/shelf_context_menu_unittest.cc
+++ b/chrome/browser/ui/ash/shelf/shelf_context_menu_unittest.cc
@@ -132,6 +132,7 @@
     session_manager_ = std::make_unique<session_manager::SessionManager>();
     model_ = std::make_unique<ash::ShelfModel>();
     shelf_item_factory_ = std::make_unique<ChromeShelfItemFactory>();
+    model_->SetShelfItemFactory(shelf_item_factory_.get());
     shelf_controller_ = std::make_unique<ChromeShelfController>(
         profile(), model_.get(), shelf_item_factory_.get());
     shelf_controller_->SetProfileForTest(profile());
diff --git a/chrome/browser/ui/ash/system_tray_client_impl.cc b/chrome/browser/ui/ash/system_tray_client_impl.cc
index bd4d5e6..a45a0e0 100644
--- a/chrome/browser/ui/ash/system_tray_client_impl.cc
+++ b/chrome/browser/ui/ash/system_tray_client_impl.cc
@@ -228,6 +228,10 @@
   DCHECK_EQ(this, g_system_tray_client_instance);
   g_system_tray_client_instance = nullptr;
 
+  // This can happen when mocking this class in tests.
+  if (!system_tray_)
+    return;
+
   system_tray_->SetClient(nullptr);
 
   policy::BrowserPolicyConnectorAsh* connector =
@@ -571,6 +575,12 @@
   chrome::AttemptUserExit();
 }
 
+SystemTrayClientImpl::SystemTrayClientImpl(SystemTrayClientImpl* mock_instance)
+    : system_tray_(nullptr) {
+  DCHECK(!g_system_tray_client_instance);
+  g_system_tray_client_instance = mock_instance;
+}
+
 void SystemTrayClientImpl::HandleUpdateAvailable(ash::UpdateType update_type) {
   UpgradeDetector* detector = UpgradeDetector::GetInstance();
   if (detector->upgrade_notification_stage() ==
diff --git a/chrome/browser/ui/ash/system_tray_client_impl.h b/chrome/browser/ui/ash/system_tray_client_impl.h
index 7ac4f769..51b615ff 100644
--- a/chrome/browser/ui/ash/system_tray_client_impl.h
+++ b/chrome/browser/ui/ash/system_tray_client_impl.h
@@ -42,7 +42,7 @@
   // Specifies if notification is recommended or required by administrator and
   // triggers the notification to be shown with the given body and title.
   // Only applies to OS updates.
-  void SetRelaunchNotificationState(
+  virtual void SetRelaunchNotificationState(
       const ash::RelaunchNotificationState& relaunch_notification_state);
 
   // Resets update state to hide notification.
@@ -94,6 +94,10 @@
   void RequestRestartForUpdate() override;
   void SetLocaleAndExit(const std::string& locale_iso_code) override;
 
+ protected:
+  // Used by mocks in tests.
+  explicit SystemTrayClientImpl(SystemTrayClientImpl* mock_instance);
+
  private:
   // Observes profile changed and profile's policy changed.
   class EnterpriseAccountObserver;
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 704df7b..5cbc53e 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -961,7 +961,7 @@
 
 bool CanDuplicateTabAt(const Browser* browser, int index) {
   WebContents* contents = browser->tab_strip_model()->GetWebContentsAt(index);
-  return contents && contents->GetController().GetLastCommittedEntry();
+  return contents;
 }
 
 void MoveTabsToExistingWindow(Browser* source,
diff --git a/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc b/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc
index d77ee495..05360034 100644
--- a/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc
+++ b/chrome/browser/ui/global_media_controls/presentation_request_notification_item_unittest.cc
@@ -39,7 +39,7 @@
   testing::NiceMock<media_message_center::test::MockMediaNotificationView> view;
 
   const std::u16string title = u"This is the page title";
-  web_contents()->UpdateTitleForEntry(controller().GetPendingEntry(), title);
+  web_contents()->UpdateTitleForEntry(controller().GetVisibleEntry(), title);
   media_session::MediaMetadata data;
   data.source_title = u"google2.com";
   data.artist = title;
diff --git a/chrome/browser/ui/login/login_handler_browsertest.cc b/chrome/browser/ui/login/login_handler_browsertest.cc
index f249b68..301c9b14 100644
--- a/chrome/browser/ui/login/login_handler_browsertest.cc
+++ b/chrome/browser/ui/login/login_handler_browsertest.cc
@@ -35,6 +35,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/security_interstitials/content/security_interstitial_tab_helper.h"
 #include "components/security_interstitials/content/ssl_blocking_page.h"
+#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/storage_partition.h"
@@ -1961,7 +1962,7 @@
 // Tests that when HTTP Auth committed interstitials are enabled, showing a
 // login prompt in a new window opened from window.open() does not
 // crash. Regression test for https://crbug.com/1005096.
-IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, PromptWithNoVisibleEntry) {
+IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, PromptWithOnlyInitialEntry) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
   content::WebContents* contents =
@@ -1976,7 +1977,7 @@
   content::WebContents* opened_contents =
       browser()->tab_strip_model()->GetWebContentsAt(1);
   NavigationController* opened_controller = &opened_contents->GetController();
-  ASSERT_FALSE(opened_controller->GetVisibleEntry());
+  ASSERT_TRUE(opened_controller->GetVisibleEntry()->IsInitialEntry());
   LoginPromptBrowserTestObserver observer;
   observer.Register(content::Source<NavigationController>(opened_controller));
   WindowedAuthNeededObserver auth_needed_waiter(opened_controller);
diff --git a/chrome/browser/ui/page_info/page_info_dialog.cc b/chrome/browser/ui/page_info/page_info_dialog.cc
index cebbcc10..d5dacfb 100644
--- a/chrome/browser/ui/page_info/page_info_dialog.cc
+++ b/chrome/browser/ui/page_info/page_info_dialog.cc
@@ -23,7 +23,7 @@
 
   content::NavigationEntry* entry =
       web_contents->GetController().GetVisibleEntry();
-  if (!entry)
+  if (entry->IsInitialEntry())
     return false;
 
   auto initialized_callback =
diff --git a/chrome/browser/ui/side_search/side_search_side_contents_helper_unittest.cc b/chrome/browser/ui/side_search/side_search_side_contents_helper_unittest.cc
index 59e96e33..6eba41f 100644
--- a/chrome/browser/ui/side_search/side_search_side_contents_helper_unittest.cc
+++ b/chrome/browser/ui/side_search/side_search_side_contents_helper_unittest.cc
@@ -128,7 +128,7 @@
 TEST_F(SideSearchSideContentsHelperTest,
        NonGoogleSearchURLNavigatesTabContents) {
   LoadURL(kNonGoogleURL);
-  EXPECT_EQ(nullptr, GetLastCommittedSideContentsEntry());
+  EXPECT_TRUE(GetLastCommittedSideContentsEntry()->IsInitialEntry());
   EXPECT_TRUE(delegate().last_search_url().is_empty());
   EXPECT_EQ(GURL(kNonGoogleURL), delegate().tab_contents_url());
   histogram_tester_.ExpectUniqueSample(
@@ -138,7 +138,7 @@
 TEST_F(SideSearchSideContentsHelperTest,
        GoogleHomePageURLNavigatesTabContents) {
   LoadURL(kGoogleSearchHomePageURL);
-  EXPECT_EQ(nullptr, GetLastCommittedSideContentsEntry());
+  EXPECT_TRUE(GetLastCommittedSideContentsEntry()->IsInitialEntry());
   EXPECT_TRUE(delegate().last_search_url().is_empty());
   EXPECT_EQ(GURL(kGoogleSearchHomePageURL), delegate().tab_contents_url());
   histogram_tester_.ExpectUniqueSample(
diff --git a/chrome/browser/ui/side_search/side_search_tab_contents_helper_unittest.cc b/chrome/browser/ui/side_search/side_search_tab_contents_helper_unittest.cc
index a861c46..ef457d9 100644
--- a/chrome/browser/ui/side_search/side_search_tab_contents_helper_unittest.cc
+++ b/chrome/browser/ui/side_search/side_search_tab_contents_helper_unittest.cc
@@ -111,7 +111,7 @@
 TEST_F(SideSearchTabContentsHelperTest, LastSearchURLUpdatesCorrectly) {
   // When a tab is first opened there should be no last encountered Google SRP.
   EXPECT_FALSE(helper()->last_search_url().has_value());
-  EXPECT_EQ(nullptr, GetLastCommittedSideContentsEntry());
+  EXPECT_TRUE(GetLastCommittedSideContentsEntry()->IsInitialEntry());
 
   // Navigating to a Google SRP should update the `last_search_url`.
   LoadURL(kGoogleSearchURL1);
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index c262ec79..4b44327 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -3152,10 +3152,9 @@
   std::string new_tab_url1 =
       tab_strip1->GetWebContentsAt(0)->GetURL().possibly_invalid_spec();
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-  // On Lacros Welcome page appears in the new (non-main) profile only if
-  // account consistency is not enabled.
-  should_show_welcome =
-      !base::FeatureList::IsEnabled(kMultiProfileAccountConsistency);
+  // Welcome page should not be shown on Lacros.
+  // (about:blank or new tab page will be shown instead)
+  should_show_welcome = false;
 #endif
   if (should_show_welcome)
     EXPECT_EQ(chrome::kChromeUIWelcomeURL, new_tab_url1);
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 5f8bb822..e26c1c7 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -34,6 +34,7 @@
 #include "chrome/browser/sessions/app_session_service_factory.h"
 #include "chrome/browser/sessions/session_service.h"
 #include "chrome/browser/sessions/session_service_factory.h"
+#include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -92,7 +93,6 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-#include "chrome/browser/lacros/account_manager/account_manager_util.h"
 #include "chromeos/lacros/lacros_service.h"
 #endif
 
@@ -377,7 +377,7 @@
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-  if (IsAccountManagerAvailable(profile_))
+  if (AccountConsistencyModeManager::IsMirrorEnabledForProfile(profile_))
     welcome_enabled = false;
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
diff --git a/chrome/browser/ui/task_manager/task_manager_table_model.cc b/chrome/browser/ui/task_manager/task_manager_table_model.cc
index 5a5fe7d..b8a8055 100644
--- a/chrome/browser/ui/task_manager/task_manager_table_model.cc
+++ b/chrome/browser/ui/task_manager/task_manager_table_model.cc
@@ -826,9 +826,9 @@
   // Do a best effort of retrieving the correct settings from the local state.
   // Use the default settings of the value if it fails to be retrieved.
   std::string sorted_col_id;
-  bool sort_is_ascending = true;
   dictionary->GetString(kSortColumnIdKey, &sorted_col_id);
-  dictionary->GetBoolean(kSortIsAscendingKey, &sort_is_ascending);
+  bool sort_is_ascending =
+      dictionary->FindBoolPath(kSortIsAscendingKey).value_or(true);
 
   int current_visible_column_index = 0;
   for (size_t i = 0; i < kColumnsSize; ++i) {
@@ -838,10 +838,10 @@
     if (col_id_key.empty())
       continue;
 
-    bool col_visibility = kColumns[i].default_visibility;
-    dictionary->GetBoolean(col_id_key, &col_visibility);
+    bool col_visibility = dictionary->FindBoolPath(col_id_key)
+                              .value_or(kColumns[i].default_visibility);
 
-    // If the above GetBoolean() fails, the |col_visibility| remains at the
+    // If the above FindBoolPath() fails, the |col_visibility| remains at the
     // default visibility.
     columns_settings_->SetBoolean(col_id_key, col_visibility);
     table_view_delegate_->SetColumnVisibility(col_id, col_visibility);
diff --git a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc
index 66256a4..8732b4f 100644
--- a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc
+++ b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc
@@ -74,7 +74,7 @@
 bool ChromeLocationBarModelDelegate::GetURL(GURL* url) const {
   DCHECK(url);
   content::NavigationEntry* entry = GetNavigationEntry();
-  if (!entry)
+  if (!entry || entry->IsInitialEntry())
     return false;
 
   *url = entry->GetVirtualURL();
@@ -98,7 +98,7 @@
   //   of view-source:chrome://newtab, which should display its URL despite what
   //   chrome://newtab says.
   content::NavigationEntry* entry = GetNavigationEntry();
-  if (!entry)
+  if (!entry || entry->IsInitialEntry())
     return true;
 
   security_interstitials::SecurityInterstitialTabHelper*
@@ -181,7 +181,7 @@
 scoped_refptr<net::X509Certificate>
 ChromeLocationBarModelDelegate::GetCertificate() const {
   content::NavigationEntry* entry = GetNavigationEntry();
-  if (!entry)
+  if (!entry || entry->IsInitialEntry())
     return scoped_refptr<net::X509Certificate>();
   return entry->GetSSL().certificate;
 }
@@ -215,7 +215,7 @@
 
 bool ChromeLocationBarModelDelegate::IsNewTabPage() const {
   content::NavigationEntry* const entry = GetNavigationEntry();
-  if (!entry)
+  if (!entry || entry->IsInitialEntry())
     return false;
 
   Profile* const profile = GetProfile();
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_unittest.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_unittest.cc
index fecac44..3afd670 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_unittest.cc
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_unittest.cc
@@ -98,6 +98,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     shelf_model_ = std::make_unique<ash::ShelfModel>();
     chrome_shelf_item_factory_ = std::make_unique<ChromeShelfItemFactory>();
+    shelf_model_->SetShelfItemFactory(chrome_shelf_item_factory_.get());
     chrome_shelf_controller_ = std::make_unique<ChromeShelfController>(
         extension_environment_.profile(), shelf_model_.get(),
         chrome_shelf_item_factory_.get());
diff --git a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
index cbbef85..00b0ff65 100644
--- a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
@@ -368,7 +368,7 @@
 
   content::NavigationEntry* entry = contents->GetController().GetVisibleEntry();
   std::u16string title, location;
-  if (entry) {
+  if (!entry->IsInitialEntry()) {
     title = Browser::FormatTitleForDisplay(entry->GetTitleForDisplay());
     if (ShouldDisplayUrl(contents)) {
       location = web_app::AppBrowserController::FormatUrlOrigin(
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 402299a..7f6d34a 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -1409,7 +1409,7 @@
     return false;
 
   content::NavigationEntry* entry = contents->GetController().GetVisibleEntry();
-  if (!entry)
+  if (entry->IsInitialEntry())
     return false;
 
   DCHECK(GetWidget());
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.cc b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.cc
index 43c95f8..86b88a21 100644
--- a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.cc
+++ b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.cc
@@ -11,6 +11,7 @@
 #include "base/check_op.h"
 #include "base/time/default_clock.h"
 #include "base/time/default_tick_clock.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/common/pref_names.h"
@@ -348,6 +349,9 @@
     base::Time relaunch_deadline,
     base::OnceCallback<base::Time()> on_visible) {
   platform_impl_.NotifyRelaunchRequired(relaunch_deadline,
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+                                        notification_type_required_overridden_,
+#endif
                                         std::move(on_visible));
 }
 
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.cc b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.cc
index 6e0402e..2bf3313 100644
--- a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.cc
+++ b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.cc
@@ -32,16 +32,17 @@
 
 void RelaunchNotificationControllerPlatformImpl::NotifyRelaunchRequired(
     base::Time deadline,
+    bool is_notification_type_overriden,
     base::OnceCallback<base::Time()> on_visible) {
   if (!relaunch_required_timer_) {
     relaunch_required_timer_ = std::make_unique<RelaunchRequiredTimer>(
-        deadline,
-        base::BindRepeating(&RelaunchNotificationControllerPlatformImpl::
-                                RefreshRelaunchRequiredTitle,
-                            base::Unretained(this)));
+        deadline, base::BindRepeating(
+                      &RelaunchNotificationControllerPlatformImpl::
+                          RefreshRelaunchRequiredTitle,
+                      base::Unretained(this), is_notification_type_overriden));
   }
 
-  RefreshRelaunchRequiredTitle();
+  RefreshRelaunchRequiredTitle(is_notification_type_overriden);
 
   if (!CanScheduleReboot()) {
     on_visible_ = std::move(on_visible);
@@ -82,12 +83,17 @@
   return relaunch_required_timer_ != nullptr;
 }
 
-void RelaunchNotificationControllerPlatformImpl::
-    RefreshRelaunchRequiredTitle() {
+void RelaunchNotificationControllerPlatformImpl::RefreshRelaunchRequiredTitle(
+    bool is_notification_type_overriden) {
   // SystemTrayClientImpl may not exist in unit tests.
   if (SystemTrayClientImpl::Get()) {
     SystemTrayClientImpl::Get()->SetRelaunchNotificationState(
         {.requirement_type = ash::RelaunchNotificationState::kRequired,
+         // We only override notification type to kRequired in the
+         // MinimumVersionPolicyHandler that handles device policies.
+         .policy_source = is_notification_type_overriden
+                              ? ash::RelaunchNotificationState::kDevice
+                              : ash::RelaunchNotificationState::kUser,
          .rounded_time_until_reboot_required =
              relaunch_required_timer_->GetRoundedDeadlineDelta()});
   }
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.h b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.h
index 7caae60..3310a43 100644
--- a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.h
+++ b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.h
@@ -34,6 +34,7 @@
 
   // Shows the relaunch required notification if it is not already open.
   void NotifyRelaunchRequired(base::Time deadline,
+                              bool is_notification_type_overriden,
                               base::OnceCallback<base::Time()> on_visible);
 
   // Sets the notification title to the default one on Chrome OS.
@@ -59,7 +60,7 @@
 
   // Callback triggered whenever the required notification's title has to
   // refresh.
-  void RefreshRelaunchRequiredTitle();
+  void RefreshRelaunchRequiredTitle(bool is_notification_type_overriden);
 
   // Returns true if the display is on && the session is active
   bool CanScheduleReboot();
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc
index a37f0fb..100bcf6 100644
--- a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc
+++ b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/public/cpp/update_types.h"
 #include "base/callback_helpers.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
@@ -19,6 +20,7 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "build/chromeos_buildflags.h"
+#include "chrome/browser/ui/ash/system_tray_client_impl.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
@@ -984,7 +986,9 @@
 
   // Expect the platform_impl to query for the deadline synchronously.
   ::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
-  platform_impl().NotifyRelaunchRequired(GetMockClock()->Now(), callback.Get());
+  platform_impl().NotifyRelaunchRequired(
+      GetMockClock()->Now(), /*is_notification_type_overriden=*/false,
+      callback.Get());
   ::testing::Mock::VerifyAndClearExpectations(&callback);
 }
 
@@ -995,7 +999,9 @@
 
   ::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
 
-  platform_impl().NotifyRelaunchRequired(GetMockClock()->Now(), callback.Get());
+  platform_impl().NotifyRelaunchRequired(
+      GetMockClock()->Now(), /*is_notification_type_overriden=*/false,
+      callback.Get());
   ::testing::Mock::VerifyAndClearExpectations(&callback);
 
   EXPECT_CALL(callback, Run());
@@ -1010,7 +1016,9 @@
 
   ::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
 
-  platform_impl().NotifyRelaunchRequired(GetMockClock()->Now(), callback.Get());
+  platform_impl().NotifyRelaunchRequired(
+      GetMockClock()->Now(), /*is_notification_type_overriden=*/false,
+      callback.Get());
   ::testing::Mock::VerifyAndClearExpectations(&callback);
 
   EXPECT_CALL(callback, Run());
@@ -1025,7 +1033,9 @@
 
   ::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
 
-  platform_impl().NotifyRelaunchRequired(GetMockClock()->Now(), callback.Get());
+  platform_impl().NotifyRelaunchRequired(
+      GetMockClock()->Now(), /*is_notification_type_overriden=*/false,
+      callback.Get());
   ::testing::Mock::VerifyAndClearExpectations(&callback);
 
   EXPECT_CALL(callback, Run());
@@ -1045,7 +1055,9 @@
 
   ::testing::StrictMock<base::MockOnceCallback<base::Time()>> callback;
 
-  platform_impl().NotifyRelaunchRequired(GetMockClock()->Now(), callback.Get());
+  platform_impl().NotifyRelaunchRequired(
+      GetMockClock()->Now(), /*is_notification_type_overriden=*/false,
+      callback.Get());
   ::testing::Mock::VerifyAndClearExpectations(&callback);
 
   EXPECT_CALL(callback, Run());
@@ -1058,6 +1070,58 @@
   ::testing::Mock::VerifyAndClearExpectations(&callback);
 }
 
+class MockSystemTrayClientImpl : public SystemTrayClientImpl {
+ public:
+  MockSystemTrayClientImpl() : SystemTrayClientImpl(this) {}
+  MOCK_METHOD(void,
+              SetRelaunchNotificationState,
+              (const ash::RelaunchNotificationState&),
+              (override));
+};
+
+// Correct relaunch notification state for required notification type.
+TEST_F(RelaunchNotificationControllerPlatformImplTest,
+       RelaunchNotificationStateRequired) {
+  base::MockOnceCallback<base::Time()> callback;
+  MockSystemTrayClientImpl system_tray_client_impl;
+  ash::RelaunchNotificationState relaunch_notification_state;
+  EXPECT_CALL(system_tray_client_impl, SetRelaunchNotificationState(_))
+      .WillOnce(testing::SaveArg<0>(&relaunch_notification_state));
+
+  platform_impl().NotifyRelaunchRequired(
+      GetMockClock()->Now(), /*is_notification_type_overriden=*/false,
+      callback.Get());
+
+  EXPECT_EQ(relaunch_notification_state.requirement_type,
+            ash::RelaunchNotificationState::kRequired);
+  EXPECT_EQ(relaunch_notification_state.policy_source,
+            ash::RelaunchNotificationState::kUser);
+  EXPECT_LE(relaunch_notification_state.rounded_time_until_reboot_required,
+            base::Seconds(1));
+}
+
+// Correct relaunch notification state for required notification type with an
+// override.
+TEST_F(RelaunchNotificationControllerPlatformImplTest,
+       RelaunchNotificationStateRequiredWithOverride) {
+  base::MockOnceCallback<base::Time()> callback;
+  MockSystemTrayClientImpl system_tray_client_impl;
+  ash::RelaunchNotificationState relaunch_notification_state;
+  EXPECT_CALL(system_tray_client_impl, SetRelaunchNotificationState(_))
+      .WillOnce(testing::SaveArg<0>(&relaunch_notification_state));
+
+  platform_impl().NotifyRelaunchRequired(
+      GetMockClock()->Now(), /*is_notification_type_overriden=*/true,
+      callback.Get());
+
+  EXPECT_EQ(relaunch_notification_state.requirement_type,
+            ash::RelaunchNotificationState::kRequired);
+  EXPECT_EQ(relaunch_notification_state.policy_source,
+            ash::RelaunchNotificationState::kDevice);
+  EXPECT_LE(relaunch_notification_state.rounded_time_until_reboot_required,
+            base::Seconds(1));
+}
+
 #else  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 class RelaunchNotificationControllerPlatformImplTest
diff --git a/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.cc b/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.cc
index d62996c..7d82eec 100644
--- a/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.cc
@@ -10,6 +10,7 @@
 #include "ash/components/phonehub/pref_names.h"
 #include "ash/public/cpp/system_tray.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/ash/phonehub/phone_hub_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -383,8 +384,9 @@
 
 void MultidevicePhoneHubHandler::HandleSetFakePhoneName(
     const base::ListValue* args) {
-  std::u16string phone_name;
-  CHECK(args->GetString(0, &phone_name));
+  base::Value::ConstListView args_list = args->GetList();
+  CHECK_GE(args_list.size(), 1u);
+  std::u16string phone_name = base::UTF8ToUTF16(args_list[0].GetString());
   fake_phone_hub_manager_->mutable_phone_model()->SetPhoneName(phone_name);
   PA_LOG(VERBOSE) << "Set phone name to " << phone_name;
 }
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 30ce2208..18682a7 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -37,6 +37,7 @@
 #include "chrome/browser/printing/print_view_manager.h"
 #include "chrome/browser/printing/printer_manager_dialog.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/account_consistency_mode_manager_factory.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/chrome_pages.h"
@@ -84,22 +85,17 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chrome/browser/ash/account_manager/account_manager_util.h"
 #include "chrome/browser/ash/crosapi/crosapi_ash.h"
 #include "chrome/browser/ash/crosapi/crosapi_manager.h"
 #include "chrome/browser/ash/crosapi/local_printer_ash.h"
 #include "chrome/browser/ash/drive/drive_integration_service.h"
 #elif BUILDFLAG(IS_CHROMEOS_LACROS)
-#include "chrome/browser/lacros/account_manager/account_manager_util.h"
 #include "chromeos/crosapi/mojom/drive_integration_service.mojom.h"
 #include "chromeos/lacros/lacros_service.h"
 #endif
 
 using content::RenderFrameHost;
 using content::WebContents;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-using ash::IsAccountManagerAvailable;
-#endif
 
 namespace printing {
 
@@ -858,7 +854,7 @@
   DCHECK(profile);
 
 #if defined(OS_CHROMEOS)
-  if (IsAccountManagerAvailable(profile)) {
+  if (AccountConsistencyModeManager::IsMirrorEnabledForProfile(profile)) {
     // Chrome OS Account Manager is enabled on this Profile and hence, all
     // account management flows will go through native UIs and not through a
     // tabbed browser window.
diff --git a/chrome/browser/ui/webui/settings/protocol_handlers_handler.cc b/chrome/browser/ui/webui/settings/protocol_handlers_handler.cc
index 15d1ba9..0666665 100644
--- a/chrome/browser/ui/webui/settings/protocol_handlers_handler.cc
+++ b/chrome/browser/ui/webui/settings/protocol_handlers_handler.cc
@@ -209,13 +209,14 @@
 
 ProtocolHandler ProtocolHandlersHandler::ParseHandlerFromArgs(
     const base::ListValue* args) const {
-  std::u16string protocol;
-  std::u16string url;
-  bool ok = args->GetString(0, &protocol) && args->GetString(1, &url);
+  base::Value::ConstListView args_list = args->GetList();
+  bool ok = args_list.size() >= 2u && args_list[0].is_string() &&
+            args_list[1].is_string();
   if (!ok)
     return ProtocolHandler::EmptyProtocolHandler();
-  return ProtocolHandler::CreateProtocolHandler(base::UTF16ToUTF8(protocol),
-                                                GURL(base::UTF16ToUTF8(url)));
+  std::string protocol = args_list[0].GetString();
+  std::string url = args_list[1].GetString();
+  return ProtocolHandler::CreateProtocolHandler(protocol, GURL(url));
 }
 
 ProtocolHandlerRegistry* ProtocolHandlersHandler::GetProtocolHandlerRegistry() {
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 ff6b50b..d1497527 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -28,7 +28,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_shortcut_manager.h"
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
-#include "chrome/browser/signin/signin_features.h"
+#include "chrome/browser/signin/account_consistency_mode_manager_factory.h"
 #include "chrome/browser/sync/sync_service_factory.h"
 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -93,7 +93,6 @@
 #include "ui/strings/grit/ui_strings.h"
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-#include "chrome/browser/lacros/account_manager/account_manager_util.h"
 #include "chromeos/lacros/lacros_service.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
@@ -1341,14 +1340,9 @@
   html_source->AddBoolean("isAccountManagerEnabled",
                           ash::IsAccountManagerAvailable(profile));
 #elif BUILDFLAG(IS_CHROMEOS_LACROS)
-  html_source->AddBoolean("isAccountManagerEnabled",
-                          IsAccountManagerAvailable(profile));
-  // On Lacros, signout is only supported for secondary profiles without account
-  // consistency.
   html_source->AddBoolean(
-      "isSignoutSupported",
-      !base::FeatureList::IsEnabled(kMultiProfileAccountConsistency) &&
-          !profile->IsMainProfile());
+      "isAccountManagerEnabled",
+      AccountConsistencyModeManager::IsMirrorEnabledForProfile(profile));
 #endif
 
   AddSignOutDialogStrings(html_source, profile);
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.cc b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
index a5975d8..3e21ece9 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_handler.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
@@ -775,56 +775,47 @@
   AllowJavascript();
   CHECK_EQ(2U, args->GetList().size());
   absl::optional<SkColor> profile_color = args->GetList()[0].GetIfInt();
+  const std::string& gaia_id = args->GetList()[1].GetString();
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-  if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency)) {
-    if (IsSelectingSecondaryAccount(web_ui())) {
-      AccountProfileMapper* mapper =
-          g_browser_process->profile_manager()->GetAccountProfileMapper();
-      const std::string& gaia_id = args->GetList()[1].GetString();
-      if (gaia_id.empty()) {
-        mapper->ShowAddAccountDialog(
-            GetCurrentProfilePath(web_ui()),
-            account_manager::AccountManagerFacade::AccountAdditionSource::
-                kOgbAddAccount,
-            AccountProfileMapper::AddAccountCallback());
-      } else {
-        mapper->AddAccount(GetCurrentProfilePath(web_ui()),
-                           account_manager::AccountKey(
-                               gaia_id, account_manager::AccountType::kGaia),
-                           AccountProfileMapper::AddAccountCallback());
-      }
-      ProfilePicker::Hide();
-      return;
-    }
-
-    DCHECK(!lacros_sign_in_provider_);
-    lacros_sign_in_provider_ =
-        std::make_unique<ProfilePickerLacrosSignInProvider>();
-    ProfilePickerLacrosSignInProvider::SignedInCallback callback =
-        base::BindOnce(&ProfilePickerHandler::OnLacrosSignedInProfileCreated,
-                       weak_factory_.GetWeakPtr(), profile_color);
-    const std::string& gaia_id = args->GetList()[1].GetString();
+  if (IsSelectingSecondaryAccount(web_ui())) {
+    AccountProfileMapper* mapper =
+        g_browser_process->profile_manager()->GetAccountProfileMapper();
     if (gaia_id.empty()) {
-      lacros_sign_in_provider_->ShowAddAccountDialogAndCreateSignedInProfile(
-          std::move(callback));
+      mapper->ShowAddAccountDialog(GetCurrentProfilePath(web_ui()),
+                                   account_manager::AccountManagerFacade::
+                                       AccountAdditionSource::kOgbAddAccount,
+                                   AccountProfileMapper::AddAccountCallback());
     } else {
-      lacros_sign_in_provider_->CreateSignedInProfileWithExistingAccount(
-          gaia_id, std::move(callback));
+      mapper->AddAccount(GetCurrentProfilePath(web_ui()),
+                         account_manager::AccountKey(
+                             gaia_id, account_manager::AccountType::kGaia),
+                         AccountProfileMapper::AddAccountCallback());
     }
+    ProfilePicker::Hide();
     return;
   }
-#endif
 
-  DCHECK(args->GetList()[1].GetString().empty())
-      << "gaiaId is only supported on Lacros with account consistency";
+  DCHECK(!lacros_sign_in_provider_);
+  lacros_sign_in_provider_ =
+      std::make_unique<ProfilePickerLacrosSignInProvider>();
+  ProfilePickerLacrosSignInProvider::SignedInCallback callback =
+      base::BindOnce(&ProfilePickerHandler::OnLacrosSignedInProfileCreated,
+                     weak_factory_.GetWeakPtr(), profile_color);
+  if (gaia_id.empty()) {
+    lacros_sign_in_provider_->ShowAddAccountDialogAndCreateSignedInProfile(
+        std::move(callback));
+  } else {
+    lacros_sign_in_provider_->CreateSignedInProfileWithExistingAccount(
+        gaia_id, std::move(callback));
+  }
+#elif BUILDFLAG(ENABLE_DICE_SUPPORT)
+  DCHECK(gaia_id.empty()) << "gaiaId is only supported on Lacros.";
   if (signin_util::IsForceSigninEnabled()) {
     // Force sign-in policy uses a separate flow that doesn't initialize the
     // profile color. Generate a new profile color here.
     profile_color = GenerateNewProfileColor().color;
   }
-
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
   ProfilePicker::SwitchToDiceSignIn(
       profile_color, base::BindOnce(&ProfilePickerHandler::OnLoadSigninFinished,
                                     weak_factory_.GetWeakPtr()));
@@ -1126,7 +1117,6 @@
 void ProfilePickerHandler::OnLacrosSignedInProfileCreated(
     absl::optional<SkColor> profile_color,
     Profile* profile) {
-  DCHECK(base::FeatureList::IsEnabled(kMultiProfileAccountConsistency));
   DCHECK(lacros_sign_in_provider_);
   lacros_sign_in_provider_.reset();
 
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler_unittest.cc b/chrome/browser/ui/webui/signin/profile_picker_handler_unittest.cc
index db8b4f3..1b48bef 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_handler_unittest.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_handler_unittest.cc
@@ -9,12 +9,10 @@
 #include "base/json/values_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
 #include "build/buildflag.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/test/base/profile_waiter.h"
@@ -156,8 +154,6 @@
 
  private:
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-  base::test::ScopedFeatureList scoped_feature_list_{
-      kMultiProfileAccountConsistency};
   testing::NiceMock<account_manager::MockAccountManagerFacade>
       mock_account_manager_facade_;
 
diff --git a/chrome/browser/ui/webui/signin/profile_picker_lacros_sign_in_provider.cc b/chrome/browser/ui/webui/signin/profile_picker_lacros_sign_in_provider.cc
index b786d5b..4997a5a 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_lacros_sign_in_provider.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_lacros_sign_in_provider.cc
@@ -9,15 +9,13 @@
 #include "chrome/browser/profiles/profile_keep_alive_types.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "components/account_manager_core/account.h"
 #include "components/account_manager_core/account_manager_facade.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/signin/public/identity_manager/primary_account_mutator.h"
 
-ProfilePickerLacrosSignInProvider::ProfilePickerLacrosSignInProvider() {
-  DCHECK(base::FeatureList::IsEnabled(kMultiProfileAccountConsistency));
-}
+ProfilePickerLacrosSignInProvider::ProfilePickerLacrosSignInProvider() =
+    default;
 
 ProfilePickerLacrosSignInProvider::~ProfilePickerLacrosSignInProvider() =
     default;
diff --git a/chrome/browser/ui/webui/signin/profile_picker_ui.cc b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
index 986eb0b..ff60fa67 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_ui.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/webui/signin/profile_picker_ui.h"
 
-#include "base/feature_list.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/buildflag.h"
@@ -16,7 +15,6 @@
 #include "chrome/browser/profiles/profile_shortcut_manager.h"
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/signin/signin_util.h"
 #include "chrome/browser/ui/managed_ui.h"
 #include "chrome/browser/ui/profile_picker.h"
@@ -220,10 +218,6 @@
       l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE),
       l10n_util::GetStringUTF16(IDS_OS_SETTINGS_PEOPLE_V2));
   html_source->AddString("removeWarningProfileLacros", remove_warning_profile);
-
-  html_source->AddBoolean(
-      "isMultiProfileAccountConsistentcyLacrosEnabled",
-      base::FeatureList::IsEnabled(kMultiProfileAccountConsistency));
 #endif
 
   // Add policies.
diff --git a/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.cc b/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.cc
index 31fe282..40e7d36 100644
--- a/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.cc
+++ b/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.cc
@@ -15,8 +15,10 @@
 #include "chrome/browser/sync_file_system/sync_file_system_service.h"
 #include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
 #include "chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.h"
+#include "content/public/browser/storage_partition_config.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
+#include "extensions/browser/extension_util.h"
 #include "extensions/common/extension.h"
 
 using sync_file_system::RemoteFileSyncService;
@@ -60,9 +62,18 @@
       SyncFileSystemServiceFactory::GetForProfile(profile_);
   if (!sync_service)
     return;
+
+  content::StoragePartitionConfig storage_partition_config =
+      extensions::util::GetStoragePartitionConfigForExtensionId(extension_id,
+                                                                profile_);
+  content::StoragePartition* storage_partition =
+      profile_->GetStoragePartition(storage_partition_config);
+  CHECK(storage_partition);
+
   sync_service->DumpFiles(
-      origin, base::BindOnce(&FileMetadataHandler::DidGetFileMetadata,
-                             weak_factory_.GetWeakPtr(), callback_id));
+      storage_partition, origin,
+      base::BindOnce(&FileMetadataHandler::DidGetFileMetadata,
+                     weak_factory_.GetWeakPtr(), callback_id));
 }
 
 void FileMetadataHandler::HandleGetExtensions(const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_handler.cc b/chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_handler.cc
index 4e282d9..b454654 100644
--- a/chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_handler.cc
+++ b/chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_handler.cc
@@ -80,6 +80,11 @@
     const GURL& app_origin,
     sync_file_system::SyncServiceState state,
     const std::string& description) {
+  if (!IsJavascriptAllowed()) {
+    // Javascript is disallowed, either due to the page still loading, or in the
+    // process of being unloaded. Skip this update.
+    return;
+  }
   std::string state_string = chrome_apps::api::sync_file_system::ToString(
       chrome_apps::api::SyncServiceStateToExtensionEnum(state));
   if (!description.empty())
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 0b86d42c..c1391b3 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -328,6 +328,7 @@
       "//ash/webui/personalization_app",
       "//ash/webui/shimless_rma",
       "//ash/webui/shortcut_customization_ui",
+      "//chrome/browser/ash/crosapi:browser_util",
       "//chromeos/strings",
       "//components/arc/mojom",
     ]
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index 32b18d7..ce6838c5 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -125,6 +125,7 @@
   specified_sources[Source::kDefault] = true;
   specified_sources[Source::kSync] = true;
   specified_sources[Source::kWebAppStore] = true;
+  specified_sources[Source::kSubApp] = true;
   return HasAnySpecifiedSourcesAndNoOtherSources(specified_sources);
 }
 
diff --git a/chrome/browser/web_applications/web_app_data_retriever.cc b/chrome/browser/web_applications/web_app_data_retriever.cc
index b3bde2d..e681876 100644
--- a/chrome/browser/web_applications/web_app_data_retriever.cc
+++ b/chrome/browser/web_applications/web_app_data_retriever.cc
@@ -46,7 +46,7 @@
 
   content::NavigationEntry* entry =
       web_contents->GetController().GetLastCommittedEntry();
-  if (!entry) {
+  if (entry->IsInitialEntry()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(&WebAppDataRetriever::CallCallbackOnError,
                                   weak_ptr_factory_.GetWeakPtr()));
@@ -159,7 +159,7 @@
   content::NavigationEntry* entry =
       contents->GetController().GetLastCommittedEntry();
 
-  if (entry) {
+  if (!entry->IsInitialEntry()) {
     if (entry->GetUniqueID() == last_committed_nav_entry_unique_id) {
       info = std::make_unique<WebApplicationInfo>(*web_page_metadata);
       if (info->start_url.is_empty())
diff --git a/chrome/browser/web_applications/web_app_utils.cc b/chrome/browser/web_applications/web_app_utils.cc
index 8a0c116..0d71024 100644
--- a/chrome/browser/web_applications/web_app_utils.cc
+++ b/chrome/browser/web_applications/web_app_utils.cc
@@ -24,8 +24,8 @@
 #include "url/gurl.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
+#include "chrome/browser/ash/crosapi/browser_util.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/common/chrome_features.h"
 #include "components/user_manager/user_manager.h"
@@ -296,7 +296,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 bool IsWebAppsCrosapiEnabled() {
   return base::FeatureList::IsEnabled(features::kWebAppsCrosapi) ||
-         base::FeatureList::IsEnabled(chromeos::features::kLacrosPrimary);
+         crosapi::browser_util::IsLacrosPrimaryBrowser();
 }
 #endif
 
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 9a20640..234ab2ef 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1638229946-50c82a81edc50e33ad40cb665d7e150c992265fe.profdata
+chrome-linux-main-1638273499-94956d51d99cb13f08a2169a82b2509c4db9111f.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index aab751e..a06ea438 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1638229946-8fea31ce4d25ed93e21d0dc1c2a3b662f96e2131.profdata
+chrome-mac-main-1638251560-e64f3a70de4c4b4e962a792fa6d7e0b8c16f57a9.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index d162737..b14977c1 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1638229946-37dacb283bd8156b022803e89774bbf9d5ebd4ba.profdata
+chrome-win32-main-1638251560-b3e4b41386637f0ea327f46072d288f22733da1c.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 6f9a396..43da7d2 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1638219078-8601a47c4e2f5d3b69adb491db33af22facac4f3.profdata
+chrome-win64-main-1638262651-1869b44a7127e397854e6700c39af4fd2000a03d.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index aba50d2..767b1d1 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2445,6 +2445,12 @@
       if (is_win) {
         sources += [ "../browser/signin/signin_util_win_browsertest.cc" ]
       }
+
+      # TODO(https://crbug.com/1198523: Remove this once enable_dice_support is
+      # no longer defined on Lacros.
+      if (is_chromeos_lacros) {
+        sources -= [ "../browser/signin/signin_ui_util_browsertest.cc" ]
+      }
     } else {
       sources += [ "../browser/signin/mirror_browsertest.cc" ]
     }
@@ -2485,9 +2491,6 @@
           "//ppapi/native_client:irt",
           "//third_party/liblouis:liblouis_test_data",
         ]
-        if (enable_nacl_nonsfi) {
-          data_deps += [ "//components/nacl/loader:helper_nonsfi" ]
-        }
       }
 
       if (is_win || is_linux || is_chromeos) {
@@ -2501,10 +2504,6 @@
       }
       if (is_linux || is_chromeos) {
         data_deps += [ "//components/nacl/loader:nacl_helper" ]
-
-        if (enable_nacl_nonsfi) {
-          data_deps += [ "//components/nacl/loader:helper_nonsfi" ]
-        }
       }
     }
 
@@ -5712,6 +5711,16 @@
       "../browser/ui/views/profiles/dice_web_signin_interception_bubble_view_unittest.cc",
       "../browser/ui/views/profiles/profile_customization_bubble_sync_controller_unittest.cc",
     ]
+
+    # TODO(https://crbug.com/1198523: Remove this once enable_dice_support is no
+    # longer defined on Lacros.
+    if (is_chromeos_lacros) {
+      sources -= [
+        "../browser/password_manager/multi_profile_credentials_filter_unittest.cc",
+        "../browser/signin/dice_web_signin_interceptor_unittest.cc",
+        "../browser/signin/signin_manager_unittest.cc",
+      ]
+    }
   }
 
   if (is_win || is_mac || (is_linux || is_chromeos_lacros)) {
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index dc7c44f..da9b9dbf 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -42,7 +42,6 @@
 #include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -224,22 +223,20 @@
         g_browser_process->system_network_context_manager()
             ->GetSharedURLLoaderFactory());
 
-    if (base::FeatureList::IsEnabled(kMultiProfileAccountConsistency)) {
-      // Make sure the primary accounts for all profiles are present in the
-      // account manager, to prevent profiles from being deleted. This is useful
-      // in particular for tests that create profiles in a PRE_ step and expect
-      // the profiles to still exist when Chrome is restarted.
-      ProfileAttributesStorage* storage =
-          &g_browser_process->profile_manager()->GetProfileAttributesStorage();
-      for (const ProfileAttributesEntry* entry :
-           storage->GetAllProfilesAttributes()) {
-        const std::string& gaia_id = entry->GetGAIAId();
-        if (!gaia_id.empty()) {
-          account_manager->UpsertAccount(
-              {gaia_id, account_manager::AccountType::kGaia},
-              base::UTF16ToUTF8(entry->GetUserName()),
-              "identity_extra_setup_test_token");
-        }
+    // Make sure the primary accounts for all profiles are present in the
+    // account manager, to prevent profiles from being deleted. This is useful
+    // in particular for tests that create profiles in a PRE_ step and expect
+    // the profiles to still exist when Chrome is restarted.
+    ProfileAttributesStorage* storage =
+        &g_browser_process->profile_manager()->GetProfileAttributesStorage();
+    for (const ProfileAttributesEntry* entry :
+         storage->GetAllProfilesAttributes()) {
+      const std::string& gaia_id = entry->GetGAIAId();
+      if (!gaia_id.empty()) {
+        account_manager->UpsertAccount(
+            {gaia_id, account_manager::AccountType::kGaia},
+            base::UTF16ToUTF8(entry->GetUserName()),
+            "identity_extra_setup_test_token");
       }
     }
   }
diff --git a/chrome/test/data/nacl/BUILD.gn b/chrome/test/data/nacl/BUILD.gn
index f56f4fa2..0daeac7 100644
--- a/chrome/test/data/nacl/BUILD.gn
+++ b/chrome/test/data/nacl/BUILD.gn
@@ -83,17 +83,6 @@
       ":sysconf_nprocessors_onln_test($glibc)",
     ]
   }
-  if ((is_linux || is_chromeos) && enable_nacl_nonsfi) {
-    nonsfi = "//build/toolchain/nacl:newlib_pnacl_nonsfi"
-    data_deps += [
-      ":irt_exception_test($nonsfi)",
-      ":irt_manifest_file($nonsfi)",
-      ":shared_test_files($nonsfi)",
-    ]
-    if (is_clang) {
-      data_deps += [ ":nonsfi_libc_free" ]
-    }
-  }
 }
 
 if (is_nacl) {
@@ -170,7 +159,7 @@
   }
 }
 
-if (is_nacl && !is_nacl_nonsfi) {
+if (is_nacl) {
   nacl_test_data("simple_test") {
     output_name = "simple"
     sources = [ "simple.cc" ]
@@ -433,6 +422,7 @@
     arch = target_cpu
   }
 
+  # TODO(https://crbug.com/1273132): Can this be deleted?
   config("nonsfi_libc_free_nexe_config") {
     cflags = [
       "-Wno-sign-compare",
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index b60db9a..38cd8ed 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -658,6 +658,7 @@
   out_dir = "$target_gen_dir/tsc"
   js_files = [
     "chai_assert.js",
+    "fake_chrome_event.js",
     "mojo_webui_test_support.js",
     "test_browser_proxy.js",
     "test_plural_string_proxy.js",
diff --git a/chrome/test/data/webui/async_gen.cc b/chrome/test/data/webui/async_gen.cc
index 20c8a145..f3f84cd 100644
--- a/chrome/test/data/webui/async_gen.cc
+++ b/chrome/test/data/webui/async_gen.cc
@@ -21,8 +21,9 @@
 
 void WebUIBrowserAsyncGenTest::AsyncWebUIMessageHandler::HandleCallJS(
     const base::ListValue* list_value) {
-  std::string call_js;
-  ASSERT_TRUE(list_value->GetString(0, &call_js));
+  base::Value::ConstListView list_view = list_value->GetList();
+  ASSERT_TRUE(0u < list_view.size() && list_view[0].is_string());
+  std::string call_js = list_view[0].GetString();
   web_ui()->CallJavascriptFunctionUnsafe(call_js);
 }
 
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_test.js b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_test.js
index db7c30c..73aa9c88 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_test.js
+++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_test.js
@@ -2,11 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'chrome://personalization/strings.m.js';
 import '../../mojo_webui_test_support.js';
 
 import * as action from 'chrome://personalization/trusted/personalization_actions.js';
 import {WallpaperCollection} from 'chrome://personalization/trusted/personalization_app.mojom-webui.js';
 import {fetchGooglePhotosAlbum, fetchLocalData, initializeBackdropData, initializeGooglePhotosData, selectWallpaper} from 'chrome://personalization/trusted/wallpaper/wallpaper_controller.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 
 import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
 
@@ -51,193 +53,145 @@
     personalizationStore.setReducersEnabled(true);
   });
 
-  test('initializes Google Photos data in store', async () => {
-    await initializeGooglePhotosData(wallpaperProvider, personalizationStore);
+  [true, false].forEach(isGooglePhotosIntegrationEnabled => {
+    test('initializes Google Photos data in store', async () => {
+      loadTimeData.overrideValues({isGooglePhotosIntegrationEnabled});
 
-    assertDeepEquals(
-        [
-          {
-            name: 'begin_load_google_photos_count',
-          },
-          {
-            name: 'set_google_photos_count',
-            count: 1000,
-          },
-          {
-            name: 'begin_load_google_photos_albums',
-          },
-          {
-            name: 'begin_load_google_photos_photos',
-          },
-          {
-            name: 'set_google_photos_albums',
-            albums: [
-              {
-                id: '9bd1d7a3-f995-4445-be47-53c5b58ce1cb',
-                name: 'Album 0',
-              },
-              {
-                id: '0ec40478-9712-42e1-b5bf-3e75870ca042',
-                name: 'Album 1',
-              },
-              {
-                id: '0a268a37-877a-4936-81d4-38cc84b0f596',
-                name: 'Album 2',
-              },
-              {
-                id: '27597eb3-a42d-474c-ab39-592680dcf35a',
-                name: 'Album 3',
-              },
-              {
-                id: 'bdcd6ba5-ed70-4866-9bc0-87ccf87db08c',
-                name: 'Album 4',
-              },
-            ],
-          },
-          {
-            name: 'set_google_photos_photos',
-            photos: Array.from({length: 1000}),
-          },
-        ],
-        personalizationStore.actions);
+      await initializeGooglePhotosData(wallpaperProvider, personalizationStore);
 
-    assertDeepEquals(
-        [
-          // BEGIN_LOAD_GOOGLE_PHOTOS_COUNT.
-          {
-            'loading.googlePhotos': {
-              count: true,
-              albums: false,
-              photos: false,
-              photosByAlbumId: {},
+      let expectedCount, expectedAlbums, expectedPhotos;
+      if (isGooglePhotosIntegrationEnabled) {
+        expectedCount = 0n;
+        expectedAlbums = [];
+        expectedPhotos = [];
+      } else {
+        expectedCount = null;
+        expectedAlbums = null;
+        expectedPhotos = null;
+      }
+
+      assertDeepEquals(
+          [
+            {
+              name: 'begin_load_google_photos_count',
             },
-            googlePhotos: {
-              count: undefined,
-              albums: undefined,
-              photos: undefined,
-              photosByAlbumId: {},
+            {
+              name: 'set_google_photos_count',
+              count: expectedCount,
             },
-          },
-          // SET_GOOGLE_PHOTOS_COUNT.
-          {
-            'loading.googlePhotos': {
-              count: false,
-              albums: false,
-              photos: false,
-              photosByAlbumId: {},
+            {
+              name: 'begin_load_google_photos_albums',
             },
-            googlePhotos: {
-              count: 1000,
-              albums: undefined,
-              photos: undefined,
-              photosByAlbumId: {},
+            {
+              name: 'begin_load_google_photos_photos',
             },
-          },
-          // BEGIN_LOAD_GOOGLE_PHOTOS_ALBUMS.
-          {
-            'loading.googlePhotos': {
-              count: false,
-              albums: true,
-              photos: false,
-              photosByAlbumId: {},
+            {
+              name: 'set_google_photos_albums',
+              albums: expectedAlbums,
             },
-            googlePhotos: {
-              count: 1000,
-              albums: undefined,
-              photos: undefined,
-              photosByAlbumId: {},
+            {
+              name: 'set_google_photos_photos',
+              photos: expectedPhotos,
             },
-          },
-          // BEGIN_LOAD_GOOGLE_PHOTOS_PHOTOS.
-          {
-            'loading.googlePhotos': {
-              count: false,
-              albums: true,
-              photos: true,
-              photosByAlbumId: {},
+          ],
+          personalizationStore.actions);
+
+      assertDeepEquals(
+          [
+            // BEGIN_LOAD_GOOGLE_PHOTOS_COUNT.
+            {
+              'loading.googlePhotos': {
+                count: true,
+                albums: false,
+                photos: false,
+                photosByAlbumId: {},
+              },
+              googlePhotos: {
+                count: undefined,
+                albums: undefined,
+                photos: undefined,
+                photosByAlbumId: {},
+              },
             },
-            googlePhotos: {
-              count: 1000,
-              albums: undefined,
-              photos: undefined,
-              photosByAlbumId: {},
+            // SET_GOOGLE_PHOTOS_COUNT.
+            {
+              'loading.googlePhotos': {
+                count: false,
+                albums: false,
+                photos: false,
+                photosByAlbumId: {},
+              },
+              googlePhotos: {
+                count: expectedCount,
+                albums: undefined,
+                photos: undefined,
+                photosByAlbumId: {},
+              },
             },
-          },
-          // SET_GOOGLE_PHOTOS_ALBUMS.
-          {
-            'loading.googlePhotos': {
-              count: false,
-              albums: false,
-              photos: true,
-              photosByAlbumId: {},
+            // BEGIN_LOAD_GOOGLE_PHOTOS_ALBUMS.
+            {
+              'loading.googlePhotos': {
+                count: false,
+                albums: true,
+                photos: false,
+                photosByAlbumId: {},
+              },
+              googlePhotos: {
+                count: expectedCount,
+                albums: undefined,
+                photos: undefined,
+                photosByAlbumId: {},
+              },
             },
-            googlePhotos: {
-              count: 1000,
-              albums: [
-                {
-                  id: '9bd1d7a3-f995-4445-be47-53c5b58ce1cb',
-                  name: 'Album 0',
-                },
-                {
-                  id: '0ec40478-9712-42e1-b5bf-3e75870ca042',
-                  name: 'Album 1',
-                },
-                {
-                  id: '0a268a37-877a-4936-81d4-38cc84b0f596',
-                  name: 'Album 2',
-                },
-                {
-                  id: '27597eb3-a42d-474c-ab39-592680dcf35a',
-                  name: 'Album 3',
-                },
-                {
-                  id: 'bdcd6ba5-ed70-4866-9bc0-87ccf87db08c',
-                  name: 'Album 4',
-                },
-              ],
-              photos: undefined,
-              photosByAlbumId: {},
+            // BEGIN_LOAD_GOOGLE_PHOTOS_PHOTOS.
+            {
+              'loading.googlePhotos': {
+                count: false,
+                albums: true,
+                photos: true,
+                photosByAlbumId: {},
+              },
+              googlePhotos: {
+                count: expectedCount,
+                albums: undefined,
+                photos: undefined,
+                photosByAlbumId: {},
+              },
             },
-          },
-          // SET_GOOGLE_PHOTOS_PHOTOS.
-          {
-            'loading.googlePhotos': {
-              count: false,
-              albums: false,
-              photos: false,
-              photosByAlbumId: {},
+            // SET_GOOGLE_PHOTOS_ALBUMS.
+            {
+              'loading.googlePhotos': {
+                count: false,
+                albums: false,
+                photos: true,
+                photosByAlbumId: {},
+              },
+              googlePhotos: {
+                count: expectedCount,
+                albums: expectedAlbums,
+                photos: undefined,
+                photosByAlbumId: {},
+              },
             },
-            googlePhotos: {
-              count: 1000,
-              albums: [
-                {
-                  id: '9bd1d7a3-f995-4445-be47-53c5b58ce1cb',
-                  name: 'Album 0',
-                },
-                {
-                  id: '0ec40478-9712-42e1-b5bf-3e75870ca042',
-                  name: 'Album 1',
-                },
-                {
-                  id: '0a268a37-877a-4936-81d4-38cc84b0f596',
-                  name: 'Album 2',
-                },
-                {
-                  id: '27597eb3-a42d-474c-ab39-592680dcf35a',
-                  name: 'Album 3',
-                },
-                {
-                  id: 'bdcd6ba5-ed70-4866-9bc0-87ccf87db08c',
-                  name: 'Album 4',
-                },
-              ],
-              photos: Array.from({length: 1000}),
-              photosByAlbumId: {},
+            // SET_GOOGLE_PHOTOS_PHOTOS.
+            {
+              'loading.googlePhotos': {
+                count: false,
+                albums: false,
+                photos: false,
+                photosByAlbumId: {},
+              },
+              googlePhotos: {
+                count: expectedCount,
+                albums: expectedAlbums,
+                photos: expectedPhotos,
+                photosByAlbumId: {},
+              },
             },
-          },
-        ],
-        personalizationStore.states.map(
-            filterAndFlattenState(['googlePhotos', 'loading.googlePhotos'])));
+          ],
+          personalizationStore.states.map(
+              filterAndFlattenState(['googlePhotos', 'loading.googlePhotos'])));
+    });
   });
 
   test('sets Google Photos album in store', async () => {
@@ -602,7 +556,7 @@
     wallpaperProvider = new TestWallpaperProvider();
     personalizationStore = new TestPersonalizationStore({});
     personalizationStore.setReducersEnabled(true);
-    loadTimeData.data = {[fullscreenPreviewFeature]: true};
+    loadTimeData.resetForTesting({[fullscreenPreviewFeature]: true});
   });
 
   test(
diff --git a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.js b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.js
index 99944d5..13cecdb8 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.js
+++ b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.js
@@ -65,7 +65,7 @@
 
     wallpaperCollectionsElement = initElement(WallpaperCollections.is);
 
-    personalizationStore.data.googlePhotos.count = 1234;
+    personalizationStore.data.googlePhotos.count = 1234n;
     personalizationStore.data.loading.googlePhotos.count = false;
     personalizationStore.notifyObservers();
 
diff --git a/chrome/test/data/webui/read_later/BUILD.gn b/chrome/test/data/webui/read_later/BUILD.gn
index e76c1ed..071c946 100644
--- a/chrome/test/data/webui/read_later/BUILD.gn
+++ b/chrome/test/data/webui/read_later/BUILD.gn
@@ -2,22 +2,40 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
 generate_grd("build_grdp") {
   grd_prefix = "webui_read_later"
   out_grd = "$target_gen_dir/resources.grdp"
 
-  input_files = [
-    "read_later_app_test.js",
+  deps = [ ":build_ts" ]
+  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  resource_path_prefix = "read_later"
+}
+
+ts_library("build_ts") {
+  root_dir = "./"
+  out_dir = "$target_gen_dir/tsc"
+  tsconfig_base = "tsconfig_base.json"
+  path_mappings = [
+    "chrome://read-later.top-chrome/*|" +
+        rebase_path("$root_gen_dir/chrome/browser/resources/read_later/tsc/*",
+                    target_gen_dir),
+    "chrome://webui-test/*|" +
+        rebase_path("$root_gen_dir/chrome/test/data/webui/tsc/*",
+                    target_gen_dir),
+  ]
+  in_files = [
+    "read_later_app_test.ts",
     "side_panel/bookmark_folder_test.js",
     "side_panel/bookmarks_drag_manager_test.js",
     "side_panel/bookmarks_list_test.js",
     "side_panel/side_panel_app_test.js",
-    "side_panel/test_bookmarks_api_proxy.js",
-    "test_read_later_api_proxy.js",
+    "side_panel/test_bookmarks_api_proxy.ts",
+    "test_read_later_api_proxy.ts",
   ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  resource_path_prefix = "read_later"
+  definitions = [ "//tools/typescript/definitions/bookmarks.d.ts" ]
+  deps = [ "//chrome/browser/resources/read_later:build_ts" ]
+  extra_deps = [ "..:generate_definitions" ]
 }
diff --git a/chrome/test/data/webui/read_later/read_later_app_test.js b/chrome/test/data/webui/read_later/read_later_app_test.ts
similarity index 71%
rename from chrome/test/data/webui/read_later/read_later_app_test.js
rename to chrome/test/data/webui/read_later/read_later_app_test.ts
index 889b3e8..b3f665c 100644
--- a/chrome/test/data/webui/read_later/read_later_app_test.js
+++ b/chrome/test/data/webui/read_later/read_later_app_test.ts
@@ -2,54 +2,47 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import '../mojo_webui_test_support.js';
+import 'chrome://webui-test/mojo_webui_test_support.js';
+import 'chrome://read-later.top-chrome/app.js';
 
 import {ReadLaterAppElement} from 'chrome://read-later.top-chrome/app.js';
 import {ReadLaterEntriesByStatus} from 'chrome://read-later.top-chrome/read_later.mojom-webui.js';
-import {ReadLaterApiProxy, ReadLaterApiProxyImpl} from 'chrome://read-later.top-chrome/read_later_api_proxy.js';
+import {ReadLaterApiProxyImpl} from 'chrome://read-later.top-chrome/read_later_api_proxy.js';
+import {ReadLaterItemElement} from 'chrome://read-later.top-chrome/read_later_item.js';
 import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
-
-import {assertEquals, assertFalse, assertTrue} from '../chai_assert.js';
-import {flushTasks} from '../test_util.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks} from 'chrome://webui-test/test_util.js';
 
 import {TestReadLaterApiProxy} from './test_read_later_api_proxy.js';
 
 suite('ReadLaterAppTest', () => {
-  /** @type {!ReadLaterAppElement} */
-  let readLaterApp;
-  /** @type {!TestReadLaterApiProxy} */
-  let testProxy;
+  let readLaterApp: ReadLaterAppElement;
+  let testProxy: TestReadLaterApiProxy;
 
-  /**
-   * @param {!NodeList<!Element>} items
-   * @param {!Array<string>} urls
-   */
-  function assertEntryURLs(items, urls) {
+  function assertEntryURLs(items: NodeListOf<HTMLElement>, urls: string[]) {
     assertEquals(urls.length, items.length);
     items.forEach((item, index) => {
-      assertEquals(urls[index], item.dataset.url);
+      assertEquals(urls[index], item.dataset['url']);
     });
   }
 
-  /** @return {!NodeList<!Element>} */
   function queryItems() {
-    return readLaterApp.shadowRoot.querySelectorAll('read-later-item');
+    return readLaterApp.shadowRoot!.querySelectorAll('read-later-item');
   }
 
-  /** @param {string} url */
-  function clickItem(url) {
-    readLaterApp.shadowRoot.querySelector(`[data-url="${url}"]`).click();
+  function clickItem(url: string) {
+    readLaterApp.shadowRoot!.querySelector<HTMLElement>(
+                                `[data-url="${url}"]`)!.click();
   }
 
-  /** @return {!ReadLaterEntriesByStatus} */
-  function getSampleData() {
+  function getSampleData(): ReadLaterEntriesByStatus {
     const entries = {
       unreadEntries: [
         {
           title: 'Google',
           url: {url: 'https://www.google.com'},
           displayUrl: 'google.com',
-          updateTime: 0,
+          updateTime: 0n,
           read: false,
           displayTimeSinceUpdate: '2 minutes ago',
         },
@@ -57,7 +50,7 @@
           title: 'Apple',
           url: {url: 'https://www.apple.com'},
           displayUrl: 'apple.com',
-          updateTime: 0,
+          updateTime: 0n,
           read: false,
           displayTimeSinceUpdate: '20 minutes ago',
         },
@@ -67,7 +60,7 @@
           title: 'Bing',
           url: {url: 'https://www.bing.com'},
           displayUrl: 'bing.com',
-          updateTime: 0,
+          updateTime: 0n,
           read: true,
           displayTimeSinceUpdate: '5 minutes ago',
         },
@@ -75,7 +68,7 @@
           title: 'Yahoo',
           url: {url: 'https://www.yahoo.com'},
           displayUrl: 'yahoo.com',
-          updateTime: 0,
+          updateTime: 0n,
           read: true,
           displayTimeSinceUpdate: '7 minutes ago',
         },
@@ -114,8 +107,8 @@
   });
 
   test('click on item passes event info', async () => {
-    const item = readLaterApp.shadowRoot.querySelector(
-        `[data-url="https://www.apple.com"]`);
+    const item = readLaterApp.shadowRoot!.querySelector(
+        `[data-url="https://www.apple.com"]`)!;
     item.dispatchEvent(new MouseEvent('click'));
     const [, , click] = await testProxy.whenCalled('openURL');
     assertFalse(
@@ -150,9 +143,9 @@
     const expectedUrl = 'https://www.apple.com';
 
     const readLaterItem =
-        readLaterApp.shadowRoot.querySelector(`[data-url="${expectedUrl}"]`);
-    const readLaterItemUpdateStatusButton =
-        readLaterItem.shadowRoot.querySelector('#updateStatusButton');
+        readLaterApp.shadowRoot!.querySelector<ReadLaterItemElement>(
+            `[data-url="${expectedUrl}"]`)!;
+    const readLaterItemUpdateStatusButton = readLaterItem.$.updateStatusButton;
     readLaterItemUpdateStatusButton.click();
     const [url, read] = await testProxy.whenCalled('updateReadStatus');
     assertEquals(expectedUrl, url.url);
@@ -163,9 +156,9 @@
     const expectedUrl = 'https://www.bing.com';
 
     const readLaterItem =
-        readLaterApp.shadowRoot.querySelector(`[data-url="${expectedUrl}"]`);
-    const readLaterItemUpdateStatusButton =
-        readLaterItem.shadowRoot.querySelector('#updateStatusButton');
+        readLaterApp.shadowRoot!.querySelector<ReadLaterItemElement>(
+            `[data-url="${expectedUrl}"]`)!;
+    const readLaterItemUpdateStatusButton = readLaterItem.$.updateStatusButton;
     readLaterItemUpdateStatusButton.click();
     const [url, read] = await testProxy.whenCalled('updateReadStatus');
     assertEquals(expectedUrl, url.url);
@@ -176,9 +169,9 @@
     const expectedUrl = 'https://www.apple.com';
 
     const readLaterItem =
-        readLaterApp.shadowRoot.querySelector(`[data-url="${expectedUrl}"]`);
-    const readLaterItemDeleteButton =
-        readLaterItem.shadowRoot.querySelector('#deleteButton');
+        readLaterApp.shadowRoot!.querySelector<ReadLaterItemElement>(
+            `[data-url="${expectedUrl}"]`)!;
+    const readLaterItemDeleteButton = readLaterItem.$.deleteButton;
     readLaterItemDeleteButton.click();
     const url = await testProxy.whenCalled('removeEntry');
     assertEquals(expectedUrl, url.url);
@@ -186,15 +179,16 @@
 
   test('Click on menu button triggers actions', async () => {
     const readLaterCloseButton =
-        readLaterApp.shadowRoot.querySelector('#closeButton');
+        readLaterApp.shadowRoot!.querySelector<HTMLElement>('#closeButton')!;
     readLaterCloseButton.click();
     await testProxy.whenCalled('closeUI');
   });
 
   test('Enter key triggers action and passes correct url', async () => {
     const expectedUrl = 'https://www.apple.com';
-    const readLaterItem = /** @type {!Element} */
-        (readLaterApp.shadowRoot.querySelector(`[data-url="${expectedUrl}"]`));
+    const readLaterItem =
+        readLaterApp.shadowRoot!.querySelector<ReadLaterItemElement>(
+            `[data-url="${expectedUrl}"]`)!;
 
     keyDownOn(readLaterItem, 0, [], 'Enter');
     const [url, updateReadStatus] = await testProxy.whenCalled('openURL');
@@ -204,8 +198,9 @@
 
   test('Space key triggers action and passes correct url', async () => {
     const expectedUrl = 'https://www.apple.com';
-    const readLaterItem = /** @type {!Element} */
-        (readLaterApp.shadowRoot.querySelector(`[data-url="${expectedUrl}"]`));
+    const readLaterItem =
+        readLaterApp.shadowRoot!.querySelector<ReadLaterItemElement>(
+            `[data-url="${expectedUrl}"]`)!;
 
     keyDownOn(readLaterItem, 0, [], ' ');
     const [url, updateReadStatus] = await testProxy.whenCalled('openURL');
@@ -218,11 +213,12 @@
       'https://www.google.com', 'https://www.apple.com', 'https://www.bing.com',
       'https://www.yahoo.com'
     ];
-    const selector = readLaterApp.shadowRoot.querySelector('iron-selector');
+    const selector = readLaterApp.shadowRoot!.querySelector('iron-selector')!;
 
     // Select first item.
     selector.selected =
-        readLaterApp.shadowRoot.querySelector('read-later-item').dataset.url;
+        readLaterApp.shadowRoot!.querySelector(
+                                    'read-later-item')!.dataset['url']!;
 
     keyDownOn(selector, 0, [], 'ArrowUp');
     assertEquals(urls[3], selector.selected);
@@ -241,43 +237,41 @@
       'Keyboard navigation left/right cycles through list item elements',
       async () => {
         const firstItem =
-            readLaterApp.shadowRoot.querySelector('read-later-item');
+            readLaterApp.shadowRoot!.querySelector('read-later-item')!;
         // Focus first item.
         firstItem.focus();
 
         keyDownOn(firstItem, 0, [], 'ArrowRight');
         assertEquals(
-            firstItem.shadowRoot.getElementById('updateStatusButton'),
-            firstItem.shadowRoot.activeElement);
+            firstItem.$.updateStatusButton,
+            firstItem.shadowRoot!.activeElement);
 
         keyDownOn(firstItem, 0, [], 'ArrowRight');
         assertEquals(
-            firstItem.shadowRoot.getElementById('deleteButton'),
-            firstItem.shadowRoot.activeElement);
+            firstItem.$.deleteButton, firstItem.shadowRoot!.activeElement);
 
         keyDownOn(firstItem, 0, [], 'ArrowRight');
-        assertEquals(firstItem, readLaterApp.shadowRoot.activeElement);
+        assertEquals(firstItem, readLaterApp.shadowRoot!.activeElement);
 
         keyDownOn(firstItem, 0, [], 'ArrowLeft');
         assertEquals(
-            firstItem.shadowRoot.getElementById('deleteButton'),
-            firstItem.shadowRoot.activeElement);
+            firstItem.$.deleteButton, firstItem.shadowRoot!.activeElement);
 
         keyDownOn(firstItem, 0, [], 'ArrowLeft');
         assertEquals(
-            firstItem.shadowRoot.getElementById('updateStatusButton'),
-            firstItem.shadowRoot.activeElement);
+            firstItem.$.updateStatusButton,
+            firstItem.shadowRoot!.activeElement);
 
         keyDownOn(firstItem, 0, [], 'ArrowLeft');
-        assertEquals(firstItem, readLaterApp.shadowRoot.activeElement);
+        assertEquals(firstItem, readLaterApp.shadowRoot!.activeElement);
       });
 
   test('Favicons present in the dom', async () => {
     const readLaterItems = /** @type {!NodeList<!Element>} */
-        (readLaterApp.shadowRoot.querySelectorAll('read-later-item'));
+        (readLaterApp.shadowRoot!.querySelectorAll('read-later-item'));
 
     readLaterItems.forEach((readLaterItem) => {
-      assertTrue(!!readLaterItem.shadowRoot.querySelector('.favicon'));
+      assertTrue(!!readLaterItem.shadowRoot!.querySelector('.favicon'));
     });
   });
 
diff --git a/chrome/test/data/webui/read_later/side_panel/bookmark_folder_test.js b/chrome/test/data/webui/read_later/side_panel/bookmark_folder_test.js
index d3edc598..9cfbd57d 100644
--- a/chrome/test/data/webui/read_later/side_panel/bookmark_folder_test.js
+++ b/chrome/test/data/webui/read_later/side_panel/bookmark_folder_test.js
@@ -6,12 +6,14 @@
 // finish running its tests.
 import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 
+import 'chrome://read-later.top-chrome/side_panel/bookmark_folder.js';
+
 import {BookmarkFolderElement, FOLDER_OPEN_CHANGED_EVENT} from 'chrome://read-later.top-chrome/side_panel/bookmark_folder.js';
-import {BookmarksApiProxy} from 'chrome://read-later.top-chrome/side_panel/bookmarks_api_proxy.js';
+import {BookmarksApiProxyImpl} from 'chrome://read-later.top-chrome/side_panel/bookmarks_api_proxy.js';
 import {getFaviconForPageURL} from 'chrome://resources/js/icon.js';
 
-import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
-import {eventToPromise, flushTasks, waitAfterNextRender} from '../../test_util.js';
+import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {eventToPromise, flushTasks, waitAfterNextRender} from 'chrome://webui-test/test_util.js';
 
 import {TestBookmarksApiProxy} from './test_bookmarks_api_proxy.js';
 
@@ -62,7 +64,7 @@
     document.body.innerHTML = '';
 
     bookmarksApi = new TestBookmarksApiProxy();
-    BookmarksApiProxy.setInstance(bookmarksApi);
+    BookmarksApiProxyImpl.setInstance(bookmarksApi);
 
     bookmarkFolder = /** @type {!BookmarkFolderElement} */ (
         document.createElement('bookmark-folder'));
diff --git a/chrome/test/data/webui/read_later/side_panel/bookmarks_drag_manager_test.js b/chrome/test/data/webui/read_later/side_panel/bookmarks_drag_manager_test.js
index 8868c7a0..102e09b1 100644
--- a/chrome/test/data/webui/read_later/side_panel/bookmarks_drag_manager_test.js
+++ b/chrome/test/data/webui/read_later/side_panel/bookmarks_drag_manager_test.js
@@ -5,13 +5,13 @@
 import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 
 import {FOLDER_OPEN_CHANGED_EVENT} from 'chrome://read-later.top-chrome/side_panel/bookmark_folder.js';
-import {BookmarksApiProxy} from 'chrome://read-later.top-chrome/side_panel/bookmarks_api_proxy.js';
+import {BookmarksApiProxyImpl} from 'chrome://read-later.top-chrome/side_panel/bookmarks_api_proxy.js';
 import {BookmarksDragManager, DROP_POSITION_ATTR, DropPosition, overrideFolderOpenerTimeoutDelay} from 'chrome://read-later.top-chrome/side_panel/bookmarks_drag_manager.js';
 import {BookmarksListElement, LOCAL_STORAGE_OPEN_FOLDERS_KEY} from 'chrome://read-later.top-chrome/side_panel/bookmarks_list.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 
-import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
-import {flushTasks} from '../../test_util.js';
+import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks} from 'chrome://webui-test/test_util.js';
 
 import {TestBookmarksApiProxy} from './test_bookmarks_api_proxy.js';
 
@@ -96,7 +96,7 @@
     bookmarksApi.setFolders(
         /** @type {!Array<!chrome.bookmarks.BookmarkTreeNode>} */ (
             JSON.parse(JSON.stringify(folders))));
-    BookmarksApiProxy.setInstance(bookmarksApi);
+    BookmarksApiProxyImpl.setInstance(bookmarksApi);
 
     window.localStorage[LOCAL_STORAGE_OPEN_FOLDERS_KEY] =
         JSON.stringify(['1', '4']);
diff --git a/chrome/test/data/webui/read_later/side_panel/bookmarks_list_test.js b/chrome/test/data/webui/read_later/side_panel/bookmarks_list_test.js
index 9acfe15..cd6fe4fa 100644
--- a/chrome/test/data/webui/read_later/side_panel/bookmarks_list_test.js
+++ b/chrome/test/data/webui/read_later/side_panel/bookmarks_list_test.js
@@ -6,13 +6,15 @@
 // finish running its tests.
 import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 
+import 'chrome://read-later.top-chrome/side_panel/bookmarks_list.js';
+
 import {BookmarkFolderElement, FOLDER_OPEN_CHANGED_EVENT} from 'chrome://read-later.top-chrome/side_panel/bookmark_folder.js';
-import {BookmarksApiProxy} from 'chrome://read-later.top-chrome/side_panel/bookmarks_api_proxy.js';
+import {BookmarksApiProxyImpl} from 'chrome://read-later.top-chrome/side_panel/bookmarks_api_proxy.js';
 import {BookmarksListElement, LOCAL_STORAGE_OPEN_FOLDERS_KEY} from 'chrome://read-later.top-chrome/side_panel/bookmarks_list.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {assertEquals, assertTrue} from '../../chai_assert.js';
-import {flushTasks} from '../../test_util.js';
+import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks} from 'chrome://webui-test/test_util.js';
 
 import {TestBookmarksApiProxy} from './test_bookmarks_api_proxy.js';
 
@@ -90,7 +92,7 @@
     bookmarksApi.setFolders(
         /** @type {!Array<!chrome.bookmarks.BookmarkTreeNode>} */ (
             JSON.parse(JSON.stringify(folders))));
-    BookmarksApiProxy.setInstance(bookmarksApi);
+    BookmarksApiProxyImpl.setInstance(bookmarksApi);
 
     bookmarksList = /** @type {!BookmarksListElement} */ (
         document.createElement('bookmarks-list'));
@@ -109,7 +111,7 @@
     const bookmarkIndex = 0;
 
     const changedBookmark = folders[rootFolderIndex].children[bookmarkIndex];
-    bookmarksApi.callbackRouter.onChanged.dispatchEvent(changedBookmark.id, {
+    bookmarksApi.callbackRouter.onChanged.callListeners(changedBookmark.id, {
       title: 'New title',
       url: 'http://new/url',
     });
@@ -123,7 +125,7 @@
     // Reverse the children of Bookmarks bar.
     const children = folders[0].children;
     const reverseOrder = children.map(child => child.id).reverse();
-    bookmarksApi.callbackRouter.onChildrenReordered.dispatchEvent(
+    bookmarksApi.callbackRouter.onChildrenReordered.callListeners(
         folders[0].id, {childIds: reverseOrder});
     flush();
 
@@ -136,7 +138,7 @@
   });
 
   test('AddsCreatedBookmark', async () => {
-    bookmarksApi.callbackRouter.onCreated.dispatchEvent('999', {
+    bookmarksApi.callbackRouter.onCreated.callListeners('999', {
       id: '999',
       title: 'New bookmark',
       index: 0,
@@ -156,7 +158,7 @@
 
   test('AddsCreatedBookmarkForNewFolder', () => {
     // Create a new folder without a children array.
-    bookmarksApi.callbackRouter.onCreated.dispatchEvent('1000', {
+    bookmarksApi.callbackRouter.onCreated.callListeners('1000', {
       id: '1000',
       title: 'New folder',
       index: 0,
@@ -165,7 +167,7 @@
     flush();
 
     // Create a new bookmark within that folder.
-    bookmarksApi.callbackRouter.onCreated.dispatchEvent('1001', {
+    bookmarksApi.callbackRouter.onCreated.callListeners('1001', {
       id: '1001',
       title: 'New bookmark in new folder',
       index: 0,
@@ -181,7 +183,7 @@
 
   test('MovesBookmarks', () => {
     const movedBookmark = folders[0].children[1].children[0];
-    bookmarksApi.callbackRouter.onMoved.dispatchEvent(movedBookmark.id, {
+    bookmarksApi.callbackRouter.onMoved.callListeners(movedBookmark.id, {
       index: 0,
       parentId: folders[0].id,                 // Moving to bookmarks bar.
       oldParentId: folders[0].children[1].id,  // Moving from child folder.
@@ -200,7 +202,7 @@
 
   test('MovesBookmarksIntoNewFolder', () => {
     // Create a new folder without a children array.
-    bookmarksApi.callbackRouter.onCreated.dispatchEvent('1000', {
+    bookmarksApi.callbackRouter.onCreated.callListeners('1000', {
       id: '1000',
       title: 'New folder',
       index: 0,
@@ -209,7 +211,7 @@
     flush();
 
     const movedBookmark = folders[0].children[1].children[0];
-    bookmarksApi.callbackRouter.onMoved.dispatchEvent(movedBookmark.id, {
+    bookmarksApi.callbackRouter.onMoved.callListeners(movedBookmark.id, {
       index: 0,
       parentId: '1000',
       oldParentId: folders[0].children[1].id,
diff --git a/chrome/test/data/webui/read_later/side_panel/side_panel_app_test.js b/chrome/test/data/webui/read_later/side_panel/side_panel_app_test.js
index 0bd50168..c82fa62 100644
--- a/chrome/test/data/webui/read_later/side_panel/side_panel_app_test.js
+++ b/chrome/test/data/webui/read_later/side_panel/side_panel_app_test.js
@@ -6,10 +6,11 @@
 // finish running its tests.
 import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 
-import {LOCAL_STORAGE_TAB_ID_KEY, SidePanelAppElement} from 'chrome://read-later.top-chrome/side_panel/app.js';
+import 'chrome://read-later.top-chrome/side_panel/app.js';
 
-import {assertEquals} from '../../chai_assert.js';
-import {flushTasks} from '../../test_util.js';
+import {LOCAL_STORAGE_TAB_ID_KEY, SidePanelAppElement} from 'chrome://read-later.top-chrome/side_panel/app.js';
+import {flushTasks} from 'chrome://webui-test/test_util.js';
+import {assertEquals} from 'chrome:/webui-test/chai_assert.js';
 
 suite('SidePanelAppElementTest', () => {
   /** @type {!SidePanelAppElement} */
diff --git a/chrome/test/data/webui/read_later/side_panel/test_bookmarks_api_proxy.js b/chrome/test/data/webui/read_later/side_panel/test_bookmarks_api_proxy.js
deleted file mode 100644
index 4bbdd2c..0000000
--- a/chrome/test/data/webui/read_later/side_panel/test_bookmarks_api_proxy.js
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {BookmarksApiProxy} from 'chrome://read-later.top-chrome/side_panel/bookmarks_api_proxy.js';
-
-import {TestBrowserProxy} from '../../test_browser_proxy.js';
-
-class EventDispatcher {
-  constructor() {
-    this.eventListeners_ = [];
-  }
-
-  addListener(callback) {
-    this.eventListeners_.push(callback);
-  }
-
-  removeListener(callback) {
-    this.eventListeners_.splice(this.eventListeners_.indexOf(callback), 1);
-  }
-
-  /** @param {...?} var_args */
-  dispatchEvent(var_args) {
-    this.eventListeners_.forEach((callback) => {
-      callback(...arguments);
-    });
-  }
-}
-
-/** @implements {BookmarksApiProxy} */
-export class TestBookmarksApiProxy extends TestBrowserProxy {
-  constructor() {
-    super([
-      'getFolders',
-      'openBookmark',
-      'cutBookmark',
-      'copyBookmark',
-      'pasteToBookmark',
-    ]);
-
-    this.callbackRouter = {
-      onChanged: new EventDispatcher(),
-      onChildrenReordered: new EventDispatcher(),
-      onCreated: new EventDispatcher(),
-      onMoved: new EventDispatcher(),
-      onRemoved: new EventDispatcher(),
-    };
-
-    /** @private {!Array<!chrome.bookmarks.BookmarkTreeNode>} */
-    this.folders_ = [];
-  }
-
-  getFolders() {
-    this.methodCalled('getFolders');
-    return Promise.resolve(this.folders_);
-  }
-
-  /**
-   * @param {string} url
-   * @param {number} depth
-   * @param {!ui.mojom.ClickModifiers} click_modifiers
-   */
-  openBookmark(url, depth, click_modifiers) {
-    this.methodCalled('openBookmark', url, depth, click_modifiers);
-  }
-
-  /** @param {!Array<!chrome.bookmarks.BookmarkTreeNode>} folders */
-  setFolders(folders) {
-    this.folders_ = folders;
-  }
-
-  /** @param {string} id */
-  copyBookmark(id) {
-    this.methodCalled('copyBookmark', id);
-  }
-
-  /** @param {string} id */
-  cutBookmark(id) {
-    this.methodCalled('cutBookmark', id);
-  }
-
-  /**
-   * @param {string} id
-   * @param {string=} destinationId
-   */
-  pasteToBookmark(id, destinationId) {
-    this.methodCalled('pasteToBookmark', id, destinationId);
-  }
-}
diff --git a/chrome/test/data/webui/read_later/side_panel/test_bookmarks_api_proxy.ts b/chrome/test/data/webui/read_later/side_panel/test_bookmarks_api_proxy.ts
new file mode 100644
index 0000000..c384fc7
--- /dev/null
+++ b/chrome/test/data/webui/read_later/side_panel/test_bookmarks_api_proxy.ts
@@ -0,0 +1,65 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {ChromeEvent} from '/tools/typescript/definitions/chrome_event.js';
+import {BookmarksApiProxy} from 'chrome://read-later.top-chrome/side_panel/bookmarks_api_proxy.js';
+import {ClickModifiers} from 'chrome://resources/mojo/ui/base/mojom/window_open_disposition.mojom-webui.js';
+import {FakeChromeEvent} from 'chrome://webui-test/fake_chrome_event.js';
+import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
+
+export class TestBookmarksApiProxy extends TestBrowserProxy implements
+    BookmarksApiProxy {
+  private folders_: chrome.bookmarks.BookmarkTreeNode[] = [];
+  callbackRouter: {[key: string]: ChromeEvent<Function>};
+
+  constructor() {
+    super([
+      'getFolders',
+      'openBookmark',
+      'cutBookmark',
+      'copyBookmark',
+      'pasteToBookmark',
+      'showContextMenu',
+    ]);
+
+    this.callbackRouter = {
+      onChanged: new FakeChromeEvent(),
+      onChildrenReordered: new FakeChromeEvent(),
+      onCreated: new FakeChromeEvent(),
+      onMoved: new FakeChromeEvent(),
+      onRemoved: new FakeChromeEvent(),
+    };
+  }
+
+  getFolders() {
+    this.methodCalled('getFolders');
+    return Promise.resolve(this.folders_);
+  }
+
+  openBookmark(url: string, depth: number, clickModifiers: ClickModifiers) {
+    this.methodCalled('openBookmark', url, depth, clickModifiers);
+  }
+
+  setFolders(folders: chrome.bookmarks.BookmarkTreeNode[]) {
+    this.folders_ = folders;
+  }
+
+  copyBookmark(id: string): Promise<void> {
+    this.methodCalled('copyBookmark', id);
+    return Promise.resolve();
+  }
+
+  cutBookmark(id: string) {
+    this.methodCalled('cutBookmark', id);
+  }
+
+  pasteToBookmark(parentId: string, destinationId?: string): Promise<void> {
+    this.methodCalled('pasteToBookmark', parentId, destinationId);
+    return Promise.resolve();
+  }
+
+  showContextMenu(id: string, x: number, y: number) {
+    this.methodCalled('showContextMenu', id, x, y);
+  }
+}
diff --git a/chrome/test/data/webui/read_later/test_read_later_api_proxy.js b/chrome/test/data/webui/read_later/test_read_later_api_proxy.ts
similarity index 60%
rename from chrome/test/data/webui/read_later/test_read_later_api_proxy.js
rename to chrome/test/data/webui/read_later/test_read_later_api_proxy.ts
index 43b81b6..2c581a18 100644
--- a/chrome/test/data/webui/read_later/test_read_later_api_proxy.js
+++ b/chrome/test/data/webui/read_later/test_read_later_api_proxy.ts
@@ -3,12 +3,16 @@
 // found in the LICENSE file.
 
 import {PageCallbackRouter, ReadLaterEntriesByStatus} from 'chrome://read-later.top-chrome/read_later.mojom-webui.js';
-
 import {ReadLaterApiProxy} from 'chrome://read-later.top-chrome/read_later_api_proxy.js';
-import {TestBrowserProxy} from '../test_browser_proxy.js';
+import {ClickModifiers} from 'chrome://resources/mojo/ui/base/mojom/window_open_disposition.mojom-webui.js';
+import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
+import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
 
-/** @implements {ReadLaterApiProxy} */
-export class TestReadLaterApiProxy extends TestBrowserProxy {
+export class TestReadLaterApiProxy extends TestBrowserProxy implements
+    ReadLaterApiProxy {
+  callbackRouter: PageCallbackRouter = new PageCallbackRouter();
+  private entries_: ReadLaterEntriesByStatus;
+
   constructor() {
     super([
       'getReadLaterEntries',
@@ -22,66 +26,54 @@
       'closeUI',
     ]);
 
-    /** @type {!PageCallbackRouter} */
-    this.callbackRouter = new PageCallbackRouter();
-
-    /** @private {!ReadLaterEntriesByStatus} */
-    this.entries_;
+    this.entries_ = {
+      unreadEntries: [],
+      readEntries: [],
+    };
   }
 
-  /** @override */
   getReadLaterEntries() {
     this.methodCalled('getReadLaterEntries');
     return Promise.resolve({entries: this.entries_});
   }
 
-  /** @override */
-  openURL(url, mark_as_read, click_info) {
-    this.methodCalled('openURL', [url, mark_as_read, click_info]);
+  openURL(url: Url, markAsRead: boolean, clickModifiers: ClickModifiers) {
+    this.methodCalled('openURL', [url, markAsRead, clickModifiers]);
   }
 
-  /** @override */
-  updateReadStatus(url, read) {
+  updateReadStatus(url: Url, read: boolean) {
     this.methodCalled('updateReadStatus', [url, read]);
   }
 
-  /** @override */
   addCurrentTab() {
     this.methodCalled('addCurrentTab');
   }
 
-  /** @override */
-  removeEntry(url) {
+  removeEntry(url: Url) {
     this.methodCalled('removeEntry', url);
   }
 
-  /** @override */
-  showContextMenuForURL(url, locationX, locationY) {
+  showContextMenuForURL(url: Url, locationX: number, locationY: number) {
     this.methodCalled('showContextMenuForURL', [url, locationX, locationY]);
   }
 
-  /** @override */
   updateCurrentPageActionButtonState() {
     this.methodCalled('updateCurrentPageActionButtonState');
   }
 
-  /** @override */
   showUI() {
     this.methodCalled('showUI');
   }
 
-  /** @override */
   closeUI() {
     this.methodCalled('closeUI');
   }
 
-  /** @override */
   getCallbackRouter() {
     return this.callbackRouter;
   }
 
-  /** @param {!ReadLaterEntriesByStatus} entries */
-  setEntries(entries) {
+  setEntries(entries: ReadLaterEntriesByStatus) {
     this.entries_ = entries;
   }
 }
diff --git a/chrome/test/data/webui/read_later/tsconfig_base.json b/chrome/test/data/webui/read_later/tsconfig_base.json
new file mode 100644
index 0000000..eeddfb3
--- /dev/null
+++ b/chrome/test/data/webui/read_later/tsconfig_base.json
@@ -0,0 +1,9 @@
+{
+  "extends": "../../../../../tools/typescript/tsconfig_base.json",
+  "compilerOptions": {
+    "allowJs": true,
+    "typeRoots": [
+       "./../../../../../third_party/node/node_modules/@types"
+    ]
+  }
+}
diff --git a/chrome/test/data/webui/signin/profile_picker_app_test.ts b/chrome/test/data/webui/signin/profile_picker_app_test.ts
index 939b5cb..8c9ca8e 100644
--- a/chrome/test/data/webui/signin/profile_picker_app_test.ts
+++ b/chrome/test/data/webui/signin/profile_picker_app_test.ts
@@ -102,9 +102,6 @@
 
   // <if expr="lacros">
   test('SignInPromoSignInWithAvailableAccountLacros', async function() {
-    loadTimeData.overrideValues({
-      isMultiProfileAccountConsistentcyLacrosEnabled: true,
-    });
     await resetTestElement(Routes.NEW_PROFILE);
     await waitForProfileCreationLoad();
     const choice =
@@ -136,9 +133,6 @@
   });
 
   test('SignInPromoSignInWithoutAccountLacros', async function() {
-    loadTimeData.overrideValues({
-      isMultiProfileAccountConsistentcyLacrosEnabled: true,
-    });
     await resetTestElement(Routes.NEW_PROFILE);
     await waitForProfileCreationLoad();
     const choice = testElement.shadowRoot!.querySelector('profile-type-choice');
diff --git a/chrome/test/nacl/nacl_browsertest.cc b/chrome/test/nacl/nacl_browsertest.cc
index e9935a3..62f25189 100644
--- a/chrome/test/nacl/nacl_browsertest.cc
+++ b/chrome/test/nacl/nacl_browsertest.cc
@@ -45,14 +45,6 @@
   RunLoadTest(FILE_PATH_LITERAL("nacl_load_test.html"));
 })
 
-IN_PROC_BROWSER_TEST_F(NaClBrowserTestNonSfiMode, MAYBE_NONSFI(Messaging)) {
-  RunLoadTest(FILE_PATH_LITERAL("libc_free.html"));
-}
-
-IN_PROC_BROWSER_TEST_F(NaClBrowserTestNonSfiMode, MAYBE_NONSFI(Irt)) {
-  RunNaClIntegrationTest(FILE_PATH_LITERAL("irt_test.html"));
-}
-
 NACL_BROWSER_TEST_F(NaClBrowserTest, ExitStatus0, {
   RunNaClIntegrationTest(FILE_PATH_LITERAL(
       "pm_exit_status_test.html?trigger=exit0&expected_exit=0"));
@@ -182,15 +174,6 @@
 IN_PROC_BROWSER_TEST_F(NaClBrowserTestNewlib, IrtManifestFile) {
   RunNaClIntegrationTest(FILE_PATH_LITERAL("irt_manifest_file_test.html"));
 }
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
-// http://crbug.com/579804
-#define MAYBE_IrtManifestFile DISABLED_IrtManifestFile
-#else
-#define MAYBE_IrtManifestFile MAYBE_PNACL_NONSFI(IrtManifestFile)
-#endif
-IN_PROC_BROWSER_TEST_F(NaClBrowserTestPnaclNonSfi, MAYBE_IrtManifestFile) {
-  RunNaClIntegrationTest(FILE_PATH_LITERAL("irt_manifest_file_test.html"));
-}
 
 #if defined(OS_WIN)
 // http://crbug.com/416272
@@ -201,15 +184,6 @@
 IN_PROC_BROWSER_TEST_F(NaClBrowserTestNewlib, MAYBE_IrtException) {
   RunNaClIntegrationTest(FILE_PATH_LITERAL("irt_exception_test.html"));
 }
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
-// http://crbug.com/579804
-#define MAYBE_IrtException2 DISABLED_IrtException
-#else
-#define MAYBE_IrtException2 MAYBE_PNACL_NONSFI(IrtException)
-#endif
-IN_PROC_BROWSER_TEST_F(NaClBrowserTestPnaclNonSfi, MAYBE_IrtException2) {
-  RunNaClIntegrationTest(FILE_PATH_LITERAL("irt_exception_test.html"));
-}
 
 // Some versions of Visual Studio does not like preprocessor
 // conditionals inside the argument of a macro, so we put the
diff --git a/chrome/test/nacl/nacl_browsertest_util.cc b/chrome/test/nacl/nacl_browsertest_util.cc
index b44fd02..e9c31c6 100644
--- a/chrome/test/nacl/nacl_browsertest_util.cc
+++ b/chrome/test/nacl/nacl_browsertest_util.cc
@@ -305,16 +305,6 @@
   command_line->AppendSwitch(switches::kForcePNaClSubzero);
 }
 
-base::FilePath::StringType NaClBrowserTestNonSfiMode::Variant() {
-  return FILE_PATH_LITERAL("libc-free");
-}
-
-void NaClBrowserTestNonSfiMode::SetUpCommandLine(
-    base::CommandLine* command_line) {
-  NaClBrowserTestBase::SetUpCommandLine(command_line);
-  command_line->AppendSwitch(switches::kEnableNaClNonSfiMode);
-}
-
 base::FilePath::StringType NaClBrowserTestStatic::Variant() {
   return FILE_PATH_LITERAL("static");
 }
@@ -324,16 +314,6 @@
   return true;
 }
 
-base::FilePath::StringType NaClBrowserTestPnaclNonSfi::Variant() {
-  return FILE_PATH_LITERAL("nonsfi");
-}
-
-void NaClBrowserTestPnaclNonSfi::SetUpCommandLine(
-    base::CommandLine* command_line) {
-  NaClBrowserTestBase::SetUpCommandLine(command_line);
-  command_line->AppendSwitch(switches::kEnableNaClNonSfiMode);
-}
-
 void NaClBrowserTestNewlibExtension::SetUpCommandLine(
     base::CommandLine* command_line) {
   NaClBrowserTestBase::SetUpCommandLine(command_line);
diff --git a/chrome/test/nacl/nacl_browsertest_util.h b/chrome/test/nacl/nacl_browsertest_util.h
index 82fe2de..7f7d279 100644
--- a/chrome/test/nacl/nacl_browsertest_util.h
+++ b/chrome/test/nacl/nacl_browsertest_util.h
@@ -135,18 +135,6 @@
   void SetUpCommandLine(base::CommandLine* command_line) override;
 };
 
-class NaClBrowserTestPnaclNonSfi : public NaClBrowserTestBase {
- public:
-  void SetUpCommandLine(base::CommandLine* command_line) override;
-  base::FilePath::StringType Variant() override;
-};
-
-class NaClBrowserTestNonSfiMode : public NaClBrowserTestBase {
- public:
-  void SetUpCommandLine(base::CommandLine* command_line) override;
-  base::FilePath::StringType Variant() override;
-};
-
 // A NaCl browser test only using static files.
 class NaClBrowserTestStatic : public NaClBrowserTestBase {
  public:
@@ -188,10 +176,6 @@
 #  define MAYBE_GLIBC(test_name) test_name
 #endif
 
-// TODO(crbug.com/1273132): Remove all code referenced by this.
-#define MAYBE_NONSFI(test_case) DISABLED_##test_case
-#define MAYBE_PNACL_NONSFI(test_case) DISABLED_##test_case
-
 #define NACL_BROWSER_TEST_F(suite, name, body) \
 IN_PROC_BROWSER_TEST_F(suite##Newlib, name) \
 body \
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index 6d5c8e7..86bef70 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -144,30 +144,18 @@
     }
 
 // NaCl based PPAPI tests
-#define TEST_PPAPI_NACL(test_name) \
-    TEST_PPAPI_NACL_NATIVE(test_name)                       \
-    IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, \
-                           MAYBE_PPAPI_PNACL(test_name)) { \
-      RunTestViaHTTP(STRIP_PREFIXES(test_name)); \
-    } \
-    IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest, \
-                           MAYBE_PNACL_NONSFI(test_name)) { \
-      RunTestViaHTTP(STRIP_PREFIXES(test_name)); \
-    }
+#define TEST_PPAPI_NACL(test_name)                                           \
+  TEST_PPAPI_NACL_NATIVE(test_name)                                          \
+  IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(test_name)) { \
+    RunTestViaHTTP(STRIP_PREFIXES(test_name));                               \
+  }
 
 // NaCl based PPAPI tests
-#define TEST_PPAPI_NACL_SUBTESTS(test_name, run_statement) \
-    IN_PROC_BROWSER_TEST_F(PPAPINaClNewlibTest, test_name) { \
-      run_statement; \
-    } \
-    IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, \
-                           MAYBE_PPAPI_PNACL(test_name)) { \
-      run_statement; \
-    } \
-    IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest, \
-                           MAYBE_PNACL_NONSFI(test_name)) { \
-      run_statement; \
-    }
+#define TEST_PPAPI_NACL_SUBTESTS(test_name, run_statement)                   \
+  IN_PROC_BROWSER_TEST_F(PPAPINaClNewlibTest, test_name) { run_statement; }  \
+  IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(test_name)) { \
+    run_statement;                                                           \
+  }
 
 // NaCl based PPAPI tests with disallowed socket API
 #define TEST_PPAPI_NACL_DISALLOWED_SOCKETS(test_name) \
@@ -176,18 +164,13 @@
     }
 
 // NaCl based PPAPI tests with SSL server
-#define TEST_PPAPI_NACL_WITH_SSL_SERVER(test_name) \
-    IN_PROC_BROWSER_TEST_F(PPAPINaClNewlibTest, test_name) { \
-      RunTestWithSSLServer(STRIP_PREFIXES(test_name)); \
-    } \
-    IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, \
-                           MAYBE_PPAPI_PNACL(test_name)) { \
-      RunTestWithSSLServer(STRIP_PREFIXES(test_name)); \
-    } \
-    IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest, \
-                           MAYBE_PNACL_NONSFI(test_name)) { \
-      RunTestWithSSLServer(STRIP_PREFIXES(test_name)); \
-    }
+#define TEST_PPAPI_NACL_WITH_SSL_SERVER(test_name)                           \
+  IN_PROC_BROWSER_TEST_F(PPAPINaClNewlibTest, test_name) {                   \
+    RunTestWithSSLServer(STRIP_PREFIXES(test_name));                         \
+  }                                                                          \
+  IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(test_name)) { \
+    RunTestWithSSLServer(STRIP_PREFIXES(test_name));                         \
+  }
 
 #endif  // !BUILDFLAG(ENABLE_NACL)
 
@@ -261,10 +244,6 @@
   }                                                                      \
   IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(_test)) { \
     RunTestViaHTTP(LIST_TEST(_test));                                    \
-  }                                                                      \
-  IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,                       \
-                         MAYBE_PNACL_NONSFI(_test)) {                    \
-    RunTestViaHTTP(LIST_TEST(_test));                                    \
   }
 
 // Split tests into multiple tests, making it easier to isolate which tests are
@@ -841,10 +820,6 @@
   }                                                                          \
   IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(test_name)) { \
     RUN_TCP_FAILURE_TEST(_test, failure_type);                               \
-  }                                                                          \
-  IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,                           \
-                         MAYBE_PNACL_NONSFI(test_name)) {                    \
-    RUN_TCP_FAILURE_TEST(_test, failure_type);                               \
   }
 
 TCP_SOCKET_FAILURE_TEST(TCPSocket_ConnectClosePipe,
@@ -1203,10 +1178,6 @@
   }                                                                          \
   IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(test_name)) { \
     RUN_UDP_FAILURE_TEST(_test, failure_type);                               \
-  }                                                                          \
-  IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,                           \
-                         MAYBE_PNACL_NONSFI(test_name)) {                    \
-    RUN_UDP_FAILURE_TEST(_test, failure_type);                               \
   }
 
 UDPSOCKET_FAILURE_TEST(UDPSocket_BindError,
@@ -1322,10 +1293,6 @@
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(HostResolver)) {
   RUN_HOST_RESOLVER_SUBTESTS;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(HostResolver)) {
-  RUN_HOST_RESOLVER_SUBTESTS;
-}
 
 TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(HostResolverPrivate_Resolve)
 TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(HostResolverPrivate_ResolveIPv4)
@@ -1450,13 +1417,6 @@
   RUN_URLLOADER_SUBTESTS_3;
 }
 
-// Flaky on 32-bit linux bot; http://crbug.com/308906
-#if (defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(ARCH_CPU_X86)
-#define MAYBE_URLLoader_BasicFilePOST DISABLED_URLLoader_BasicFilePOST
-#else
-#define MAYBE_URLLoader_BasicFilePOST URLLoader_BasicFilePOST
-#endif
-
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(URLLoader0)) {
   RUN_URLLOADER_SUBTESTS_0;
 }
@@ -1469,23 +1429,6 @@
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(URLLoader3)) {
   RUN_URLLOADER_SUBTESTS_3;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(URLLoader0)) {
-  RUN_URLLOADER_SUBTESTS_0;
-}
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(URLLoader1)) {
-  RUN_URLLOADER_SUBTESTS_1;
-}
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(URLLoader2)) {
-  RUN_URLLOADER_SUBTESTS_2;
-}
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(URLLoader3)) {
-  RUN_URLLOADER_SUBTESTS_3;
-}
-
 
 // URLRequestInfo tests.
 TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(URLRequest_CreateAndIsURLRequestInfo)
@@ -1575,10 +1518,6 @@
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(PostMessage)) {
   RUN_POSTMESSAGE_SUBTESTS;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(PostMessage)) {
-  RUN_POSTMESSAGE_SUBTESTS;
-}
 
 TEST_PPAPI_NACL(Memory)
 
@@ -1634,14 +1573,6 @@
   RUN_FILEIO_PRIVATE_SUBTESTS;
 }
 
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest, MAYBE_PNACL_NONSFI(FileIO)) {
-  RUN_FILEIO_SUBTESTS;
-}
-IN_PROC_BROWSER_TEST_F(PPAPIPrivateNaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(FILEIO_Private)) {
-  RUN_FILEIO_PRIVATE_SUBTESTS;
-}
-
 #define SETUP_FOR_FILEREF_TESTS                                              \
   const char kContents[] = "Hello from browser";                             \
   base::ScopedAllowBlockingForTesting allow_blocking;                        \
@@ -1705,14 +1636,6 @@
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(FileRef2)) {
   RUN_FILEREF_SUBTESTS_2;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(FileRef1)) {
-  RUN_FILEREF_SUBTESTS_1;
-}
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(FileRef2)) {
-  RUN_FILEREF_SUBTESTS_2;
-}
 
 TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(FileSystem)
 
@@ -1764,10 +1687,6 @@
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(NetAddress)) {
   RUN_NETADDRESS_SUBTESTS;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(NetAddress)) {
-  RUN_NETADDRESS_SUBTESTS;
-}
 
 // NetAddressPrivate tests.
 #define RUN_NETADDRESS_PRIVATE_SUBTESTS \
@@ -1808,10 +1727,6 @@
                        MAYBE_PPAPI_PNACL(NetAddressPrivate)) {
   RUN_NETADDRESS_PRIVATE_UNTRUSTED_SUBTESTS;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(NetAddressPrivate)) {
-  RUN_NETADDRESS_PRIVATE_UNTRUSTED_SUBTESTS;
-}
 
 // NetworkMonitor tests.
 #define RUN_NETWORK_MONITOR_SUBTESTS \
@@ -1831,10 +1746,6 @@
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(NetworkMonitor)) {
   RUN_NETWORK_MONITOR_SUBTESTS;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(NetworkMonitor)) {
-  RUN_NETWORK_MONITOR_SUBTESTS;
-}
 
 // In-process WebSocket tests. Note, the WebSocket tests are split into two,
 // because all of them together sometimes take too long on windows:
@@ -1894,14 +1805,6 @@
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(WebSocket2)) {
   RUN_WEBSOCKET_SUBTESTS_2;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(WebSocket1)) {
-  RUN_WEBSOCKET_SUBTESTS_1;
-}
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(WebSocket2)) {
-  RUN_WEBSOCKET_SUBTESTS_2;
-}
 
 // AudioConfig tests
 #define RUN_AUDIO_CONFIG_SUBTESTS \
@@ -1923,10 +1826,6 @@
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(AudioConfig)) {
   RUN_AUDIO_CONFIG_SUBTESTS;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(AudioConfig)) {
-  RUN_AUDIO_CONFIG_SUBTESTS;
-}
 
 // PPB_Audio tests.
 #define RUN_AUDIO_SUBTESTS \
@@ -1960,10 +1859,6 @@
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(MAYBE_Audio)) {
   RUN_AUDIO_SUBTESTS;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(MAYBE_Audio)) {
-  RUN_AUDIO_SUBTESTS;
-}
 
 #define RUN_AUDIO_THREAD_CREATOR_SUBTESTS \
   RunTestViaHTTP( \
@@ -1986,10 +1881,6 @@
                        MAYBE_PPAPI_PNACL(MAYBE_AudioThreadCreator)) {
   RUN_AUDIO_THREAD_CREATOR_SUBTESTS;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest,
-                       MAYBE_PNACL_NONSFI(MAYBE_AudioThreadCreator)) {
-  RUN_AUDIO_THREAD_CREATOR_SUBTESTS;
-}
 
 TEST_PPAPI_OUT_OF_PROCESS(View_CreatedVisible)
 #if defined(OS_MAC)
@@ -2086,9 +1977,6 @@
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(View)) {
   RUN_VIEW_SUBTESTS;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest, MAYBE_PNACL_NONSFI(View)) {
-  RUN_VIEW_SUBTESTS;
-}
 
 // The compositor test timeouts sometimes, so we have to split it to two
 // subtests.
@@ -2227,16 +2115,6 @@
   NewlibPackagedAppTest() : PackagedAppTest("newlib") { }
 };
 
-class NonSfiPackagedAppTest : public PackagedAppTest {
- public:
-  NonSfiPackagedAppTest() : PackagedAppTest("nonsfi") { }
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    PackagedAppTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(switches::kEnableNaClNonSfiMode);
-  }
-};
-
 // Load a packaged app, and wait for it to successfully post a "hello" message
 // back.
 #if defined(OS_WIN) || !defined(NDEBUG) || defined(OS_MAC)
@@ -2250,16 +2128,6 @@
   RunTests("packaged_app");
 }
 
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
-// http://crbug.com/579804
-#define MAYBE_SuccessfulLoad DISABLED_SuccessfulLoad
-#else
-#define MAYBE_SuccessfulLoad MAYBE_PNACL_NONSFI(SuccessfulLoad)
-#endif
-IN_PROC_BROWSER_TEST_F(NonSfiPackagedAppTest, MAYBE_SuccessfulLoad) {
-  RunTests("packaged_app");
-}
-
 IN_PROC_BROWSER_TEST_F(NewlibPackagedAppTest,
                        MAYBE_PPAPI_NACL(MulticastPermissions)) {
   RunTests("multicast_permissions");
diff --git a/chrome/test/ppapi/ppapi_test.cc b/chrome/test/ppapi/ppapi_test.cc
index f056d11..2badae7 100644
--- a/chrome/test/ppapi/ppapi_test.cc
+++ b/chrome/test/ppapi/ppapi_test.cc
@@ -465,27 +465,6 @@
   AddPrivateSwitches(command_line);
 }
 
-void PPAPINaClPNaClNonSfiTest::SetUpCommandLine(
-    base::CommandLine* command_line) {
-  PPAPINaClTest::SetUpCommandLine(command_line);
-#if BUILDFLAG(ENABLE_NACL)
-  command_line->AppendSwitch(switches::kEnableNaClNonSfiMode);
-#endif
-}
-
-std::string PPAPINaClPNaClNonSfiTest::BuildQuery(
-    const std::string& base,
-    const std::string& test_case) {
-  return base::StringPrintf("%smode=nacl_pnacl_nonsfi&testcase=%s",
-                            base.c_str(), test_case.c_str());
-}
-
-void PPAPIPrivateNaClPNaClNonSfiTest::SetUpCommandLine(
-    base::CommandLine* command_line) {
-  PPAPINaClPNaClNonSfiTest::SetUpCommandLine(command_line);
-  AddPrivateSwitches(command_line);
-}
-
 void PPAPINaClTestDisallowedSockets::SetUpCommandLine(
     base::CommandLine* command_line) {
   PPAPITestBase::SetUpCommandLine(command_line);
diff --git a/chrome/updater/tools/tag.py b/chrome/updater/tools/tag.py
index 9d82206..388a60d44 100755
--- a/chrome/updater/tools/tag.py
+++ b/chrome/updater/tools/tag.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # 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.
diff --git a/chrome/updater/win/signing/sign.py b/chrome/updater/win/signing/sign.py
index 420fff8..75a6fd5 100755
--- a/chrome/updater/win/signing/sign.py
+++ b/chrome/updater/win/signing/sign.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # 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.
diff --git a/chromeos/components/tether/persistent_host_scan_cache_impl.cc b/chromeos/components/tether/persistent_host_scan_cache_impl.cc
index 0b702d0..038f5ba 100644
--- a/chromeos/components/tether/persistent_host_scan_cache_impl.cc
+++ b/chromeos/components/tether/persistent_host_scan_cache_impl.cc
@@ -78,11 +78,12 @@
   }
   builder.SetSignalStrength(signal_strength);
 
-  bool setup_required;
-  if (!dictionary.GetBoolean(kSetupRequiredKey, &setup_required)) {
+  absl::optional<bool> setup_required =
+      dictionary.FindBoolPath(kSetupRequiredKey);
+  if (!setup_required)
     return nullptr;
-  }
-  builder.SetSetupRequired(setup_required);
+
+  builder.SetSetupRequired(*setup_required);
 
   return builder.Build();
 }
diff --git a/components/arc/mojom/BUILD.gn b/components/arc/mojom/BUILD.gn
index 1975418..4d54f3f 100644
--- a/components/arc/mojom/BUILD.gn
+++ b/components/arc/mojom/BUILD.gn
@@ -15,18 +15,7 @@
       "anr.mojom",
       "app.mojom",
       "app_permissions.mojom",
-      "backup_settings.mojom",
-      "bluetooth.mojom",
-      "boot_phase_monitor.mojom",
-      "camera.mojom",
-      "cast_receiver.mojom",
-      "cert_store.mojom",
-      "clipboard.mojom",
       "compatibility_mode.mojom",
-      "crash_collector.mojom",
-      "dark_theme.mojom",
-      "digital_goods.mojom",
-      "disk_quota.mojom",
       "enterprise_reporting.mojom",
       "file_system.mojom",
       "iio_sensor.mojom",
@@ -103,41 +92,6 @@
       {
         types = [
           {
-            mojom = "arc.mojom.BluetoothDeviceType"
-            cpp = "::device::BluetoothTransport"
-          },
-          {
-            mojom = "arc.mojom.BluetoothSdpAttributeType"
-            cpp = "::bluez::BluetoothServiceAttributeValueBlueZ::Type"
-          },
-          {
-            mojom = "arc.mojom.BluetoothUUID"
-            cpp = "::device::BluetoothUUID"
-          },
-          {
-            mojom = "arc.mojom.BluetoothAdvertisement"
-            cpp = "::std::unique_ptr<::device::BluetoothAdvertisement::Data>"
-            move_only = true
-          },
-        ]
-        traits_headers = [
-          "//device/bluetooth/bluetooth_advertisement.h",
-          "//device/bluetooth/bluetooth_common.h",
-          "//device/bluetooth/public/cpp/bluetooth_uuid.h",
-          "//device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h",
-        ]
-        traits_private_headers =
-            [ "//ash/components/arc/bluetooth/bluetooth_mojom_traits.h" ]
-        traits_sources =
-            [ "//ash/components/arc/bluetooth/bluetooth_mojom_traits.cc" ]
-        traits_public_deps = [
-          "//device/bluetooth",
-          "//device/bluetooth/public/cpp",
-        ]
-      },
-      {
-        types = [
-          {
             mojom = "arc.mojom.ChangeType"
             cpp = "::storage::WatcherManager::ChangeType"
           },
diff --git a/components/dbus/menu/BUILD.gn b/components/dbus/menu/BUILD.gn
index 9361184..672687e 100644
--- a/components/dbus/menu/BUILD.gn
+++ b/components/dbus/menu/BUILD.gn
@@ -38,6 +38,10 @@
     "//testing/gtest",
   ]
   if (use_ozone) {
-    deps += [ "//ui/ozone" ]
+    deps += [
+      "//ui/events:test_support",
+      "//ui/events/ozone/layout:layout",
+      "//ui/ozone",
+    ]
   }
 }
diff --git a/components/dbus/menu/DEPS b/components/dbus/menu/DEPS
index 1afde18eb..435d1b3 100644
--- a/components/dbus/menu/DEPS
+++ b/components/dbus/menu/DEPS
@@ -1,7 +1,7 @@
 include_rules = [
   "+dbus",
   "+ui/base",
-  "+ui/events/keycodes",
+  "+ui/events",
   "+ui/gfx/image",
   "+ui/gfx/x",
   "+ui/ozone/public",
diff --git a/components/dbus/menu/menu_property_list_unittest.cc b/components/dbus/menu/menu_property_list_unittest.cc
index f9d8f2a..d406b34 100644
--- a/components/dbus/menu/menu_property_list_unittest.cc
+++ b/components/dbus/menu/menu_property_list_unittest.cc
@@ -16,6 +16,8 @@
 #include "ui/base/models/menu_model.h"
 #include "ui/base/models/menu_separator_types.h"
 #include "ui/base/models/simple_menu_model.h"
+#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
+#include "ui/events/test/keyboard_layout.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_rep_default.h"
@@ -325,33 +327,43 @@
 
 #if defined(OS_LINUX)
 TEST(MenuPropertyListTest, ComputePropertiesAccelerator) {
-  // TODO(1136791): fix for Ozone/Wayland.
-  if (ui::OzonePlatform::GetPlatformNameForTest() != "x11")
-    GTEST_SKIP();
+  // The Wayland implementation requires the keyboard layout to be set.
+  // The ScopedKeyboardLayout does not unset the already existing layout engine,
+  // so we do so here and restore in the end of the test.
+  auto* const old_layout =
+      ui::KeyboardLayoutEngineManager::GetKeyboardLayoutEngine();
+  ui::KeyboardLayoutEngineManager::ResetKeyboardLayoutEngine();
 
-  auto builder = TestMenuModelBuilder();
+  {
+    ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
 
-  // No accelerator.
-  auto menu = builder.SetAccelerator(ui::Accelerator()).Build();
-  MenuItemProperties props;
-  EXPECT_EQ(menu->ComputeProperties(), props);
+    auto builder = TestMenuModelBuilder();
 
-  // Set a key.
-  menu = builder.SetAccelerator(ui::Accelerator(ui::VKEY_A, 0)).Build();
-  props["shortcut"] =
-      MakeDbusVariant(MakeDbusArray(MakeDbusArray(DbusString("a"))));
-  EXPECT_EQ(menu->ComputeProperties(), props);
+    // No accelerator.
+    auto menu = builder.SetAccelerator(ui::Accelerator()).Build();
+    MenuItemProperties props;
+    EXPECT_EQ(menu->ComputeProperties(), props);
 
-  // Add modifiers.
-  menu = builder
-             .SetAccelerator(ui::Accelerator(
-                 ui::VKEY_A,
-                 ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN))
-             .Build();
-  props["shortcut"] = MakeDbusVariant(
-      MakeDbusArray(MakeDbusArray(DbusString("Control"), DbusString("Alt"),
-                                  DbusString("Shift"), DbusString("a"))));
-  EXPECT_EQ(menu->ComputeProperties(), props);
+    // Set a key.
+    menu = builder.SetAccelerator(ui::Accelerator(ui::VKEY_A, 0)).Build();
+    props["shortcut"] =
+        MakeDbusVariant(MakeDbusArray(MakeDbusArray(DbusString("a"))));
+    EXPECT_EQ(menu->ComputeProperties(), props);
+
+    // Add modifiers.
+    menu = builder
+               .SetAccelerator(ui::Accelerator(
+                   ui::VKEY_A,
+                   ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN))
+               .Build();
+    props["shortcut"] = MakeDbusVariant(
+        MakeDbusArray(MakeDbusArray(DbusString("Control"), DbusString("Alt"),
+                                    DbusString("Shift"), DbusString("a"))));
+    EXPECT_EQ(menu->ComputeProperties(), props);
+  }
+
+  if (old_layout)
+    ui::KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(old_layout);
 }
 #endif
 
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java
index 4d3c4a0d..025e4ca 100644
--- a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java
+++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java
@@ -130,7 +130,7 @@
         redirectHandler.updateNewUrlLoading(navigationParams.pageTransitionType,
                 navigationParams.isRedirect,
                 navigationParams.hasUserGesture || navigationParams.hasUserGestureCarryover,
-                lastUserInteractionTime, getLastCommittedEntryIndex());
+                lastUserInteractionTime, getLastCommittedEntryIndex(), isInitialNavigation());
 
         boolean shouldCloseTab = shouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent();
         ExternalNavigationParams params =
@@ -230,18 +230,21 @@
         return mClient.getWebContents().getNavigationController().getLastCommittedEntryIndex();
     }
 
+    private boolean isInitialNavigation() {
+        if (mClient.getWebContents() == null) return true;
+        return mClient.getWebContents().getNavigationController().isInitialNavigation();
+    }
+
     private boolean shouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent() {
         if (mClient.getWebContents() == null) return false;
-        if (!mClient.getWebContents().getNavigationController().canGoToOffset(0)) return true;
+        // If no navigation has committed, close the tab.
+        if (mClient.getWebContents().getLastCommittedUrl().isEmpty()) return true;
 
-        // http://crbug/415948 : if the last committed entry index which was saved before this
-        // navigation is invalid, it means that this navigation is the first one since this tab was
-        // created.
+        // http://crbug/415948: If the user has not started a non-initial
+        // navigation, this might be a JS redirect.
         // In such case, we would like to close this tab.
         if (mClient.getOrCreateRedirectHandler().isOnNavigation()) {
-            return mClient.getOrCreateRedirectHandler()
-                           .getLastCommittedEntryIndexBeforeStartingNavigation()
-                    == RedirectHandler.INVALID_ENTRY_INDEX;
+            return !mClient.getOrCreateRedirectHandler().hasUserStartedNonInitialNavigation();
         }
         return false;
     }
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandler.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandler.java
index d2ddd40..d16d0f9 100644
--- a/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandler.java
+++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandler.java
@@ -46,6 +46,7 @@
     private boolean mIsOnEffectiveRedirectChain;
     private int mInitialNavigationType;
     private int mLastCommittedEntryIndexBeforeStartingNavigation;
+    private boolean mHasUserStartedNonInitialNavigation;
 
     private boolean mShouldNotOverrideUrlLoadingOnCurrentRedirectChain;
     private boolean mShouldNotBlockOverrideUrlLoadingOnCurrentRedirectionChain;
@@ -114,6 +115,7 @@
         mInitialNavigationType = NAVIGATION_TYPE_NONE;
         mIsOnEffectiveRedirectChain = false;
         mLastCommittedEntryIndexBeforeStartingNavigation = 0;
+        mHasUserStartedNonInitialNavigation = false;
         mShouldNotOverrideUrlLoadingOnCurrentRedirectChain = false;
         mShouldNotBlockOverrideUrlLoadingOnCurrentRedirectionChain = false;
     }
@@ -160,9 +162,11 @@
      * @param hasUserGesture whether this loading is started by a user gesture.
      * @param lastUserInteractionTime time when the last user interaction was made.
      * @param lastCommittedEntryIndex the last committed entry index right before this loading.
+     * @param isInitialNavigation whether this loading is for the initial navigation.
      */
     public void updateNewUrlLoading(int pageTransType, boolean isRedirect, boolean hasUserGesture,
-            long lastUserInteractionTime, int lastCommittedEntryIndex) {
+            long lastUserInteractionTime, int lastCommittedEntryIndex,
+            boolean isInitialNavigation) {
         long prevNewUrlLoadingTime = mLastNewUrlLoadingTime;
         mLastNewUrlLoadingTime = SystemClock.elapsedRealtime();
 
@@ -202,6 +206,9 @@
             }
             mIsOnEffectiveRedirectChain = false;
             mLastCommittedEntryIndexBeforeStartingNavigation = lastCommittedEntryIndex;
+            if (!isInitialNavigation) {
+                mHasUserStartedNonInitialNavigation = true;
+            }
             mShouldNotOverrideUrlLoadingOnCurrentRedirectChain = false;
             mShouldNotBlockOverrideUrlLoadingOnCurrentRedirectionChain = false;
         } else if (mInitialNavigationType != NAVIGATION_TYPE_NONE) {
@@ -303,6 +310,13 @@
     }
 
     /**
+     * @return whether the user has started a non-initial navigation.
+     */
+    public boolean hasUserStartedNonInitialNavigation() {
+        return mHasUserStartedNonInitialNavigation;
+    }
+
+    /**
      * @return whether |intent| has a new resolver against |mIntentHistory| or not.
      */
     public boolean hasNewResolver(List<ResolveInfo> resolvingInfos,
diff --git a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
index 0b63551..3ec502af 100644
--- a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
+++ b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
@@ -218,7 +218,7 @@
         mDelegate.add(new IntentActivity(YOUTUBE_URL, YOUTUBE_PACKAGE_NAME));
 
         RedirectHandler handler = RedirectHandler.create();
-        handler.updateNewUrlLoading(PageTransition.CLIENT_REDIRECT, false, false, 0, 0);
+        handler.updateNewUrlLoading(PageTransition.CLIENT_REDIRECT, false, false, 0, 0, false);
 
         checkUrl(YOUTUBE_URL)
                 .withRedirectHandler(handler)
@@ -593,8 +593,8 @@
         // have any new resolver.
         redirectHandler.updateIntent(ytIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
                 IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED, !INTENT_STARTED_TASK);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0, false);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withPageTransition(transTypeLinkFromIntent)
                 .withIsRedirect(true)
@@ -604,8 +604,8 @@
         // Do not ignore if a new intent has any new resolver.
         redirectHandler.updateIntent(fooIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
                 IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED, !INTENT_STARTED_TASK);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0, false);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withPageTransition(transTypeLinkFromIntent)
                 .withIsRedirect(true)
@@ -616,8 +616,8 @@
         // Do not ignore if a new intent cannot be handled by Chrome.
         redirectHandler.updateIntent(fooIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
                 IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED, !INTENT_STARTED_TASK);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0, false);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0, false);
         checkUrl("intent://myownurl")
                 .withPageTransition(transTypeLinkFromIntent)
                 .withIsRedirect(true)
@@ -639,8 +639,8 @@
         // Ignore if an initial Intent was heading to Chrome.
         redirectHandler.updateIntent(fooIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
                 IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED, !INTENT_STARTED_TASK);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0, false);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withPageTransition(transTypeLinkFromIntent)
                 .withIsRedirect(true)
@@ -650,8 +650,8 @@
         // Do not ignore if the URI has an external protocol.
         redirectHandler.updateIntent(fooIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
                 IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED, !INTENT_STARTED_TASK);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0, false);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0, false);
         checkUrl("market://1234")
                 .withPageTransition(transTypeLinkFromIntent)
                 .withIsRedirect(true)
@@ -673,7 +673,7 @@
         barIntent.setPackage(mContext.getPackageName());
         redirectHandler.updateIntent(barIntent, IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
                 IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED, !INTENT_STARTED_TASK);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0, false);
         checkUrl(YOUTUBE_URL)
                 .withPageTransition(transTypeLinkFromIntent)
                 .withRedirectHandler(redirectHandler)
@@ -684,8 +684,8 @@
         fooIntent.setPackage(mContext.getPackageName());
         redirectHandler.updateIntent(fooIntent, IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
                 IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED, !INTENT_STARTED_TASK);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0, false);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0, false);
         checkUrl(YOUTUBE_URL)
                 .withPageTransition(transTypeLinkFromIntent)
                 .withIsRedirect(true)
@@ -698,8 +698,8 @@
         extraIntent2.setPackage(mContext.getPackageName());
         redirectHandler.updateIntent(extraIntent2, IS_CUSTOM_TAB_INTENT, SEND_TO_EXTERNAL_APPS,
                 IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED, !INTENT_STARTED_TASK);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0, false);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0, false);
         checkUrl(YOUTUBE_URL)
                 .withPageTransition(transTypeLinkFromIntent)
                 .withIsRedirect(true)
@@ -711,8 +711,8 @@
         extraIntent3.setPackage(mContext.getPackageName());
         redirectHandler.updateIntent(extraIntent3, IS_CUSTOM_TAB_INTENT, SEND_TO_EXTERNAL_APPS,
                 IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED, !INTENT_STARTED_TASK);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0, false);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0, false);
         checkUrl(YOUTUBE_URL)
                 .withPageTransition(transTypeLinkFromIntent)
                 .withIsRedirect(true)
@@ -723,10 +723,10 @@
         // External intent for a user-initiated navigation should always be allowed.
         redirectHandler.updateIntent(fooIntent, IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
                 IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED, !INTENT_STARTED_TASK);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0, false);
         // Simulate a real user navigation.
         redirectHandler.updateNewUrlLoading(
-                PageTransition.LINK, false, true, SystemClock.elapsedRealtime() + 1, 0);
+                PageTransition.LINK, false, true, SystemClock.elapsedRealtime() + 1, 0, false);
         checkUrl(YOUTUBE_URL)
                 .withPageTransition(PageTransition.LINK)
                 .withRedirectHandler(redirectHandler)
@@ -747,8 +747,8 @@
         fooIntent.setPackage(mContext.getPackageName());
         redirectHandler.updateIntent(fooIntent, IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
                 IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED, !INTENT_STARTED_TASK);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0, false);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0, false);
 
         mDelegate.setCanHandleWithInstantApp(true);
         checkUrl("http://instantappenabled.com")
@@ -808,8 +808,8 @@
                 Intent.parseUri("http://instantappenabled.com", Intent.URI_INTENT_SCHEME);
         redirectHandler.updateIntent(fooIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
                 IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED, !INTENT_STARTED_TASK);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
-        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0, false);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0, false);
 
         mDelegate.setCanHandleWithInstantApp(true);
         checkUrl("http://goo.gl/1234")
@@ -1232,7 +1232,7 @@
         mDelegate.setCanResolveActivityForExternalSchemes(false);
 
         RedirectHandler redirectHandler = RedirectHandler.create();
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0, false);
         String intent = "intent:///name/nm0000158#Intent;scheme=imdb;package=com.imdb.mobile;"
                 + "S." + ExternalNavigationHandler.EXTRA_BROWSER_FALLBACK_URL + "="
                 + "https://play.google.com/store/apps/details?id=com.imdb.mobile"
@@ -1248,7 +1248,7 @@
                 mDelegate.startActivityIntent.getDataString());
 
         redirectHandler = RedirectHandler.create();
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0, false);
         String intentBadUrl = "intent:///name/nm0000158#Intent;scheme=imdb;package=com.imdb.mobile;"
                 + "S." + ExternalNavigationHandler.EXTRA_BROWSER_FALLBACK_URL + "="
                 + "https://play.google.com/store/search?q=pub:imdb;end";
@@ -1267,13 +1267,13 @@
 
         RedirectHandler redirectHandler = RedirectHandler.create();
 
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0, false);
         checkUrl("http://goo.gl/abcdefg")
                 .withPageTransition(PageTransition.LINK)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
 
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, true, true, 0, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, true, true, 0, 0, false);
         String realIntent = "intent:///name/nm0000158#Intent;scheme=imdb;package=com.imdb.mobile;"
                 + "S." + ExternalNavigationHandler.EXTRA_BROWSER_FALLBACK_URL + "="
                 + "https://play.google.com/store/apps/details?id=com.imdb.mobile"
@@ -1299,7 +1299,7 @@
         mDelegate.add(new IntentActivity(IMDB_WEBPAGE_FOR_TOM_HANKS, WEBAPK_PACKAGE_NAME));
 
         RedirectHandler redirectHandler = RedirectHandler.create();
-        redirectHandler.updateNewUrlLoading(PageTransition.AUTO_SUBFRAME, true, true, 0, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.AUTO_SUBFRAME, true, true, 0, 0, false);
 
         checkUrl(INTENT_URL_WITH_FALLBACK_URL)
                 .withIsMainFrame(false)
@@ -1316,7 +1316,7 @@
         mDelegate.add(new IntentActivity(IMDB_WEBPAGE_FOR_TOM_HANKS, WEBAPK_PACKAGE_NAME));
 
         RedirectHandler redirectHandler = RedirectHandler.create();
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 0, false);
 
         checkUrl(INTENT_URL_WITH_FALLBACK_URL)
                 .withHasUserGesture(false)
@@ -1385,19 +1385,19 @@
 
         RedirectHandler redirectHandler = RedirectHandler.create();
 
-        redirectHandler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0, false);
         checkUrl("http://goo.gl/abcdefg")
                 .withPageTransition(PageTransition.TYPED)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
 
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 0, false);
         checkUrl(INTENT_URL_WITH_FALLBACK_URL_WITHOUT_PACKAGE_NAME)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
 
         // Now the user opens a link.
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 1);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 1, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
@@ -1411,7 +1411,7 @@
 
         RedirectHandler redirectHandler = RedirectHandler.create();
 
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0, false);
         checkUrl(INTENT_URL_WITH_CHAIN_FALLBACK_URL)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
@@ -1420,7 +1420,7 @@
         // The fall-back URL was HTTP-schemed, but it was effectively redirected to a new intent
         // URL using javascript. However, we do not allow chained fallback intent, so we do NOT
         // override URL loading here.
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 0, false);
         checkUrl(INTENT_URL_WITH_FALLBACK_URL)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
@@ -1432,7 +1432,7 @@
         // systemclock or pass the new time as parameter.
         long lastUserInteractionTimeInMillis = SystemClock.elapsedRealtime() + 2 * 1000L;
         redirectHandler.updateNewUrlLoading(
-                PageTransition.LINK, false, true, lastUserInteractionTimeInMillis, 1);
+                PageTransition.LINK, false, true, lastUserInteractionTimeInMillis, 1, false);
         checkUrl(INTENT_URL_WITH_FALLBACK_URL)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
@@ -1445,20 +1445,20 @@
 
         RedirectHandler redirectHandler = RedirectHandler.create();
 
-        redirectHandler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withPageTransition(PageTransition.TYPED)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
 
-        redirectHandler.updateNewUrlLoading(PageTransition.TYPED, true, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.TYPED, true, false, 0, 0, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withPageTransition(PageTransition.TYPED)
                 .withIsRedirect(true)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
 
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
@@ -1471,18 +1471,18 @@
 
         RedirectHandler redirectHandler = RedirectHandler.create();
 
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 1, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 1, 0, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
 
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, true, false, 1, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, true, false, 1, 0, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withIsRedirect(true)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
 
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 1, 1);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 1, 1, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
@@ -1697,18 +1697,18 @@
 
         RedirectHandler redirectHandler = RedirectHandler.create();
 
-        redirectHandler.updateNewUrlLoading(PageTransition.RELOAD, false, false, 1, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.RELOAD, false, false, 1, 0, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
 
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, true, false, 1, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, true, false, 1, 0, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withIsRedirect(true)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
 
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 1, 1);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 1, 1, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
@@ -1722,18 +1722,19 @@
         RedirectHandler redirectHandler = RedirectHandler.create();
 
         redirectHandler.updateNewUrlLoading(
-                PageTransition.FORM_SUBMIT | PageTransition.FORWARD_BACK, false, false, 1, 0);
+                PageTransition.FORM_SUBMIT | PageTransition.FORWARD_BACK, false, false, 1, 0,
+                false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
 
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, true, false, 1, 0);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, true, false, 1, 0, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withIsRedirect(true)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
 
-        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 1, 1);
+        redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 1, 1, false);
         checkUrl(YOUTUBE_MOBILE_URL)
                 .withRedirectHandler(redirectHandler)
                 .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
diff --git a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java
index 4d505927..4926f24 100644
--- a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java
+++ b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java
@@ -75,9 +75,9 @@
         handler.updateIntent(sYtIntent, false, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
-        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
+        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0, false);
         Assert.assertFalse(handler.isOnEffectiveIntentRedirectChain());
-        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, true, false, 0, 0);
+        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, true, false, 0, 0, false);
         Assert.assertTrue(handler.isOnEffectiveIntentRedirectChain());
         Assert.assertFalse(handler.hasNewResolver(
                 queryIntentActivities(sMoblieYtIntent), mQueryIntentFunction));
@@ -98,9 +98,9 @@
         handler.updateIntent(sYtIntent, false, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
-        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
+        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0, false);
         Assert.assertFalse(handler.isOnEffectiveIntentRedirectChain());
-        handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1);
+        handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1, false);
         Assert.assertTrue(handler.isOnEffectiveIntentRedirectChain());
         Assert.assertFalse(handler.hasNewResolver(
                 queryIntentActivities(sMoblieYtIntent), mQueryIntentFunction));
@@ -121,9 +121,9 @@
         handler.updateIntent(sYtIntent, false, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
-        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
+        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0, false);
         Assert.assertFalse(handler.isOnEffectiveIntentRedirectChain());
-        handler.updateNewUrlLoading(PageTransition.FORM_SUBMIT, false, false, 0, 1);
+        handler.updateNewUrlLoading(PageTransition.FORM_SUBMIT, false, false, 0, 1, false);
         Assert.assertTrue(handler.isOnEffectiveIntentRedirectChain());
         Assert.assertFalse(handler.hasNewResolver(
                 queryIntentActivities(sMoblieYtIntent), mQueryIntentFunction));
@@ -144,9 +144,9 @@
         handler.updateIntent(null, false, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
-        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
+        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0, false);
         Assert.assertFalse(handler.isOnEffectiveIntentRedirectChain());
-        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, true, false, 0, 0);
+        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, true, false, 0, 0, false);
         Assert.assertFalse(handler.isOnEffectiveIntentRedirectChain());
         Assert.assertTrue(handler.hasNewResolver(
                 queryIntentActivities(sMoblieYtIntent), mQueryIntentFunction));
@@ -167,9 +167,9 @@
         handler.updateIntent(sYtIntent, false, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
-        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
+        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0, false);
         Assert.assertFalse(handler.isOnEffectiveIntentRedirectChain());
-        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, true, false, 0, 0);
+        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, true, false, 0, 0, false);
         Assert.assertTrue(handler.isOnEffectiveIntentRedirectChain());
         Assert.assertFalse(handler.hasNewResolver(
                 queryIntentActivities(sMoblieYtIntent), mQueryIntentFunction));
@@ -196,9 +196,9 @@
         handler.updateIntent(sYtIntent, false, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
-        handler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0);
+        handler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0, false);
         Assert.assertFalse(handler.isOnEffectiveIntentRedirectChain());
-        handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1);
+        handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1, false);
         Assert.assertFalse(handler.isOnEffectiveIntentRedirectChain());
         Assert.assertTrue(handler.hasNewResolver(
                 queryIntentActivities(sMoblieYtIntent), mQueryIntentFunction));
@@ -219,9 +219,9 @@
         handler.updateIntent(sYtIntent, false, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
-        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
+        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0, false);
         Assert.assertFalse(handler.isOnEffectiveIntentRedirectChain());
-        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, true, false, 0, 0);
+        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, true, false, 0, 0, false);
         Assert.assertTrue(handler.isOnEffectiveIntentRedirectChain());
         Assert.assertFalse(handler.hasNewResolver(
                 queryIntentActivities(sMoblieYtIntent), mQueryIntentFunction));
@@ -231,7 +231,7 @@
 
         SystemClock.sleep(1);
         handler.updateNewUrlLoading(
-                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 1);
+                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 1, false);
         Assert.assertFalse(handler.isOnEffectiveIntentRedirectChain());
         Assert.assertTrue(handler.hasNewResolver(
                 queryIntentActivities(sMoblieYtIntent), mQueryIntentFunction));
@@ -256,10 +256,10 @@
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
 
-        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
+        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0, false);
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
-        handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1);
+        handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1, false);
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
 
@@ -268,7 +268,7 @@
 
         SystemClock.sleep(1);
         handler.updateNewUrlLoading(
-                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2);
+                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2, false);
         Assert.assertFalse(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
 
@@ -285,9 +285,9 @@
         Assert.assertFalse(handler.isOnNavigation());
         Assert.assertFalse(handler.isNavigationFromUserTyping());
 
-        handler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0);
+        handler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0, false);
         Assert.assertTrue(handler.isNavigationFromUserTyping());
-        handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1);
+        handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1, false);
         Assert.assertTrue(handler.isNavigationFromUserTyping());
 
         Assert.assertTrue(handler.isOnNavigation());
@@ -295,7 +295,7 @@
 
         SystemClock.sleep(1);
         handler.updateNewUrlLoading(
-                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2);
+                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2, false);
         Assert.assertFalse(handler.isNavigationFromUserTyping());
 
         Assert.assertTrue(handler.isOnNavigation());
@@ -314,10 +314,10 @@
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
 
-        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0);
+        handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0, false);
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
-        handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1);
+        handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1, false);
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
 
@@ -326,7 +326,7 @@
 
         SystemClock.sleep(1);
         handler.updateNewUrlLoading(
-                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2);
+                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2, false);
         Assert.assertFalse(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
 
@@ -345,10 +345,10 @@
         handler.updateIntent(sYtIntent, false, false, false, false);
         Assert.assertFalse(handler.shouldNotOverrideUrlLoading());
 
-        handler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0);
+        handler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0, false);
         handler.setShouldNotOverrideUrlLoadingOnCurrentRedirectChain();
 
-        handler.updateNewUrlLoading(PageTransition.LINK, true, false, 0, 0);
+        handler.updateNewUrlLoading(PageTransition.LINK, true, false, 0, 0, false);
         Assert.assertTrue(handler.shouldNotOverrideUrlLoading());
         Assert.assertEquals(0, handler.getLastCommittedEntryIndexBeforeStartingNavigation());
 
@@ -359,11 +359,11 @@
         handler.updateIntent(sYtIntent, false, false, false, false);
         Assert.assertFalse(handler.shouldNotOverrideUrlLoading());
 
-        handler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0);
+        handler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0, false);
         handler.setShouldNotOverrideUrlLoadingOnCurrentRedirectChain();
 
         // Effective redirection occurred.
-        handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1);
+        handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1, false);
         Assert.assertTrue(handler.shouldNotOverrideUrlLoading());
         Assert.assertEquals(0, handler.getLastCommittedEntryIndexBeforeStartingNavigation());
 
@@ -372,7 +372,7 @@
         /////////////////////////////////////////////////////
         SystemClock.sleep(1);
         handler.updateNewUrlLoading(
-                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2);
+                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2, false);
         Assert.assertFalse(handler.shouldNotOverrideUrlLoading());
         Assert.assertEquals(2, handler.getLastCommittedEntryIndexBeforeStartingNavigation());
     }
@@ -388,10 +388,12 @@
         Assert.assertFalse(handler.shouldStayInApp(true));
 
         long lastUserInteractionTime = SystemClock.elapsedRealtime();
-        handler.updateNewUrlLoading(PageTransition.LINK, false, false, lastUserInteractionTime, 0);
+        handler.updateNewUrlLoading(
+                PageTransition.LINK, false, false, lastUserInteractionTime, 0, false);
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertTrue(handler.shouldStayInApp(true));
-        handler.updateNewUrlLoading(PageTransition.LINK, false, false, lastUserInteractionTime, 1);
+        handler.updateNewUrlLoading(
+                PageTransition.LINK, false, false, lastUserInteractionTime, 1, false);
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertTrue(handler.shouldStayInApp(true));
 
@@ -400,7 +402,7 @@
 
         SystemClock.sleep(1);
         handler.updateNewUrlLoading(
-                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2);
+                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2, false);
         Assert.assertFalse(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
 
@@ -420,10 +422,11 @@
 
         long lastUserInteractionTime = SystemClock.elapsedRealtime();
         handler.updateNewUrlLoading(
-                PageTransition.RELOAD, false, false, lastUserInteractionTime, 0);
+                PageTransition.RELOAD, false, false, lastUserInteractionTime, 0, false);
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertTrue(handler.shouldStayInApp(true));
-        handler.updateNewUrlLoading(PageTransition.LINK, false, false, lastUserInteractionTime, 1);
+        handler.updateNewUrlLoading(
+                PageTransition.LINK, false, false, lastUserInteractionTime, 1, false);
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertTrue(handler.shouldStayInApp(true));
 
@@ -432,7 +435,7 @@
 
         SystemClock.sleep(1);
         handler.updateNewUrlLoading(
-                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2);
+                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2, false);
         Assert.assertFalse(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
 
@@ -449,27 +452,31 @@
         Assert.assertFalse(handler.isOnNavigation());
         Assert.assertFalse(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
+        Assert.assertFalse(handler.hasUserStartedNonInitialNavigation());
 
         long lastUserInteractionTime = SystemClock.elapsedRealtime();
         handler.updateNewUrlLoading(PageTransition.FORM_SUBMIT | PageTransition.FORWARD_BACK, false,
-                true, lastUserInteractionTime, 0);
+                true, lastUserInteractionTime, 0, false);
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertTrue(handler.shouldStayInApp(true));
-        handler.updateNewUrlLoading(PageTransition.LINK, false, false, lastUserInteractionTime, 1);
+        handler.updateNewUrlLoading(PageTransition.LINK, false, false, lastUserInteractionTime, 1,
+                false /* isInitialNavigation */);
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertTrue(handler.shouldStayInApp(true));
 
         Assert.assertTrue(handler.isOnNavigation());
         Assert.assertEquals(0, handler.getLastCommittedEntryIndexBeforeStartingNavigation());
+        Assert.assertTrue(handler.hasUserStartedNonInitialNavigation());
 
         SystemClock.sleep(1);
-        handler.updateNewUrlLoading(
-                PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2);
+        handler.updateNewUrlLoading(PageTransition.LINK, false, true, SystemClock.elapsedRealtime(),
+                2, false /* isInitialNavigation */);
         Assert.assertFalse(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
 
         Assert.assertTrue(handler.isOnNavigation());
         Assert.assertEquals(2, handler.getLastCommittedEntryIndexBeforeStartingNavigation());
+        Assert.assertTrue(handler.hasUserStartedNonInitialNavigation());
     }
 
     @Test
@@ -483,10 +490,12 @@
 
         Assert.assertFalse(handler.isOnNavigation());
         handler.updateNewUrlLoading(PageTransition.LINK, false, true,
-                uninitializedUserInteractionTime, RedirectHandler.INVALID_ENTRY_INDEX);
+                uninitializedUserInteractionTime, RedirectHandler.INVALID_ENTRY_INDEX,
+                true /* isInitialNavigation */);
         Assert.assertTrue(handler.isOnNavigation());
         Assert.assertEquals(RedirectHandler.INVALID_ENTRY_INDEX,
                 handler.getLastCommittedEntryIndexBeforeStartingNavigation());
+        Assert.assertFalse(handler.hasUserStartedNonInitialNavigation());
     }
 
     /**
@@ -500,10 +509,22 @@
         RedirectHandler handler = RedirectHandler.create();
         handler.updateIntent(sFooIntent, false, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
+        Assert.assertFalse(handler.hasUserStartedNonInitialNavigation());
 
-        handler.updateNewUrlLoading(PageTransition.CLIENT_REDIRECT, false, false, 0, 0);
+        // Navigation to a page that will trigger a client redirect.
+        handler.updateNewUrlLoading(PageTransition.LINK, false /* isRedirect */,
+                false /* hasUserGesture */, 0, 0, true /* isInitialNavigation */);
         Assert.assertTrue(handler.shouldStayInApp(true));
         Assert.assertFalse(handler.shouldStayInApp(true, true));
+        Assert.assertFalse(handler.hasUserStartedNonInitialNavigation());
+
+        // Client redirect navigation.
+        handler.updateNewUrlLoading(PageTransition.LINK | PageTransition.CLIENT_REDIRECT,
+                false /* isRedirect */, false /* hasUserGesture */, 0, 0,
+                false /* isInitialNavigation */);
+        Assert.assertTrue(handler.shouldStayInApp(true));
+        Assert.assertFalse(handler.shouldStayInApp(true, true));
+        Assert.assertFalse(handler.hasUserStartedNonInitialNavigation());
     }
 
     private static class TestPackageManager extends MockPackageManager {
diff --git a/components/feed/core/v2/tools/protoc_util.py b/components/feed/core/v2/tools/protoc_util.py
index 2d2ce70..6c05742 100755
--- a/components/feed/core/v2/tools/protoc_util.py
+++ b/components/feed/core/v2/tools/protoc_util.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # 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.
diff --git a/components/feed/core/v2/tools/stream_dump.py b/components/feed/core/v2/tools/stream_dump.py
index c6a0040..9df5d01 100755
--- a/components/feed/core/v2/tools/stream_dump.py
+++ b/components/feed/core/v2/tools/stream_dump.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # 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.
diff --git a/components/feed/core/v2/tools/textpb_to_binarypb.py b/components/feed/core/v2/tools/textpb_to_binarypb.py
index ef07d25..0c8e569 100755
--- a/components/feed/core/v2/tools/textpb_to_binarypb.py
+++ b/components/feed/core/v2/tools/textpb_to_binarypb.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # 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.
diff --git a/components/nacl/browser/BUILD.gn b/components/nacl/browser/BUILD.gn
index ebd6417..97568e7c 100644
--- a/components/nacl/browser/BUILD.gn
+++ b/components/nacl/browser/BUILD.gn
@@ -70,10 +70,6 @@
       "//sandbox/linux:sandbox_services",
       "//sandbox/linux:suid_sandbox_client",
     ]
-
-    if (enable_nacl_nonsfi) {
-      data_deps += [ "//components/nacl/loader:helper_nonsfi" ]
-    }
   }
 
   if (is_win && current_cpu == "x86") {
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc
index 32a080b..4b892436 100644
--- a/components/nacl/browser/nacl_process_host.cc
+++ b/components/nacl/browser/nacl_process_host.cc
@@ -388,21 +388,11 @@
   }
 
   if (uses_nonsfi_mode_) {
-    bool nonsfi_mode_forced_by_command_line = false;
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
-    nonsfi_mode_forced_by_command_line =
-        cmd->HasSwitch(switches::kEnableNaClNonSfiMode);
-#endif
-    bool nonsfi_mode_enabled =
-        nonsfi_mode_forced_by_command_line || nonsfi_mode_allowed_;
-
-    if (!nonsfi_mode_enabled) {
-      SendErrorToRenderer(
-          "NaCl non-SFI mode is not available for this platform"
-          " and NaCl module.");
-      delete this;
-      return;
-    }
+    SendErrorToRenderer(
+        "NaCl non-SFI mode is not available for this platform"
+        " and NaCl module.");
+    delete this;
+    return;
   }
 
   // Launch the process
diff --git a/components/nacl/common/nacl_types.h b/components/nacl/common/nacl_types.h
index 1845b56..fc217d2 100644
--- a/components/nacl/common/nacl_types.h
+++ b/components/nacl/common/nacl_types.h
@@ -85,7 +85,7 @@
   IPC::PlatformFileForTransit debug_stub_server_bound_socket;
 #endif
 
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_NACL_NONSFI)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
   // These are for Non-SFI mode IPC channels.
   // For security hardening, unlike in SFI mode, we cannot create socket pairs
   // in a NaCl loader process. Thus, the browser process creates the
diff --git a/components/nacl/features.gni b/components/nacl/features.gni
index ad4bfdc..a2547a2c 100644
--- a/components/nacl/features.gni
+++ b/components/nacl/features.gni
@@ -17,9 +17,6 @@
       !(is_mac && (host_os != "mac" || target_cpu != "x64"))
 }
 
-# TODO(crbug.com/1273132): Remove all code referenced by this.
-enable_nacl_nonsfi = false
-
 assert(!(is_win && host_os != "win") || !enable_nacl,
        "NaCl doesn't work in win cross builds, crbug.com/774186")
 assert(!enable_nacl || checkout_nacl)
diff --git a/components/nacl/loader/BUILD.gn b/components/nacl/loader/BUILD.gn
index 5c77c8f..75f2adf 100644
--- a/components/nacl/loader/BUILD.gn
+++ b/components/nacl/loader/BUILD.gn
@@ -103,20 +103,6 @@
     "//ppapi/c",
     "//testing/gtest",
   ]
-
-  if (is_nacl_nonsfi) {
-    sources += [
-      # TODO(hamaji): Currently, we build them twice. Stop building
-      # them for components_unittests. See crbug.com/364751
-      "nonsfi/nonsfi_sandbox_sigsys_unittest.cc",
-      "nonsfi/nonsfi_sandbox_unittest.cc",
-    ]
-
-    deps += [
-      ":nacl_linux",
-      "//sandbox/linux:sandbox_linux_test_utils",
-    ]
-  }
 }
 
 if (is_linux || is_chromeos) {
@@ -173,23 +159,6 @@
     public = [ "nacl_helper_linux.h" ]
     data_deps = [ ":nacl_helper" ]
   }
-
-  if (enable_nacl_nonsfi) {
-    test("nacl_helper_nonsfi_unittests") {
-      sources = [ "nonsfi/nacl_helper_nonsfi_unittests.cc" ]
-      deps = [
-        "//base",
-        "//base/test:test_launcher_nacl_nonsfi",
-      ]
-      data_deps = [ ":nacl_helper_nonsfi_unittests_main_copy(//build/toolchain/nacl:newlib_pnacl_nonsfi)" ]
-    }
-
-    group("helper_nonsfi") {
-      data_deps = [
-        ":nacl_helper_nonsfi_copy(//build/toolchain/nacl:newlib_pnacl_nonsfi)",
-      ]
-    }
-  }
 }
 
 if (is_win && target_cpu == "x86" && current_cpu == "x64") {
@@ -213,92 +182,3 @@
     ]
   }
 }
-
-if (is_nacl_nonsfi) {
-  executable("nacl_helper_nonsfi_nexe") {
-    output_name = "nacl_helper_nonsfi"
-    sources = [
-      "nacl_helper_linux.cc",
-      "nacl_helper_linux.h",
-      "nacl_trusted_listener.cc",
-      "nacl_trusted_listener.h",
-      "nonsfi/nonsfi_listener.cc",
-      "nonsfi/nonsfi_listener.h",
-      "nonsfi/nonsfi_main.cc",
-      "nonsfi/nonsfi_main.h",
-    ]
-    deps = [
-      ":nacl_helper_nonsfi_sandbox",
-      "//base",
-      "//components/nacl/common:minimal",
-      "//components/nacl/common:mojo_bindings",
-      "//components/nacl/common:switches",
-      "//content",
-      "//ipc",
-      "//mojo/core/embedder",
-      "//native_client/src/nonsfi/irt:nacl_sys_private",
-      "//native_client/src/nonsfi/loader:elf_loader",
-
-      # Normally libnacl is included implicitly by libc and is part of the
-      # toolchain. But //build/config/nacl:compiler uses -nodefaultlibs and so
-      # omits the default libnacl. When the nonsfi toolchain is more complete
-      # and that kludge is no longer required, this dependency should be
-      # removed.
-      "//native_client/src/untrusted/nacl",
-      "//ppapi/proxy",
-      "//sandbox/linux:sandbox",
-      "//sandbox/policy",
-      "//services/service_manager/public/cpp",
-    ]
-  }
-
-  source_set("nacl_helper_nonsfi_sandbox") {
-    sources = [
-      "nonsfi/nonsfi_sandbox.cc",
-      "nonsfi/nonsfi_sandbox.h",
-      "sandbox_linux/nacl_sandbox_linux.cc",
-      "sandbox_linux/nacl_sandbox_linux.h",
-    ]
-    deps = [
-      "//base",
-      "//components/nacl/common:minimal",
-      "//components/nacl/common:switches",
-      "//content",
-      "//sandbox/linux:sandbox",
-      "//sandbox/linux:sandbox_services_headers",
-    ]
-  }
-
-  copy("nacl_helper_nonsfi_copy") {
-    sources = [ "${root_out_dir}/nacl_helper_nonsfi" ]
-    outputs = [ "${root_build_dir}/{{source_file_part}}" ]
-    deps = [ ":nacl_helper_nonsfi_nexe" ]
-  }
-
-  test("nacl_helper_nonsfi_unittests_main") {
-    sources = [
-      "nonsfi/nonsfi_sandbox_sigsys_unittest.cc",
-      "nonsfi/nonsfi_sandbox_unittest.cc",
-      "nonsfi/run_all_unittests.cc",
-    ]
-    deps = [
-      ":nacl_helper_nonsfi_sandbox",
-      "//base",
-      "//base/test:test_support",
-      "//content",
-      "//native_client/src/nonsfi/irt:nacl_sys_private",
-      "//native_client/src/untrusted/nacl:nacl",
-      "//sandbox/linux:sandbox",
-      "//sandbox/linux:sandbox_linux_test_utils",
-      "//sandbox/linux:sandbox_services_headers",
-      "//testing/gtest",
-    ]
-  }
-
-  copy("nacl_helper_nonsfi_unittests_main_copy") {
-    testonly = true
-    sources = [ "${root_out_dir}/nacl_helper_nonsfi_unittests_main" ]
-    outputs = [ "${root_build_dir}/{{source_file_part}}" ]
-    deps = [ ":nacl_helper_nonsfi_unittests_main" ]
-  }
-}
diff --git a/components/nacl/loader/nacl_helper_linux.cc b/components/nacl/loader/nacl_helper_linux.cc
index 4752baf..3c8ec93e 100644
--- a/components/nacl/loader/nacl_helper_linux.cc
+++ b/components/nacl/loader/nacl_helper_linux.cc
@@ -8,6 +8,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <link.h>
 #include <signal.h>
 #include <stddef.h>
 #include <stdio.h>
@@ -35,6 +36,7 @@
 #include "base/task/single_thread_task_executor.h"
 #include "build/build_config.h"
 #include "components/nacl/common/nacl_switches.h"
+#include "components/nacl/loader/nacl_listener.h"
 #include "components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h"
 #include "content/public/common/content_descriptors.h"
 #include "content/public/common/zygote/send_zygote_child_ping_linux.h"
@@ -43,14 +45,6 @@
 #include "sandbox/linux/services/credentials.h"
 #include "sandbox/linux/services/namespace_sandbox.h"
 
-#if defined(OS_NACL_NONSFI)
-#include "components/nacl/loader/nonsfi/nonsfi_listener.h"
-#include "native_client/src/public/nonsfi/irt_exception_handling.h"
-#else
-#include <link.h>
-#include "components/nacl/loader/nacl_listener.h"
-#endif
-
 namespace {
 
 struct NaClLoaderSystemInfo {
@@ -58,19 +52,6 @@
   long number_of_cores;
 };
 
-#if defined(OS_NACL_NONSFI)
-// Replace |file_descriptor| with the reading end of a closed pipe.
-void ReplaceFDWithDummy(int file_descriptor) {
-  // Make sure that file_descriptor is an open descriptor.
-  PCHECK(-1 != fcntl(file_descriptor, F_GETFD, 0));
-  int pipefd[2];
-  PCHECK(0 == pipe(pipefd));
-  PCHECK(-1 != dup2(pipefd[0], file_descriptor));
-  PCHECK(0 == IGNORE_EINTR(close(pipefd[0])));
-  PCHECK(0 == IGNORE_EINTR(close(pipefd[1])));
-}
-#endif
-
 // The child must mimic the behavior of zygote_main_linux.cc on the child
 // side of the fork. See zygote_main_linux.cc:HandleForkRequest from
 //   if (!child) {
@@ -83,26 +64,7 @@
   // Close or shutdown IPC channels that we don't need anymore.
   PCHECK(0 == IGNORE_EINTR(close(kNaClZygoteDescriptor)));
 
-#if defined(OS_NACL_NONSFI)
-  // In Non-SFI mode, it's important to close any non-expected IPC channels.
-  CHECK(uses_nonsfi_mode);
-  // The low-level kSandboxIPCChannel is used by renderers and NaCl for
-  // various operations. See the SandboxLinux::METHOD_* methods. NaCl uses
-  // SandboxLinux::METHOD_MAKE_SHARED_MEMORY_SEGMENT in SFI mode, so this
-  // should only be closed in Non-SFI mode.
-  // This file descriptor is insidiously used by a number of APIs. Closing it
-  // could lead to difficult to debug issues. Instead of closing it, replace
-  // it with a dummy.
-  const int sandbox_ipc_channel =
-      base::GlobalDescriptors::kBaseDescriptor + kSandboxIPCChannel;
-
-  ReplaceFDWithDummy(sandbox_ipc_channel);
-
-  // Install crash signal handlers before disallowing system calls.
-  nonsfi_initialize_signal_handler();
-#else
   CHECK(!uses_nonsfi_mode);
-#endif
 
   // Always ignore SIGPIPE, for consistency with other Chrome processes and
   // because some IPC code, such as sync_socket_posix.cc, requires this.
@@ -122,17 +84,12 @@
   mojo::core::Init();
 
   base::SingleThreadTaskExecutor io_task_executor(base::MessagePumpType::IO);
-#if defined(OS_NACL_NONSFI)
-  CHECK(uses_nonsfi_mode);
-  nacl::nonsfi::NonSfiListener listener;
-  listener.Listen();
-#else
   CHECK(!uses_nonsfi_mode);
   NaClListener listener;
   listener.set_prereserved_sandbox_size(system_info.prereserved_sandbox_size);
   listener.set_number_of_cores(system_info.number_of_cores);
   listener.Listen();
-#endif
+
   _exit(0);
 }
 
@@ -200,15 +157,6 @@
   }
 
   if (child_pid == 0) {
-    // Install termiantion signal handlers for nonsfi NaCl. The SFI NaCl runtime
-    // will install signal handlers for SIGINT, SIGTERM, etc. so we do not need
-    // to install termination signal handlers ourselves (in fact, it will crash
-    // if signal handlers for these are present).
-    if (uses_nonsfi_mode && getpid() == 1) {
-      // Note that nonsfi NaCl may override some of these signal handlers, which
-      // is fine.
-      sandbox::NamespaceSandbox::InstallDefaultTerminationSignalHandlers();
-    }
     ChildNaClLoaderInit(std::move(child_fds), system_info, uses_nonsfi_mode,
                         nacl_sandbox, channel_id);
     NOTREACHED();
@@ -328,7 +276,6 @@
                               system_info, nacl_sandbox, &read_iter);
 }
 
-#if !defined(OS_NACL_NONSFI)
 static const char kNaClHelperReservedAtZero[] = "reserved_at_zero";
 static const char kNaClHelperRDebug[] = "r_debug";
 
@@ -399,7 +346,6 @@
   }
   return prereserved_sandbox_size;
 }
-#endif
 
 }  // namespace
 
@@ -416,17 +362,10 @@
   base::AtExitManager exit_manager;
   base::RandUint64();  // acquire /dev/urandom fd before sandbox is raised
 
-  const NaClLoaderSystemInfo system_info = {
-#if !defined(OS_NACL_NONSFI)
-    // These are not used by nacl_helper_nonsfi.
-    CheckReservedAtZero(),
-    sysconf(_SC_NPROCESSORS_ONLN)
-#endif
-  };
+  const NaClLoaderSystemInfo system_info = {CheckReservedAtZero(),
+                                            sysconf(_SC_NPROCESSORS_ONLN)};
 
-#if !defined(OS_NACL_NONSFI)
   CheckRDebug(argv[0]);
-#endif
 
   std::unique_ptr<nacl::NaClSandbox> nacl_sandbox(new nacl::NaClSandbox);
   // Make sure that the early initialization did not start any spurious
diff --git a/components/nacl/loader/nonsfi/DEPS b/components/nacl/loader/nonsfi/DEPS
deleted file mode 100644
index af61a9f7..0000000
--- a/components/nacl/loader/nonsfi/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-include_rules = [
-  "+ppapi/nacl_irt",
-  "+sandbox/linux/seccomp-bpf-helpers",
-  "+third_party/lss/linux_syscall_support.h",  # for BPF policy tests
-]
diff --git a/components/nacl/loader/nonsfi/OWNERS b/components/nacl/loader/nonsfi/OWNERS
deleted file mode 100644
index 36b844c3..0000000
--- a/components/nacl/loader/nonsfi/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-hidehiko@chromium.org
-
-per-file nonsfi_sandbox*=mseaborn@chromium.org
diff --git a/components/nacl/loader/nonsfi/nacl_helper_nonsfi_unittests.cc b/components/nacl/loader/nonsfi/nacl_helper_nonsfi_unittests.cc
deleted file mode 100644
index dbca0a6..0000000
--- a/components/nacl/loader/nonsfi/nacl_helper_nonsfi_unittests.cc
+++ /dev/null
@@ -1,13 +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 "base/at_exit.h"
-#include "base/command_line.h"
-#include "base/test/launcher/test_launcher_nacl_nonsfi.h"
-
-int main(int argc, char* argv[]) {
-  base::AtExitManager at_exit;
-  base::CommandLine::Init(argc, argv);
-  return base::TestLauncherNonSfiMain("nacl_helper_nonsfi_unittests_main");
-}
diff --git a/components/nacl/loader/nonsfi/nonsfi_listener.cc b/components/nacl/loader/nonsfi/nonsfi_listener.cc
deleted file mode 100644
index 76844b2..0000000
--- a/components/nacl/loader/nonsfi/nonsfi_listener.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2014 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/nacl/loader/nonsfi/nonsfi_listener.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/command_line.h"
-#include "base/file_descriptor_posix.h"
-#include "base/logging.h"
-#include "base/message_loop/message_pump_type.h"
-#include "base/rand_util.h"
-#include "base/run_loop.h"
-#include "build/build_config.h"
-#include "components/nacl/common/nacl.mojom.h"
-#include "components/nacl/common/nacl_messages.h"
-#include "components/nacl/common/nacl_service.h"
-#include "components/nacl/common/nacl_types.h"
-#include "components/nacl/loader/nacl_trusted_listener.h"
-#include "components/nacl/loader/nonsfi/nonsfi_main.h"
-#include "content/public/common/content_descriptors.h"
-#include "ipc/ipc_channel.h"
-#include "ipc/ipc_channel_handle.h"
-#include "ipc/ipc_sync_channel.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "native_client/src/public/nonsfi/irt_random.h"
-#include "ppapi/nacl_irt/irt_manifest.h"
-#include "ppapi/nacl_irt/plugin_startup.h"
-
-#if !defined(OS_NACL_NONSFI)
-#error "This file must be built for nacl_helper_nonsfi."
-#endif
-
-namespace nacl {
-namespace nonsfi {
-
-NonSfiListener::NonSfiListener()
-    : io_thread_("NaCl_IOThread"),
-      shutdown_event_(base::WaitableEvent::ResetPolicy::MANUAL,
-                      base::WaitableEvent::InitialState::NOT_SIGNALED),
-      key_fd_map_(new std::map<std::string, int>) {
-  io_thread_.StartWithOptions(
-      base::Thread::Options(base::MessagePumpType::IO, 0));
-}
-
-NonSfiListener::~NonSfiListener() {
-}
-
-void NonSfiListener::Listen() {
-  NaClService service(io_thread_.task_runner());
-  channel_ = IPC::SyncChannel::Create(
-      service.TakeChannelPipe().release(), IPC::Channel::MODE_CLIENT,
-      this,  // As a Listener.
-      io_thread_.task_runner(), base::ThreadTaskRunnerHandle::Get(),
-      true,  // Create pipe now.
-      &shutdown_event_);
-  base::RunLoop().Run();
-}
-
-bool NonSfiListener::OnMessageReceived(const IPC::Message& msg) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(NonSfiListener, msg)
-      IPC_MESSAGE_HANDLER(NaClProcessMsg_AddPrefetchedResource,
-                          OnAddPrefetchedResource)
-      IPC_MESSAGE_HANDLER(NaClProcessMsg_Start, OnStart)
-      IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void NonSfiListener::OnAddPrefetchedResource(
-    const nacl::NaClResourcePrefetchResult& prefetched_resource_file) {
-  CHECK(prefetched_resource_file.file_path_metadata.empty());
-  bool result = key_fd_map_->insert(std::make_pair(
-      prefetched_resource_file.file_key,
-      IPC::PlatformFileForTransitToPlatformFile(
-          prefetched_resource_file.file))).second;
-  if (!result) {
-    LOG(FATAL) << "Duplicated open_resource key: "
-               << prefetched_resource_file.file_key;
-  }
-}
-
-void NonSfiListener::OnStart(const nacl::NaClStartParams& params) {
-  // Random number source initialization.
-  nonsfi_set_urandom_fd(base::GetUrandomFD());
-
-  // In Non-SFI mode, we neither intercept nor rewrite the message using
-  // NaClIPCAdapter, and the channels are connected between the plugin and
-  // the hosts directly. So, the IPC::Channel instances will be created in
-  // the plugin side, because the IPC::Listener needs to live on the
-  // plugin's main thread. We just pass the FDs to plugin side.
-  // The FDs are created in the browser process. Following check can fail
-  // if the preparation for sending NaClProcessMsg_Start were incomplete.
-  CHECK(params.ppapi_browser_channel_handle.is_mojo_channel_handle());
-  CHECK(params.ppapi_renderer_channel_handle.is_mojo_channel_handle());
-  CHECK(params.trusted_service_channel_handle.is_mojo_channel_handle());
-  CHECK(params.manifest_service_channel_handle.is_mojo_channel_handle());
-
-  ppapi::SetIPCChannelHandles(
-      params.ppapi_browser_channel_handle,
-      params.ppapi_renderer_channel_handle,
-      params.manifest_service_channel_handle);
-  ppapi::StartUpPlugin();
-
-  trusted_listener_ = std::make_unique<NaClTrustedListener>(
-      mojo::PendingRemote<nacl::mojom::NaClRendererHost>(
-          mojo::ScopedMessagePipeHandle(
-              params.trusted_service_channel_handle.mojo_handle),
-          nacl::mojom::NaClRendererHost::Version_),
-      io_thread_.task_runner().get());
-
-  // Ensure that the validation cache key (used as an extra input to the
-  // validation cache's hashing) isn't exposed accidentally.
-  CHECK(!params.validation_cache_enabled);
-  CHECK(params.validation_cache_key.size() == 0);
-  CHECK(params.version.size() == 0);
-  // Ensure that a debug stub FD isn't passed through accidentally.
-  CHECK(!params.enable_debug_stub);
-  CHECK(params.debug_stub_server_bound_socket.fd == -1);
-
-  CHECK(params.irt_handle == IPC::InvalidPlatformFileForTransit());
-  CHECK(params.debug_stub_server_bound_socket ==
-        IPC::InvalidPlatformFileForTransit());
-
-  // We are only expecting non-SFI mode to be used with NaCl for now,
-  // not PNaCl processes.
-  CHECK(params.process_type == kNativeNaClProcessType);
-
-  CHECK(params.nexe_file != IPC::InvalidPlatformFileForTransit());
-  CHECK(params.nexe_file_path_metadata.empty());
-
-  ppapi::RegisterPreopenedDescriptorsNonSfi(key_fd_map_.release());
-
-  MainStart(IPC::PlatformFileForTransitToPlatformFile(params.nexe_file));
-}
-
-}  // namespace nonsfi
-}  // namespace nacl
diff --git a/components/nacl/loader/nonsfi/nonsfi_listener.h b/components/nacl/loader/nonsfi/nonsfi_listener.h
deleted file mode 100644
index 79fa229..0000000
--- a/components/nacl/loader/nonsfi/nonsfi_listener.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2014 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_NACL_LOADER_NONSFI_NONSFI_LISTENER_H_
-#define COMPONENTS_NACL_LOADER_NONSFI_NONSFI_LISTENER_H_
-
-#include <map>
-#include <memory>
-
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
-#include "components/nacl/common/nacl_types.h"
-#include "ipc/ipc_listener.h"
-
-namespace IPC {
-class Message;
-class SyncChannel;
-}  // namespace IPC
-
-class NaClTrustedListener;
-
-namespace nacl {
-
-struct NaClStartParams;
-
-namespace nonsfi {
-
-class NonSfiListener : public IPC::Listener {
- public:
-  NonSfiListener();
-
-  NonSfiListener(const NonSfiListener&) = delete;
-  NonSfiListener& operator=(const NonSfiListener&) = delete;
-
-  ~NonSfiListener() override;
-
-  // Listen for a request to launch a non-SFI NaCl module.
-  void Listen();
-
- private:
-  bool OnMessageReceived(const IPC::Message& msg) override;
-  void OnAddPrefetchedResource(
-      const nacl::NaClResourcePrefetchResult& prefetched_resource_file);
-  void OnStart(const nacl::NaClStartParams& params);
-
-  base::Thread io_thread_;
-  base::WaitableEvent shutdown_event_;
-  std::unique_ptr<IPC::SyncChannel> channel_;
-  std::unique_ptr<NaClTrustedListener> trusted_listener_;
-
-  std::unique_ptr<std::map<std::string, int>> key_fd_map_;
-};
-
-}  // namespace nonsfi
-}  // namespace nacl
-
-#endif  // COMPONENTS_NACL_LOADER_NONSFI_NONSFI_LISTENER_H_
diff --git a/components/nacl/loader/nonsfi/nonsfi_main.cc b/components/nacl/loader/nonsfi/nonsfi_main.cc
deleted file mode 100644
index 30986c7..0000000
--- a/components/nacl/loader/nonsfi/nonsfi_main.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2014 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/nacl/loader/nonsfi/nonsfi_main.h"
-
-#include <stddef.h>
-
-#include "base/logging.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/thread_restrictions.h"
-#include "build/build_config.h"
-#include "native_client/src/include/elf_auxv.h"
-#include "native_client/src/public/nonsfi/elf_loader.h"
-#include "ppapi/nacl_irt/irt_interfaces.h"
-
-#if !defined(OS_NACL_NONSFI)
-#error "nonsfi_main.cc must be built for nacl_helper_nonsfi."
-#endif
-
-namespace nacl {
-namespace nonsfi {
-
-namespace {
-
-typedef void (*EntryPointType)(uintptr_t*);
-
-// Default stack size of the plugin main thread. We heuristically chose 16M.
-const size_t kStackSize = (16 << 20);
-
-}  // namespace
-
-class PluginMainDelegate : public base::PlatformThread::Delegate {
- public:
-  explicit PluginMainDelegate(EntryPointType entry_point)
-      : entry_point_(entry_point) {
-  }
-
-  ~PluginMainDelegate() override {}
-
-  void ThreadMain() override {
-    base::PlatformThread::SetName("NaClMainThread");
-
-    // This will only happen once per process, so we give the permission to
-    // create Singletons.
-    base::PermanentSingletonAllowance::AllowSingleton();
-    uintptr_t info[] = {
-      0,  // Do not use fini.
-      0,  // envc.
-      0,  // argc.
-      0,  // Null terminate for argv.
-      0,  // Null terminate for envv.
-      AT_SYSINFO,
-      reinterpret_cast<uintptr_t>(&chrome_irt_query),
-      AT_NULL,
-      0,  // Null terminate for auxv.
-    };
-    entry_point_(info);
-  }
-
- private:
-  EntryPointType entry_point_;
-};
-
-void MainStart(int nexe_file) {
-  EntryPointType entry_point =
-      reinterpret_cast<EntryPointType>(NaClLoadElfFile(nexe_file));
-  if (!base::PlatformThread::CreateNonJoinable(
-          kStackSize, new PluginMainDelegate(entry_point))) {
-    LOG(ERROR) << "LoadModuleRpc: Failed to create plugin main thread.";
-    return;
-  }
-}
-
-}  // namespace nonsfi
-}  // namespace nacl
diff --git a/components/nacl/loader/nonsfi/nonsfi_main.h b/components/nacl/loader/nonsfi/nonsfi_main.h
deleted file mode 100644
index 3a28bcd..0000000
--- a/components/nacl/loader/nonsfi/nonsfi_main.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2014 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_NACL_LOADER_NONSFI_NONSFI_MAIN_H_
-#define COMPONENTS_NACL_LOADER_NONSFI_NONSFI_MAIN_H_
-
-namespace nacl {
-namespace nonsfi {
-
-// Launch NaCl with Non SFI mode. This takes the ownership of |nexe_file|.
-void MainStart(int nexe_file);
-
-}  // namespace nonsfi
-}  // namespace nacl
-
-#endif  // COMPONENTS_NACL_LOADER_NONSFI_NONSFI_MAIN_H_
diff --git a/components/nacl/loader/nonsfi/nonsfi_sandbox.cc b/components/nacl/loader/nonsfi/nonsfi_sandbox.cc
deleted file mode 100644
index 154e96b..0000000
--- a/components/nacl/loader/nonsfi/nonsfi_sandbox.cc
+++ /dev/null
@@ -1,350 +0,0 @@
-// Copyright 2014 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/nacl/loader/nonsfi/nonsfi_sandbox.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/net.h>
-#include <stdint.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
-
-#include <memory>
-
-#include "base/check_op.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "content/public/common/sandbox_init.h"
-#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
-#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
-#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
-#include "sandbox/linux/system_headers/linux_futex.h"
-#include "sandbox/linux/system_headers/linux_signal.h"
-#include "sandbox/linux/system_headers/linux_syscalls.h"
-
-#if !defined(OS_NACL_NONSFI)
-#error "nonsfi_sandbox.cc must be built for nacl_helper_nonsfi."
-#endif
-
-// Chrome OS Daisy (ARM) build environment and PNaCl toolchain do not define
-// MAP_STACK.
-#if !defined(MAP_STACK)
-# if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY)
-#  define MAP_STACK 0x20000
-# elif defined(ARCH_CPU_MIPS_FAMILY)
-#  define MAP_STACK 0x40000
-# else
-// Note that, on other architectures, MAP_STACK has different value,
-// though Non-SFI is not supported on such architectures.
-#  error "Unknown platform."
-# endif
-#endif  // !defined(MAP_STACK)
-
-#define CASES SANDBOX_BPF_DSL_CASES
-
-using sandbox::CrashSIGSYS;
-using sandbox::CrashSIGSYSClone;
-using sandbox::CrashSIGSYSFutex;
-using sandbox::CrashSIGSYSPrctl;
-using sandbox::bpf_dsl::Allow;
-using sandbox::bpf_dsl::Arg;
-using sandbox::bpf_dsl::BoolExpr;
-using sandbox::bpf_dsl::Error;
-using sandbox::bpf_dsl::If;
-using sandbox::bpf_dsl::ResultExpr;
-
-namespace nacl {
-namespace nonsfi {
-namespace {
-
-ResultExpr RestrictFcntlCommands() {
-  const Arg<int> cmd(1);
-  const Arg<long> long_arg(2);
-
-  // We allow following cases:
-  // 1. F_SETFD + FD_CLOEXEC: libevent's epoll_init uses this.
-  // 2. F_GETFL: Used by SetNonBlocking in
-  // message_pump_libevent.cc and Channel::ChannelImpl::CreatePipe
-  // in ipc_channel_posix.cc. Note that the latter does not work
-  // with EPERM.
-  // 3. F_SETFL: Used by evutil_make_socket_nonblocking in
-  // libevent and SetNonBlocking. As the latter mix O_NONBLOCK to
-  // the return value of F_GETFL, so we need to allow O_ACCMODE in
-  // addition to O_NONBLOCK.
-  const uint64_t kAllowedMask = O_ACCMODE | O_NONBLOCK;
-  return If(AnyOf(AllOf(cmd == F_SETFD, long_arg == FD_CLOEXEC), cmd == F_GETFL,
-                  AllOf(cmd == F_SETFL, (long_arg & ~kAllowedMask) == 0)),
-            Allow())
-      .Else(CrashSIGSYS());
-}
-
-ResultExpr RestrictClone() {
-  // We allow clone only for new thread creation.
-  const int kCloneFlags =
-      CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
-      CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID;
-  const Arg<int> flags(0);
-  return If(flags == kCloneFlags, Allow()).Else(CrashSIGSYSClone());
-}
-
-ResultExpr RestrictFutexOperation() {
-  // TODO(hamaji): Allow only FUTEX_PRIVATE_FLAG futexes.
-  const uint64_t kAllowedFutexFlags = FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME;
-  const Arg<int> op(1);
-  return Switch(op & ~kAllowedFutexFlags)
-      .CASES((FUTEX_WAIT,
-              FUTEX_WAKE,
-              FUTEX_REQUEUE,
-              FUTEX_CMP_REQUEUE,
-              FUTEX_WAKE_OP,
-              FUTEX_WAIT_BITSET,
-              FUTEX_WAKE_BITSET),
-             Allow())
-      .Default(CrashSIGSYSFutex());
-}
-
-ResultExpr RestrictPrctl() {
-  // base::PlatformThread::SetName() uses PR_SET_NAME so we return
-  // EPERM for it. Otherwise, we will raise SIGSYS.
-  const Arg<int> option(0);
-  return If(option == PR_SET_NAME, Error(EPERM)).Else(CrashSIGSYSPrctl());
-}
-
-#if defined(__i386__)
-ResultExpr RestrictSocketcall() {
-  // We only allow shutdown(), sendmsg(), and recvmsg().
-  const Arg<int> call(0);
-  return Switch(call)
-      .CASES((SYS_SHUTDOWN, SYS_SENDMSG, SYS_RECVMSG), Allow())
-      .Default(CrashSIGSYS());
-}
-#endif
-
-ResultExpr RestrictMprotect() {
-  // TODO(jln, keescook, drewry): Limit the use of mprotect by adding
-  // some features to linux kernel.
-  const uint64_t kAllowedMask = PROT_READ | PROT_WRITE | PROT_EXEC;
-  const Arg<int> prot(2);
-  return If((prot & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS());
-}
-
-ResultExpr RestrictMmap() {
-  const uint64_t kAllowedFlagMask =
-      MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_FIXED;
-  // When PROT_EXEC is specified, IRT mmap of Non-SFI NaCl helper
-  // calls mmap without PROT_EXEC and then adds PROT_EXEC by mprotect,
-  // so we do not need to allow PROT_EXEC in mmap.
-  const uint64_t kAllowedProtMask = PROT_READ | PROT_WRITE;
-  const Arg<int> prot(2), flags(3);
-  return If(AllOf((prot & ~kAllowedProtMask) == 0,
-                  (flags & ~kAllowedFlagMask) == 0),
-            Allow())
-      .Else(CrashSIGSYS());
-}
-
-ResultExpr RestrictTgkill(int policy_pid) {
-  const Arg<int> tgid(0), tid(1), signum(2);
-  // Only sending SIGUSR1 to a thread in the same process is allowed.
-  return If(AllOf(
-                tgid == policy_pid,
-                // Arg does not support a greater-than operator, so two separate
-                // checks are needed to ensure tid is positive.
-                tid != 0,
-                (tid & (1u << 31)) == 0,  // tid is non-negative.
-                signum == LINUX_SIGUSR1),
-            Allow())
-      .Else(CrashSIGSYS());
-}
-
-bool IsGracefullyDenied(int sysno) {
-  switch (sysno) {
-    // libevent tries this first and then falls back to poll if
-    // epoll_create fails.
-    case __NR_epoll_create:
-    // third_party/libevent uses them, but we can just return -1 from
-    // them as it is just checking getuid() != geteuid() and
-    // getgid() != getegid()
-#if defined(__i386__) || defined(__arm__)
-    case __NR_getegid32:
-    case __NR_geteuid32:
-    case __NR_getgid32:
-    case __NR_getuid32:
-#endif
-    case __NR_getegid:
-    case __NR_geteuid:
-    case __NR_getgid:
-    case __NR_getuid:
-    // tcmalloc calls madvise in TCMalloc_SystemRelease.
-    case __NR_madvise:
-    // EPERM instead of SIGSYS as glibc tries to open files in /proc.
-    // openat via opendir via get_nprocs_conf and open via get_nprocs.
-    // TODO(hamaji): Remove this when we switch to newlib.
-    case __NR_open:
-    case __NR_openat:
-    // For RunSandboxSanityChecks().
-    case __NR_ptrace:
-    // glibc uses this for its pthread implementation. If we return
-    // EPERM for this, glibc will stop using this.
-    // TODO(hamaji): newlib does not use this. Make this SIGTRAP once
-    // we have switched to newlib.
-    case __NR_set_robust_list:
-    // This is obsolete in ARM EABI, but x86 glibc indirectly calls
-    // this in sysconf.
-#if defined(__i386__) || defined(__x86_64__)
-    case __NR_time:
-#endif
-      return true;
-
-    default:
-      return false;
-  }
-}
-
-void RunSandboxSanityChecks() {
-  errno = 0;
-  // Make a ptrace request with an invalid PID.
-  long ptrace_ret = syscall(
-      __NR_ptrace, 3 /* = PTRACE_PEEKUSER */, -1 /* pid */, NULL, NULL);
-  CHECK_EQ(-1, ptrace_ret);
-  // Without the sandbox on, this ptrace call would ESRCH instead.
-  CHECK_EQ(EPERM, errno);
-}
-
-}  // namespace
-
-NaClNonSfiBPFSandboxPolicy::NaClNonSfiBPFSandboxPolicy()
-    : policy_pid_(getpid()) {
-}
-
-NaClNonSfiBPFSandboxPolicy::~NaClNonSfiBPFSandboxPolicy() {
-  // Make sure that this policy is created, used and destroyed by a single
-  // process.
-  DCHECK_EQ(getpid(), policy_pid_);
-}
-
-ResultExpr NaClNonSfiBPFSandboxPolicy::EvaluateSyscall(int sysno) const {
-  switch (sysno) {
-    // Allowed syscalls.
-#if defined(__i386__) || defined(__arm__)
-    case __NR__llseek:
-#elif defined(__x86_64__)
-    case __NR_lseek:
-#endif
-    case __NR_close:
-    case __NR_dup:
-    case __NR_dup2:
-    case __NR_exit:
-    case __NR_exit_group:
-#if defined(__i386__) || defined(__arm__)
-    case __NR_fstat64:
-#elif defined(__x86_64__)
-    case __NR_fstat:
-#endif
-    // TODO(hamaji): Remove the need of gettid. Currently, this is
-    // called from PlatformThread::CurrentId().
-    case __NR_gettid:
-    case __NR_gettimeofday:
-    case __NR_munmap:
-    case __NR_nanosleep:
-    // TODO(hamaji): Remove the need of pipe. Currently, this is
-    // called from base::MessagePumpLibevent::Init().
-    case __NR_pipe:
-    case __NR_poll:
-    case __NR_pread64:
-    case __NR_pwrite64:
-    case __NR_read:
-    case __NR_restart_syscall:
-    case __NR_sched_yield:
-    // __NR_times needed as clock() is called by CommandBufferHelper, which is
-    // used by NaCl applications that use Pepper's 3D interfaces.
-    // See crbug.com/264856 for details.
-    case __NR_times:
-    case __NR_write:
-#if defined(__arm__)
-    case __ARM_NR_cacheflush:
-#endif
-      return Allow();
-
-    case __NR_clock_getres:
-    case __NR_clock_gettime:
-      return sandbox::RestrictClockID();
-
-    case __NR_clone:
-      return RestrictClone();
-
-#if defined(__x86_64__)
-    case __NR_fcntl:
-#endif
-#if defined(__i386__) || defined(__arm__)
-    case __NR_fcntl64:
-#endif
-      return RestrictFcntlCommands();
-
-    case __NR_futex:
-      return RestrictFutexOperation();
-
-#if defined(__x86_64__)
-    case __NR_mmap:
-#endif
-#if defined(__i386__) || defined(__arm__)
-    case __NR_mmap2:
-#endif
-      return RestrictMmap();
-    case __NR_mprotect:
-      return RestrictMprotect();
-
-    case __NR_prctl:
-      return RestrictPrctl();
-
-#if defined(__i386__)
-    case __NR_socketcall:
-      return RestrictSocketcall();
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-    case __NR_recvmsg:
-    case __NR_sendmsg:
-    case __NR_shutdown:
-      return Allow();
-#endif
-
-    case __NR_tgkill:
-      return RestrictTgkill(policy_pid_);
-
-    case __NR_brk:
-      // The behavior of brk on Linux is different from other system
-      // calls. It does not return errno but the current break on
-      // failure. glibc thinks brk failed if the return value of brk
-      // is less than the requested address (i.e., brk(addr) < addr).
-      // So, glibc thinks brk succeeded if we return -EPERM and we
-      // need to return zero instead.
-      return Error(0);
-
-    default:
-      if (IsGracefullyDenied(sysno))
-        return Error(EPERM);
-      return CrashSIGSYS();
-  }
-}
-
-ResultExpr NaClNonSfiBPFSandboxPolicy::InvalidSyscall() const {
-  return CrashSIGSYS();
-}
-
-bool InitializeBPFSandbox(base::ScopedFD proc_fd) {
-  bool sandbox_is_initialized = content::InitializeSandbox(
-      std::unique_ptr<sandbox::bpf_dsl::Policy>(
-          new nacl::nonsfi::NaClNonSfiBPFSandboxPolicy()),
-      std::move(proc_fd));
-  if (!sandbox_is_initialized)
-    return false;
-  RunSandboxSanityChecks();
-  return true;
-}
-
-}  // namespace nonsfi
-}  // namespace nacl
diff --git a/components/nacl/loader/nonsfi/nonsfi_sandbox.h b/components/nacl/loader/nonsfi/nonsfi_sandbox.h
deleted file mode 100644
index 0d1dea7..0000000
--- a/components/nacl/loader/nonsfi/nonsfi_sandbox.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2014 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_NACL_LOADER_NONSFI_NONSFI_SANDBOX_H_
-#define COMPONENTS_NACL_LOADER_NONSFI_NONSFI_SANDBOX_H_
-
-#include "base/files/scoped_file.h"
-#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
-#include "sandbox/linux/bpf_dsl/policy.h"
-
-namespace nacl {
-namespace nonsfi {
-
-// The seccomp sandbox policy for NaCl non-SFI mode. Note that this
-// policy must be as strong as possible, as non-SFI mode heavily
-// depends on seccomp sandbox.
-class NaClNonSfiBPFSandboxPolicy : public sandbox::bpf_dsl::Policy {
- public:
-  explicit NaClNonSfiBPFSandboxPolicy();
-
-  NaClNonSfiBPFSandboxPolicy(const NaClNonSfiBPFSandboxPolicy&) = delete;
-  NaClNonSfiBPFSandboxPolicy& operator=(const NaClNonSfiBPFSandboxPolicy&) =
-      delete;
-
-  ~NaClNonSfiBPFSandboxPolicy() override;
-
-  sandbox::bpf_dsl::ResultExpr EvaluateSyscall(int sysno) const override;
-  sandbox::bpf_dsl::ResultExpr InvalidSyscall() const override;
-
- private:
-  // The PID that the policy applies to (should be equal to the current pid).
-  const pid_t policy_pid_;
-};
-
-// Initializes seccomp-bpf sandbox for non-SFI NaCl. Returns false on
-// failure.
-bool InitializeBPFSandbox(base::ScopedFD proc_fd);
-
-}  // namespace nonsfi
-}  // namespace nacl
-
-#endif  // COMPONENTS_NACL_LOADER_NONSFI_NONSFI_SANDBOX_H_
diff --git a/components/nacl/loader/nonsfi/nonsfi_sandbox_sigsys_unittest.cc b/components/nacl/loader/nonsfi/nonsfi_sandbox_sigsys_unittest.cc
deleted file mode 100644
index 582596f..0000000
--- a/components/nacl/loader/nonsfi/nonsfi_sandbox_sigsys_unittest.cc
+++ /dev/null
@@ -1,621 +0,0 @@
-// Copyright 2014 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.
-
-// Sanitizers internally use some syscalls which non-SFI NaCl disallows.
-#if !defined(ADDRESS_SANITIZER) && !defined(THREAD_SANITIZER) && \
-    !defined(MEMORY_SANITIZER) && !defined(LEAK_SANITIZER)
-
-#include "components/nacl/loader/nonsfi/nonsfi_sandbox.h"
-
-#include <sys/syscall.h>
-#include <unistd.h>
-
-#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
-#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
-#include "sandbox/linux/system_headers/linux_syscalls.h"
-
-namespace {
-
-// Test cases in this file just make sure syscalls not in the allow list
-// are appropriately disallowed. They should raise SIGSYS regardless
-// of arguments. We always pass five zeros not to pass uninitialized
-// values to syscalls.
-#define RESTRICT_SYSCALL_DEATH_TEST_IMPL(name, sysno)                   \
-  BPF_DEATH_TEST_C(NaClNonSfiSandboxSIGSYSTest,                         \
-                   name,                                                \
-                   DEATH_SEGV_MESSAGE(                                  \
-                       sandbox::GetErrorMessageContentForTests()),      \
-                   nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {          \
-    syscall(sysno, 0, 0, 0, 0, 0, 0);                                   \
-  }
-
-#define RESTRICT_SYSCALL_DEATH_TEST(name)               \
-  RESTRICT_SYSCALL_DEATH_TEST_IMPL(name, __NR_ ## name)
-
-#define RESTRICT_ARM_SYSCALL_DEATH_TEST(name)           \
-  RESTRICT_SYSCALL_DEATH_TEST_IMPL(ARM_ ## name, __ARM_NR_ ## name)
-
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(_newselect);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(_sysctl);
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(accept);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(accept4);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(access);
-RESTRICT_SYSCALL_DEATH_TEST(acct);
-RESTRICT_SYSCALL_DEATH_TEST(add_key);
-RESTRICT_SYSCALL_DEATH_TEST(adjtimex);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(afs_syscall);
-#endif
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(alarm);
-#endif
-#if defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(arch_prctl);
-#endif
-#if defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(arm_fadvise64_64);
-#endif
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(bdflush);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(bind);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(break);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(capget);
-RESTRICT_SYSCALL_DEATH_TEST(capset);
-RESTRICT_SYSCALL_DEATH_TEST(chdir);
-RESTRICT_SYSCALL_DEATH_TEST(chmod);
-RESTRICT_SYSCALL_DEATH_TEST(chown);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(chown32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(chroot);
-RESTRICT_SYSCALL_DEATH_TEST(clock_adjtime);
-RESTRICT_SYSCALL_DEATH_TEST(clock_nanosleep);
-RESTRICT_SYSCALL_DEATH_TEST(clock_settime);
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(connect);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(creat);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(create_module);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(delete_module);
-RESTRICT_SYSCALL_DEATH_TEST(dup3);
-RESTRICT_SYSCALL_DEATH_TEST(epoll_create1);
-RESTRICT_SYSCALL_DEATH_TEST(epoll_ctl);
-#if defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(epoll_ctl_old);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(epoll_pwait);
-RESTRICT_SYSCALL_DEATH_TEST(epoll_wait);
-#if defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(epoll_wait_old);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(eventfd);
-RESTRICT_SYSCALL_DEATH_TEST(eventfd2);
-RESTRICT_SYSCALL_DEATH_TEST(execve);
-RESTRICT_SYSCALL_DEATH_TEST(faccessat);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(fadvise64);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(fadvise64_64);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(fallocate);
-RESTRICT_SYSCALL_DEATH_TEST(fanotify_init);
-RESTRICT_SYSCALL_DEATH_TEST(fanotify_mark);
-RESTRICT_SYSCALL_DEATH_TEST(fchdir);
-RESTRICT_SYSCALL_DEATH_TEST(fchmod);
-RESTRICT_SYSCALL_DEATH_TEST(fchmodat);
-RESTRICT_SYSCALL_DEATH_TEST(fchown);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(fchown32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(fchownat);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(fcntl);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(fdatasync);
-RESTRICT_SYSCALL_DEATH_TEST(fgetxattr);
-RESTRICT_SYSCALL_DEATH_TEST(flistxattr);
-RESTRICT_SYSCALL_DEATH_TEST(flock);
-RESTRICT_SYSCALL_DEATH_TEST(fork);
-RESTRICT_SYSCALL_DEATH_TEST(fremovexattr);
-RESTRICT_SYSCALL_DEATH_TEST(fsetxattr);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(fstat);
-#endif
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(fstatat64);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(fstatfs);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(fstatfs64);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(fsync);
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(ftime);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(ftruncate);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(ftruncate64);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(futimesat);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(get_kernel_syms);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(get_mempolicy);
-RESTRICT_SYSCALL_DEATH_TEST(get_robust_list);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(get_thread_area);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(getcpu);
-RESTRICT_SYSCALL_DEATH_TEST(getcwd);
-RESTRICT_SYSCALL_DEATH_TEST(getdents);
-RESTRICT_SYSCALL_DEATH_TEST(getdents64);
-RESTRICT_SYSCALL_DEATH_TEST(getgroups);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(getgroups32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(getitimer);
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(getpeername);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(getpgid);
-RESTRICT_SYSCALL_DEATH_TEST(getpgrp);
-RESTRICT_SYSCALL_DEATH_TEST(getpid);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(getpmsg);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(getppid);
-RESTRICT_SYSCALL_DEATH_TEST(getpriority);
-RESTRICT_SYSCALL_DEATH_TEST(getresgid);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(getresgid32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(getresuid);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(getresuid32);
-#endif
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(getrlimit);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(getrusage);
-RESTRICT_SYSCALL_DEATH_TEST(getsid);
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(getsockname);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(getsockopt);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(getxattr);
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(gtty);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(idle);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(init_module);
-RESTRICT_SYSCALL_DEATH_TEST(inotify_add_watch);
-RESTRICT_SYSCALL_DEATH_TEST(inotify_init);
-RESTRICT_SYSCALL_DEATH_TEST(inotify_init1);
-RESTRICT_SYSCALL_DEATH_TEST(inotify_rm_watch);
-RESTRICT_SYSCALL_DEATH_TEST(io_cancel);
-RESTRICT_SYSCALL_DEATH_TEST(io_destroy);
-RESTRICT_SYSCALL_DEATH_TEST(io_getevents);
-RESTRICT_SYSCALL_DEATH_TEST(io_setup);
-RESTRICT_SYSCALL_DEATH_TEST(io_submit);
-RESTRICT_SYSCALL_DEATH_TEST(ioctl);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(ioperm);
-#endif
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(iopl);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(ioprio_get);
-RESTRICT_SYSCALL_DEATH_TEST(ioprio_set);
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(ipc);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(kexec_load);
-RESTRICT_SYSCALL_DEATH_TEST(keyctl);
-RESTRICT_SYSCALL_DEATH_TEST(kill);
-RESTRICT_SYSCALL_DEATH_TEST(lchown);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(lchown32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(lgetxattr);
-RESTRICT_SYSCALL_DEATH_TEST(link);
-RESTRICT_SYSCALL_DEATH_TEST(linkat);
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(listen);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(listxattr);
-RESTRICT_SYSCALL_DEATH_TEST(llistxattr);
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(lock);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(lookup_dcookie);
-RESTRICT_SYSCALL_DEATH_TEST(lremovexattr);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(lseek);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(lsetxattr);
-RESTRICT_SYSCALL_DEATH_TEST(lstat);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(lstat64);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(mbind);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(migrate_pages);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(mincore);
-RESTRICT_SYSCALL_DEATH_TEST(mkdir);
-RESTRICT_SYSCALL_DEATH_TEST(mkdirat);
-RESTRICT_SYSCALL_DEATH_TEST(mknod);
-RESTRICT_SYSCALL_DEATH_TEST(mknodat);
-RESTRICT_SYSCALL_DEATH_TEST(mlock);
-RESTRICT_SYSCALL_DEATH_TEST(mlockall);
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(mmap);
-#endif
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(modify_ldt);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(mount);
-RESTRICT_SYSCALL_DEATH_TEST(move_pages);
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(mpx);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(mq_getsetattr);
-RESTRICT_SYSCALL_DEATH_TEST(mq_notify);
-RESTRICT_SYSCALL_DEATH_TEST(mq_open);
-RESTRICT_SYSCALL_DEATH_TEST(mq_timedreceive);
-RESTRICT_SYSCALL_DEATH_TEST(mq_timedsend);
-RESTRICT_SYSCALL_DEATH_TEST(mq_unlink);
-RESTRICT_SYSCALL_DEATH_TEST(mremap);
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(msgctl);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(msgget);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(msgrcv);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(msgsnd);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(msync);
-RESTRICT_SYSCALL_DEATH_TEST(munlock);
-RESTRICT_SYSCALL_DEATH_TEST(munlockall);
-RESTRICT_SYSCALL_DEATH_TEST(name_to_handle_at);
-#if defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(newfstatat);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(nfsservctl);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(nice);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(oldfstat);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(oldlstat);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(oldolduname);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(oldstat);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(olduname);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(open_by_handle_at);
-RESTRICT_SYSCALL_DEATH_TEST(pause);
-#if defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(pciconfig_iobase);
-#endif
-#if defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(pciconfig_read);
-#endif
-#if defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(pciconfig_write);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(perf_event_open);
-RESTRICT_SYSCALL_DEATH_TEST(personality);
-RESTRICT_SYSCALL_DEATH_TEST(pipe2);
-RESTRICT_SYSCALL_DEATH_TEST(pivot_root);
-RESTRICT_SYSCALL_DEATH_TEST(ppoll);
-RESTRICT_SYSCALL_DEATH_TEST(preadv);
-RESTRICT_SYSCALL_DEATH_TEST(prlimit64);
-RESTRICT_SYSCALL_DEATH_TEST(process_vm_readv);
-RESTRICT_SYSCALL_DEATH_TEST(process_vm_writev);
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(prof);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(profil);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(pselect6);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(putpmsg);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(pwritev);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(query_module);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(quotactl);
-RESTRICT_SYSCALL_DEATH_TEST(readahead);
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(readdir);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(readlink);
-RESTRICT_SYSCALL_DEATH_TEST(readlinkat);
-RESTRICT_SYSCALL_DEATH_TEST(readv);
-RESTRICT_SYSCALL_DEATH_TEST(reboot);
-#if defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(recv);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(recvfrom);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(recvmmsg);
-RESTRICT_SYSCALL_DEATH_TEST(remap_file_pages);
-RESTRICT_SYSCALL_DEATH_TEST(removexattr);
-RESTRICT_SYSCALL_DEATH_TEST(rename);
-RESTRICT_SYSCALL_DEATH_TEST(renameat);
-RESTRICT_SYSCALL_DEATH_TEST(request_key);
-RESTRICT_SYSCALL_DEATH_TEST(rmdir);
-RESTRICT_SYSCALL_DEATH_TEST(rt_sigaction);
-RESTRICT_SYSCALL_DEATH_TEST(rt_sigpending);
-RESTRICT_SYSCALL_DEATH_TEST(rt_sigprocmask);
-RESTRICT_SYSCALL_DEATH_TEST(rt_sigqueueinfo);
-RESTRICT_SYSCALL_DEATH_TEST(rt_sigreturn);
-RESTRICT_SYSCALL_DEATH_TEST(rt_sigsuspend);
-RESTRICT_SYSCALL_DEATH_TEST(rt_sigtimedwait);
-RESTRICT_SYSCALL_DEATH_TEST(rt_tgsigqueueinfo);
-RESTRICT_SYSCALL_DEATH_TEST(sched_get_priority_max);
-RESTRICT_SYSCALL_DEATH_TEST(sched_get_priority_min);
-RESTRICT_SYSCALL_DEATH_TEST(sched_getaffinity);
-RESTRICT_SYSCALL_DEATH_TEST(sched_getparam);
-RESTRICT_SYSCALL_DEATH_TEST(sched_getscheduler);
-RESTRICT_SYSCALL_DEATH_TEST(sched_rr_get_interval);
-RESTRICT_SYSCALL_DEATH_TEST(sched_setaffinity);
-RESTRICT_SYSCALL_DEATH_TEST(sched_setparam);
-RESTRICT_SYSCALL_DEATH_TEST(sched_setscheduler);
-#if defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(security);
-#endif
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(select);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(semctl);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(semget);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(semop);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(semtimedop);
-#endif
-#if defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(send);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(sendfile);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(sendfile64);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(sendmmsg);
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(sendto);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(set_mempolicy);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(set_thread_area);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(set_tid_address);
-RESTRICT_SYSCALL_DEATH_TEST(setdomainname);
-RESTRICT_SYSCALL_DEATH_TEST(setfsgid);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(setfsgid32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(setfsuid);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(setfsuid32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(setgid);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(setgid32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(setgroups);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(setgroups32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(sethostname);
-RESTRICT_SYSCALL_DEATH_TEST(setitimer);
-RESTRICT_SYSCALL_DEATH_TEST(setns);
-RESTRICT_SYSCALL_DEATH_TEST(setpgid);
-RESTRICT_SYSCALL_DEATH_TEST(setpriority);
-RESTRICT_SYSCALL_DEATH_TEST(setregid);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(setregid32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(setresgid);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(setresgid32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(setresuid);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(setresuid32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(setreuid);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(setreuid32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(setrlimit);
-RESTRICT_SYSCALL_DEATH_TEST(setsid);
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(setsockopt);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(settimeofday);
-RESTRICT_SYSCALL_DEATH_TEST(setuid);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(setuid32);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(setxattr);
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(sgetmask);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(shmat);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(shmctl);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(shmdt);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(shmget);
-#endif
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(sigaction);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(signal);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(signalfd);
-RESTRICT_SYSCALL_DEATH_TEST(signalfd4);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(sigpending);
-#endif
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(sigprocmask);
-#endif
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(sigreturn);
-#endif
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(sigsuspend);
-#endif
-#if defined(__x86_64__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(socket);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(splice);
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(ssetmask);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(stat);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(stat64);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(statfs);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(statfs64);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(stime);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(stty);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(swapoff);
-RESTRICT_SYSCALL_DEATH_TEST(swapon);
-RESTRICT_SYSCALL_DEATH_TEST(symlink);
-RESTRICT_SYSCALL_DEATH_TEST(symlinkat);
-RESTRICT_SYSCALL_DEATH_TEST(sync);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(sync_file_range);
-#endif
-#if defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(sync_file_range2);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(syncfs);
-RESTRICT_SYSCALL_DEATH_TEST(sysfs);
-RESTRICT_SYSCALL_DEATH_TEST(sysinfo);
-RESTRICT_SYSCALL_DEATH_TEST(syslog);
-RESTRICT_SYSCALL_DEATH_TEST(tee);
-RESTRICT_SYSCALL_DEATH_TEST(tgkill);
-RESTRICT_SYSCALL_DEATH_TEST(timer_create);
-RESTRICT_SYSCALL_DEATH_TEST(timer_delete);
-RESTRICT_SYSCALL_DEATH_TEST(timer_getoverrun);
-RESTRICT_SYSCALL_DEATH_TEST(timer_gettime);
-RESTRICT_SYSCALL_DEATH_TEST(timer_settime);
-RESTRICT_SYSCALL_DEATH_TEST(timerfd_create);
-RESTRICT_SYSCALL_DEATH_TEST(timerfd_gettime);
-RESTRICT_SYSCALL_DEATH_TEST(timerfd_settime);
-RESTRICT_SYSCALL_DEATH_TEST(tkill);
-RESTRICT_SYSCALL_DEATH_TEST(truncate);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(truncate64);
-#endif
-#if defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(tuxcall);
-#endif
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_DEATH_TEST(ugetrlimit);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(ulimit);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(umask);
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(umount);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(umount2);
-RESTRICT_SYSCALL_DEATH_TEST(uname);
-RESTRICT_SYSCALL_DEATH_TEST(unlink);
-RESTRICT_SYSCALL_DEATH_TEST(unlinkat);
-RESTRICT_SYSCALL_DEATH_TEST(unshare);
-RESTRICT_SYSCALL_DEATH_TEST(uselib);
-RESTRICT_SYSCALL_DEATH_TEST(ustat);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_DEATH_TEST(utime);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(utimensat);
-RESTRICT_SYSCALL_DEATH_TEST(utimes);
-RESTRICT_SYSCALL_DEATH_TEST(vfork);
-RESTRICT_SYSCALL_DEATH_TEST(vhangup);
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(vm86);
-#endif
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(vm86old);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(vmsplice);
-RESTRICT_SYSCALL_DEATH_TEST(vserver);
-RESTRICT_SYSCALL_DEATH_TEST(wait4);
-RESTRICT_SYSCALL_DEATH_TEST(waitid);
-#if defined(__i386__)
-RESTRICT_SYSCALL_DEATH_TEST(waitpid);
-#endif
-RESTRICT_SYSCALL_DEATH_TEST(writev);
-
-// ARM specific syscalls.
-#if defined(__arm__)
-RESTRICT_ARM_SYSCALL_DEATH_TEST(breakpoint);
-RESTRICT_ARM_SYSCALL_DEATH_TEST(usr26);
-RESTRICT_ARM_SYSCALL_DEATH_TEST(usr32);
-RESTRICT_ARM_SYSCALL_DEATH_TEST(set_tls);
-#endif
-
-}  // namespace
-
-#endif  // !ADDRESS_SANITIZER && !THREAD_SANITIZER &&
-        // !MEMORY_SANITIZER && !LEAK_SANITIZER
diff --git a/components/nacl/loader/nonsfi/nonsfi_sandbox_unittest.cc b/components/nacl/loader/nonsfi/nonsfi_sandbox_unittest.cc
deleted file mode 100644
index 91b95234..0000000
--- a/components/nacl/loader/nonsfi/nonsfi_sandbox_unittest.cc
+++ /dev/null
@@ -1,715 +0,0 @@
-// Copyright 2014 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.
-
-// Sanitizers internally use some syscalls which non-SFI NaCl disallows.
-#if !defined(ADDRESS_SANITIZER) && !defined(THREAD_SANITIZER) && \
-    !defined(MEMORY_SANITIZER) && !defined(LEAK_SANITIZER)
-
-#include "components/nacl/loader/nonsfi/nonsfi_sandbox.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/net.h>
-#include <pthread.h>
-#include <sched.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <memory>
-
-#include "base/at_exit.h"
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/files/scoped_file.h"
-#include "base/logging.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/rand_util.h"
-#include "base/system/sys_info.h"
-#include "base/threading/thread.h"
-#include "base/time/time.h"
-#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
-#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
-#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
-#include "sandbox/linux/seccomp-bpf/syscall.h"
-#include "sandbox/linux/system_headers/linux_futex.h"
-#include "sandbox/linux/system_headers/linux_signal.h"
-#include "sandbox/linux/system_headers/linux_syscalls.h"
-#include "sandbox/linux/system_headers/linux_time.h"
-
-// These defines are for PNaCl toolchain build.
-#if !defined(F_DUPFD_CLOEXEC)
-#define F_DUPFD_CLOEXEC 1030
-#endif
-
-#if !defined(MAP_POPULATE)
-#define MAP_POPULATE 0x8000
-#endif
-
-#if !defined(PROT_GROWSDOWN)
-#define PROT_GROWSDOWN 0x01000000
-#endif
-
-#if !defined(AF_INET)
-#define AF_INET 2
-#endif
-
-#if defined(__i386__)
-
-#if !defined(SYS_SOCKET)
-#define SYS_SOCKET 1
-#endif
-
-#if !defined(SYS_BIND)
-#define SYS_BIND 2
-#endif
-
-#if !defined(SYS_CONNECT)
-#define SYS_CONNECT 3
-#endif
-
-#if !defined(SYS_LISTEN)
-#define SYS_LISTEN 4
-#endif
-
-#if !defined(SYS_ACCEPT)
-#define SYS_ACCEPT 5
-#endif
-
-#if !defined(SYS_GETSOCKNAME)
-#define SYS_GETSOCKNAME 6
-#endif
-
-#if !defined(SYS_GETPEERNAME)
-#define SYS_GETPEERNAME 7
-#endif
-
-#if !defined(SYS_SETSOCKOPT)
-#define SYS_SETSOCKOPT 14
-#endif
-
-#if !defined(SYS_GETSOCKOPT)
-#define SYS_GETSOCKOPT 15
-#endif
-
-#endif // defined(__i386__)
-
-namespace {
-
-void DoPipe(base::ScopedFD* fds) {
-  int tmp_fds[2];
-  BPF_ASSERT_EQ(0, pipe(tmp_fds));
-  fds[0].reset(tmp_fds[0]);
-  fds[1].reset(tmp_fds[1]);
-}
-
-TEST(NaClNonSfiSandboxTest, BPFIsSupported) {
-  bool seccomp_bpf_supported = sandbox::SandboxBPF::SupportsSeccompSandbox(
-      sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED);
-
-  if (!seccomp_bpf_supported) {
-    LOG(ERROR) << "Seccomp BPF is not supported, these tests "
-               << "will pass without running";
-  }
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 invalid_sysno,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  syscall(999);
-}
-
-const int kExpectedValue = 123;
-
-void* SetValueInThread(void* test_val_ptr) {
-  *reinterpret_cast<int*>(test_val_ptr) = kExpectedValue;
-  return NULL;
-}
-
-// To make this test pass, we need to allow sched_getaffinity and
-// mmap. We just disable this test not to complicate the sandbox.
-BPF_TEST_C(NaClNonSfiSandboxTest,
-           clone_by_pthread_create,
-           nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  // clone call for thread creation is allowed.
-  pthread_t th;
-  int test_val = 42;
-  BPF_ASSERT_EQ(0, pthread_create(&th, NULL, &SetValueInThread, &test_val));
-  BPF_ASSERT_EQ(0, pthread_join(th, NULL));
-  BPF_ASSERT_EQ(kExpectedValue, test_val);
-}
-
-int DoFork() {
-  // Call clone() to do a fork().
-  const int pid = syscall(__NR_clone, LINUX_SIGCHLD, NULL);
-  if (pid == 0)
-    _exit(0);
-  return pid;
-}
-
-// The sanity check for DoFork without the sandbox.
-TEST(NaClNonSfiSandboxTest, DoFork) {
-  const int pid = DoFork();
-  ASSERT_LT(0, pid);
-  int status;
-  ASSERT_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0)));
-  ASSERT_TRUE(WIFEXITED(status));
-  ASSERT_EQ(0, WEXITSTATUS(status));
-}
-
-// Then, try this in the sandbox.
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 clone_for_fork,
-                 DEATH_SEGV_MESSAGE(
-                     sandbox::GetCloneErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  DoFork();
-}
-
-BPF_TEST_C(NaClNonSfiSandboxTest,
-           prctl_SET_NAME,
-           nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  errno = 0;
-  BPF_ASSERT_EQ(-1, syscall(__NR_prctl, PR_SET_NAME, "foo"));
-  BPF_ASSERT_EQ(EPERM, errno);
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 prctl_SET_DUMPABLE,
-                 DEATH_SEGV_MESSAGE(
-                     sandbox::GetPrctlErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  syscall(__NR_prctl, PR_SET_DUMPABLE, 1UL);
-}
-
-BPF_DEATH_TEST_C(NaClNonsfiSandboxTest,
-                 socketpair_af_unix_disallowed,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  int tmp_fds[2];
-  socketpair(AF_UNIX, SOCK_STREAM, 0, tmp_fds);
-}
-
-// On arm and x86_64 the arguments to socketpair are passed in registers,
-// so they can be filtered by seccomp-bpf.  This filter cannot be applied
-// on x86_32 as the arguments are passed in memory.
-#if defined(__x86_64__) || defined(__arm__)
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 socketpair_af_inet_disallowed,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  int fds[2];
-  socketpair(AF_INET, SOCK_STREAM, 0, fds);
-}
-#endif
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 accept,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(__i386__)
-  uintptr_t args[] = {0, 0, 0};
-  syscall(__NR_socketcall, SYS_ACCEPT, args);
-#else
-  syscall(__NR_accept, 0, 0, 0);
-#endif
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 bind,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(__i386__)
-  uintptr_t args[] = {0, 0, 0};
-  syscall(__NR_socketcall, SYS_BIND, args);
-#else
-  syscall(__NR_bind, 0, 0, 0);
-#endif
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 connect,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(__i386__)
-  uintptr_t args[] = {0, 0, 0};
-  syscall(__NR_socketcall, SYS_CONNECT, args);
-#else
-  syscall(__NR_connect, 0, 0, 0);
-#endif
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 getpeername,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(__i386__)
-  uintptr_t args[] = {0, 0, 0};
-  syscall(__NR_socketcall, SYS_GETPEERNAME, args);
-#else
-  syscall(__NR_getpeername, 0, 0, 0);
-#endif
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 getsockname,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(__i386__)
-  uintptr_t args[] = {0, 0, 0};
-  syscall(__NR_socketcall, SYS_GETSOCKNAME, args);
-#else
-  syscall(__NR_getsockname, 0, 0, 0);
-#endif
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 getsockopt,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(__i386__)
-  uintptr_t args[] = {0, 0, 0, 0, 0};
-  syscall(__NR_socketcall, SYS_GETSOCKOPT, args);
-#else
-  syscall(__NR_getsockname, 0, 0, 0, 0, 0);
-#endif
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 listen,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(__i386__)
-  uintptr_t args[] = {0, 0};
-  syscall(__NR_socketcall, SYS_LISTEN, args);
-#else
-  syscall(__NR_listen, 0, 0);
-#endif
-}
-
-// On x86_64 architecture, there is no __NR_recv system call. Note: recv()
-// syscall wrapper usually uses __NR_recvfrom, instead, (like in glibc).
-#if defined(__i386__) || defined(__arm__)
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 recv,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(__i386__)
-  uintptr_t args[] = {0, 0, 0, 0};
-  syscall(__NR_socketcall, SYS_RECV, args);
-#else
-  syscall(__NR_recv, 0, 0, 0, 0);
-#endif
-}
-#endif
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 recvfrom,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(__i386__)
-  uintptr_t args[] = {0, 0, 0, 0, 0, 0};
-  syscall(__NR_socketcall, SYS_RECVFROM, args);
-#else
-  syscall(__NR_recvfrom, 0, 0, 0, 0, 0, 0);
-#endif
-}
-
-// On x86_64 architecture, there is no __NR_send system call. Note: send()
-// syscall wrapper usually uses __NR_sendto, instead, (like in glibc).
-#if defined(__i386__) || defined(__arm__)
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 send,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(__i386__)
-  uintptr_t args[] = {0, 0, 0, 0};
-  syscall(__NR_socketcall, SYS_SEND, args);
-#else
-  syscall(__NR_send, 0, 0, 0, 0);
-#endif
-}
-#endif
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 sendto,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(__i386__)
-  uintptr_t args[] = {0, 0, 0, 0, 0, 0};
-  syscall(__NR_socketcall, SYS_SENDTO, args);
-#else
-  syscall(__NR_sendto, 0, 0, 0, 0, 0, 0);
-#endif
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 setsockopt,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(__i386__)
-  uintptr_t args[] = {0, 0, 0, 0, 0};
-  syscall(__NR_socketcall, SYS_SETSOCKOPT, args);
-#else
-  syscall(__NR_setsockopt, 0, 0, 0, 0, 0);
-#endif
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 socket,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(__i386__)
-  uintptr_t args[] = {0, 0, 0};
-  syscall(__NR_socketcall, SYS_SOCKET, args);
-#else
-  syscall(__NR_socket, 0, 0, 0);
-#endif
-}
-
-BPF_TEST_C(NaClNonSfiSandboxTest,
-           fcntl_SETFD_allowed,
-           nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  base::ScopedFD fds[2];
-  DoPipe(fds);
-  BPF_ASSERT_EQ(0, fcntl(fds[0].get(), F_SETFD, FD_CLOEXEC));
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 fcntl_SETFD,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  base::ScopedFD fds[2];
-  DoPipe(fds);
-  fcntl(fds[0].get(), F_SETFD, 99);
-}
-
-BPF_TEST_C(NaClNonSfiSandboxTest,
-           fcntl_GETFL_SETFL_allowed,
-           nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  base::ScopedFD fds[2];
-  DoPipe(fds);
-  const int fd = fds[0].get();
-  BPF_ASSERT_EQ(0, fcntl(fd, F_GETFL));
-  BPF_ASSERT_EQ(0, fcntl(fd, F_SETFL, O_RDWR | O_NONBLOCK));
-  BPF_ASSERT_EQ(O_NONBLOCK, fcntl(fd, F_GETFL));
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 fcntl_GETFL_SETFL,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  base::ScopedFD fds[2];
-  DoPipe(fds);
-  fcntl(fds[0].get(), F_SETFL, O_APPEND);
-}
-
-void DoFcntl(int fd, int cmd) {
-  // fcntl in PNaCl toolchain returns an error without calling actual system
-  // call for unknown |cmd|. So, instead, here we use syscall().
-  syscall(__NR_fcntl64, fd, cmd);
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 fcntl_DUPFD,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  DoFcntl(0, F_DUPFD);
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 fcntl_DUPFD_CLOEXEC,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  DoFcntl(0, F_DUPFD_CLOEXEC);
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 FutexWithRequeuePriorityInheritence,
-                 DEATH_SEGV_MESSAGE(
-                     sandbox::GetFutexErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI, 0, NULL, NULL, 0);
-  _exit(1);
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 FutexWithRequeuePriorityInheritencePrivate,
-                 DEATH_SEGV_MESSAGE(
-                     sandbox::GetFutexErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI_PRIVATE, 0, NULL, NULL, 0);
-  _exit(1);
-}
-
-BPF_TEST_C(NaClNonSfiSandboxTest,
-           StartingAndJoiningThreadWorks,
-           nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  base::Thread thread("sandbox_tests");
-  BPF_ASSERT(thread.Start());
-  // |thread|'s destructor will join the thread.
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 FutexWithUnlockPIPrivate,
-                 DEATH_SEGV_MESSAGE(
-                     sandbox::GetFutexErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  syscall(__NR_futex, NULL, FUTEX_UNLOCK_PI_PRIVATE, 0, NULL, NULL, 0);
-  _exit(1);
-}
-
-void* DoMmap(int prot, int flags) {
-  // When PROT_EXEC is set, PNaCl toolchain's mmap() system call wrapper uses
-  // two system calls mmap2(2) and mprotect(2), so that we cannot test
-  // sandbox with the wrapper. Instead, here we use syscall().
-  return reinterpret_cast<void*>(
-      syscall(__NR_mmap2, NULL, getpagesize(), prot, flags, -1, 0));
-}
-
-void* DoAllowedAnonymousMmap() {
-  return DoMmap(PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED);
-}
-
-BPF_TEST_C(NaClNonSfiSandboxTest,
-           mmap_allowed,
-           nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  void* ptr = DoAllowedAnonymousMmap();
-  BPF_ASSERT_NE(MAP_FAILED, ptr);
-  BPF_ASSERT_EQ(0, munmap(ptr, getpagesize()));
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 mmap_unallowed_flag,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  DoMmap(PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_POPULATE);
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 mmap_unallowed_prot,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  DoMmap(PROT_READ | PROT_GROWSDOWN, MAP_ANONYMOUS);
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 mmap_exec,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  DoMmap(PROT_EXEC, MAP_ANONYMOUS);
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 mmap_read_exec,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  DoMmap(PROT_READ | PROT_EXEC, MAP_ANONYMOUS);
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 mmap_write_exec,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  DoMmap(PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS);
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 mmap_read_write_exec,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  DoMmap(PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS);
-}
-
-BPF_TEST_C(NaClNonSfiSandboxTest,
-           mprotect_allowed,
-           nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  void* ptr = DoAllowedAnonymousMmap();
-  BPF_ASSERT_NE(MAP_FAILED, ptr);
-  BPF_ASSERT_EQ(0, mprotect(ptr, getpagesize(), PROT_READ));
-  BPF_ASSERT_EQ(0, munmap(ptr, getpagesize()));
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 mprotect_unallowed_prot,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  // We have tested DoAllowedAnonymousMmap is allowed in
-  // mmap_allowed, so we can make sure the following mprotect call
-  // kills the process.
-  void* ptr = DoAllowedAnonymousMmap();
-  BPF_ASSERT_NE(MAP_FAILED, ptr);
-  mprotect(ptr, getpagesize(), PROT_READ | PROT_GROWSDOWN);
-}
-
-BPF_TEST_C(NaClNonSfiSandboxTest,
-           brk,
-           nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  char* next_brk = static_cast<char*>(sbrk(0)) + getpagesize();
-  // The kernel interface must return zero for brk.
-  BPF_ASSERT_EQ(0, syscall(__NR_brk, next_brk));
-}
-
-// clockid restrictions are mostly tested in sandbox/ with the
-// RestrictClockID() unittests. Some basic tests are duplicated here as
-// a precaution.
-
-void CheckClock(clockid_t clockid) {
-  struct timespec ts;
-  ts.tv_sec = ts.tv_nsec = -1;
-  BPF_ASSERT_EQ(0, clock_gettime(clockid, &ts));
-  BPF_ASSERT_LE(0, ts.tv_sec);
-  BPF_ASSERT_LE(0, ts.tv_nsec);
-}
-
-BPF_TEST_C(NaClNonSfiSandboxTest,
-           clock_gettime_allowed,
-           nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  CheckClock(CLOCK_MONOTONIC);
-  CheckClock(CLOCK_PROCESS_CPUTIME_ID);
-  CheckClock(CLOCK_REALTIME);
-  CheckClock(CLOCK_THREAD_CPUTIME_ID);
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 clock_gettime_crash_clock_fd,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  struct timespec ts;
-  // Negative clock IDs are per pid/tid or clock FDs - and are disallowed.
-  clock_gettime(-1, &ts);
-}
-
-BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
-                 invalid_syscall_crash,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  sandbox::Syscall::InvalidCall();
-}
-
-BPF_TEST_C(NaClNonSfiSandboxTest,
-           random,
-           nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-  // Ensure that UrandomFD is valid.
-  int urandom_fd = base::GetUrandomFD();
-  BPF_ASSERT_NE(-1, urandom_fd);
-
-  // The test should pass if the base::Rand*() don't crash.
-  base::RandDouble();
-}
-
-// The following tests check for several restrictions in tgkill(). A delegate is
-// needed to be able to call getpid() from inside the process that will be
-// sandboxed, but before the sandbox is installed.
-template<void(*callback)(int pid, int tid)>
-class TgkillDelegate : public sandbox::BPFTesterDelegate {
- public:
-  TgkillDelegate() {}
-
-  TgkillDelegate(const TgkillDelegate&) = delete;
-  TgkillDelegate& operator=(const TgkillDelegate&) = delete;
-
-  ~TgkillDelegate() override {}
-
-  std::unique_ptr<sandbox::bpf_dsl::Policy> GetSandboxBPFPolicy() override {
-    // These two values must be obtained when running in the sandboxed process.
-    // They cannot be set in the constructor and are also not available from
-    // within |RunTestFunction|.
-    pid_ = getpid();
-    tid_ = syscall(__NR_gettid);
-
-    return std::unique_ptr<sandbox::bpf_dsl::Policy>(
-        new nacl::nonsfi::NaClNonSfiBPFSandboxPolicy());
-  }
-
-  void RunTestFunction() override {
-    callback(pid_, tid_);
-  }
-
-  // These are longs as a temporary workaround for crbug.com/532992.
-  long pid_;
-  long tid_;
-};
-
-void BPF_TEST_D_tgkill_with_invalid_signal(int pid, int tid) {
-  syscall(__NR_tgkill, pid, tid, SIGKILL);
-}
-
-BPF_DEATH_TEST_D(NaClNonSfiSandboxTest,
-                 tgkill_with_invalid_signal,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 TgkillDelegate<BPF_TEST_D_tgkill_with_invalid_signal>);
-
-void BPF_TEST_D_tgkill_with_invalid_tgid(int pid, int tid) {
-  syscall(__NR_tgkill, 1, tid, LINUX_SIGUSR1);
-}
-
-BPF_DEATH_TEST_D(NaClNonSfiSandboxTest,
-                 tgkill_with_invalid_tgid,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 TgkillDelegate<BPF_TEST_D_tgkill_with_invalid_tgid>);
-
-void BPF_TEST_D_tgkill_with_negative_tgid(int pid, int tid) {
-  syscall(__NR_tgkill, pid, -1, LINUX_SIGUSR1);
-}
-
-BPF_DEATH_TEST_D(NaClNonSfiSandboxTest,
-                 tgkill_with_negative_tgid,
-                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
-                 TgkillDelegate<BPF_TEST_D_tgkill_with_negative_tgid>);
-
-void BPF_TEST_D_tgkill_with_invalid_tid(int pid, int tid) {
-  BPF_ASSERT_EQ(-1, syscall(__NR_tgkill, pid, 1, LINUX_SIGUSR1));
-  BPF_ASSERT_EQ(ESRCH, errno);
-}
-
-BPF_TEST_D(NaClNonSfiSandboxTest,
-           tgkill_with_invalid_tid,
-           TgkillDelegate<BPF_TEST_D_tgkill_with_invalid_tid>);
-
-// The following test cases check if syscalls return EPERM regardless
-// of arguments.
-#define RESTRICT_SYSCALL_EPERM_TEST(name)                      \
-  BPF_TEST_C(NaClNonSfiSandboxTest,                            \
-             name##_EPERM,                                     \
-             nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {       \
-    errno = 0;                                                 \
-    BPF_ASSERT_EQ(-1, syscall(__NR_##name, 0, 0, 0, 0, 0, 0)); \
-    BPF_ASSERT_EQ(EPERM, errno);                               \
-  }
-
-RESTRICT_SYSCALL_EPERM_TEST(epoll_create);
-#if defined(__i386__) || defined(__arm__)
-RESTRICT_SYSCALL_EPERM_TEST(getegid32);
-RESTRICT_SYSCALL_EPERM_TEST(geteuid32);
-RESTRICT_SYSCALL_EPERM_TEST(getgid32);
-RESTRICT_SYSCALL_EPERM_TEST(getuid32);
-#endif
-RESTRICT_SYSCALL_EPERM_TEST(getegid);
-RESTRICT_SYSCALL_EPERM_TEST(geteuid);
-RESTRICT_SYSCALL_EPERM_TEST(getgid);
-RESTRICT_SYSCALL_EPERM_TEST(getuid);
-RESTRICT_SYSCALL_EPERM_TEST(madvise);
-RESTRICT_SYSCALL_EPERM_TEST(open);
-RESTRICT_SYSCALL_EPERM_TEST(openat);
-RESTRICT_SYSCALL_EPERM_TEST(ptrace);
-RESTRICT_SYSCALL_EPERM_TEST(set_robust_list);
-#if defined(__i386__) || defined(__x86_64__)
-RESTRICT_SYSCALL_EPERM_TEST(time);
-#endif
-
-}  // namespace
-
-#endif  // !ADDRESS_SANITIZER && !THREAD_SANITIZER &&
-        // !MEMORY_SANITIZER && !LEAK_SANITIZER
diff --git a/components/nacl/loader/nonsfi/run_all_unittests.cc b/components/nacl/loader/nonsfi/run_all_unittests.cc
deleted file mode 100644
index 7da3e83..0000000
--- a/components/nacl/loader/nonsfi/run_all_unittests.cc
+++ /dev/null
@@ -1,28 +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 "base/at_exit.h"
-#include "base/bind.h"
-#include "base/rand_util.h"
-#include "base/test/launcher/unit_test_launcher.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-int RunAllTestsImpl() {
-  return RUN_ALL_TESTS();
-}
-
-}  // namespace
-
-int main(int argc, char** argv) {
-  base::AtExitManager at_exit;
-  testing::InitGoogleTest(&argc, argv);
-
-  // Force early initialisation of /dev/urandom FD as it can't be initialised
-  // from a sandbox.
-  base::GetUrandomFD();
-
-  return base::LaunchUnitTests(argc, argv, base::BindOnce(&RunAllTestsImpl));
-}
diff --git a/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc b/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc
index acb6c07..0f20fa6 100644
--- a/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc
+++ b/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc
@@ -25,7 +25,6 @@
 #include "base/rand_util.h"
 #include "build/build_config.h"
 #include "components/nacl/common/nacl_switches.h"
-#include "components/nacl/loader/nonsfi/nonsfi_sandbox.h"
 #include "components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.h"
 #include "content/public/common/content_switches.h"
 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
@@ -193,14 +192,8 @@
   // Pass proc_fd_ ownership to the BPF sandbox, which guarantees it will
   // be closed. There is no point in keeping it around since the BPF policy
   // will prevent its usage.
-#if defined(OS_NACL_NONSFI)
-  CHECK(uses_nonsfi_mode);
-  layer_two_enabled_ = nacl::nonsfi::InitializeBPFSandbox(std::move(proc_fd_));
-  layer_two_is_nonsfi_ = true;
-#else
   CHECK(!uses_nonsfi_mode);
   layer_two_enabled_ = nacl::InitializeBPFSandbox(std::move(proc_fd_));
-#endif
 }
 
 void NaClSandbox::SealLayerOneSandbox() {
@@ -218,19 +211,7 @@
   static const char kItIsNotAllowedMsg[] =
       " this is not allowed in this configuration.";
 
-  const bool no_sandbox_for_nonsfi_ok =
-#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
-    defined(MEMORY_SANITIZER) || defined(LEAK_SANITIZER)
-      // Sanitizer tests run with --no-sandbox, but without
-      // --nacl-dangerous-no-sandbox-nonsfi. Allow that case.
-      true;
-#else
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kNaClDangerousNoSandboxNonSfi);
-#endif
-
-  const bool can_be_no_sandbox =
-      !layer_two_is_nonsfi_ || no_sandbox_for_nonsfi_ok;
+  const bool can_be_no_sandbox = !layer_two_is_nonsfi_;
 
   if (!layer_one_enabled_ || !layer_one_sealed_) {
     static const char kNoSuidMsg[] =
diff --git a/components/page_info/android/connection_info_view_android.cc b/components/page_info/android/connection_info_view_android.cc
index 70d03a2..86222e3 100644
--- a/components/page_info/android/connection_info_view_android.cc
+++ b/components/page_info/android/connection_info_view_android.cc
@@ -53,7 +53,7 @@
   // Important to use GetVisibleEntry to match what's showing in the omnibox.
   content::NavigationEntry* nav_entry =
       web_contents->GetController().GetVisibleEntry();
-  if (nav_entry == nullptr)
+  if (nav_entry->IsInitialEntry())
     return;
 
   popup_jobject_.Reset(env, java_page_info_pop);
diff --git a/components/page_info/android/page_info_controller_android.cc b/components/page_info/android/page_info_controller_android.cc
index 0d4c623..3ffbeb6 100644
--- a/components/page_info/android/page_info_controller_android.cc
+++ b/components/page_info/android/page_info_controller_android.cc
@@ -49,7 +49,7 @@
   // Important to use GetVisibleEntry to match what's showing in the omnibox.
   content::NavigationEntry* nav_entry =
       web_contents->GetController().GetVisibleEntry();
-  if (nav_entry == nullptr)
+  if (nav_entry->IsInitialEntry())
     return;
 
   url_ = nav_entry->GetURL();
diff --git a/components/password_manager/core/browser/leak_detection_dialog_utils.cc b/components/password_manager/core/browser/leak_detection_dialog_utils.cc
index e36987e..8d4ae11 100644
--- a/components/password_manager/core/browser/leak_detection_dialog_utils.cc
+++ b/components/password_manager/core/browser/leak_detection_dialog_utils.cc
@@ -88,20 +88,39 @@
 }
 
 std::u16string GetDescription(CredentialLeakType leak_type) {
-  if (ShouldShowChangePasswordButton(leak_type)) {
+  if (base::FeatureList::IsEnabled(
+          password_manager::features::
+              kIOSEnablePasswordManagerBrandingUpdate)) {
+    if (ShouldShowChangePasswordButton(leak_type)) {
+      return l10n_util::GetStringUTF16(
+          IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_AUTOMATICALLY_MESSAGE);
+    }
+    if (!ShouldCheckPasswords(leak_type)) {
+      return l10n_util::GetStringUTF16(
+          IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_BRANDED);
+    }
+    if (password_manager::IsPasswordSaved(leak_type)) {
+      return l10n_util::GetStringUTF16(
+          IDS_CREDENTIAL_LEAK_CHECK_PASSWORDS_MESSAGE_BRANDED);
+    }
     return l10n_util::GetStringUTF16(
-        IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_AUTOMATICALLY_MESSAGE);
-  }
-  if (!ShouldCheckPasswords(leak_type)) {
+        IDS_CREDENTIAL_LEAK_CHANGE_AND_CHECK_PASSWORDS_MESSAGE_BRANDED);
+  } else {
+    if (ShouldShowChangePasswordButton(leak_type)) {
+      return l10n_util::GetStringUTF16(
+          IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_AUTOMATICALLY_MESSAGE);
+    }
+    if (!ShouldCheckPasswords(leak_type)) {
+      return l10n_util::GetStringUTF16(
+          IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE);
+    }
+    if (password_manager::IsPasswordSaved(leak_type)) {
+      return l10n_util::GetStringUTF16(
+          IDS_CREDENTIAL_LEAK_CHECK_PASSWORDS_MESSAGE);
+    }
     return l10n_util::GetStringUTF16(
-        IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE);
+        IDS_CREDENTIAL_LEAK_CHANGE_AND_CHECK_PASSWORDS_MESSAGE);
   }
-  if (password_manager::IsPasswordSaved(leak_type)) {
-    return l10n_util::GetStringUTF16(
-        IDS_CREDENTIAL_LEAK_CHECK_PASSWORDS_MESSAGE);
-  }
-  return l10n_util::GetStringUTF16(
-      IDS_CREDENTIAL_LEAK_CHANGE_AND_CHECK_PASSWORDS_MESSAGE);
 }
 
 std::u16string GetTitle(CredentialLeakType leak_type) {
@@ -109,10 +128,18 @@
     return l10n_util::GetStringUTF16(
         IDS_CREDENTIAL_LEAK_TITLE_CHANGE_AUTOMATICALLY);
   }
-
-  return l10n_util::GetStringUTF16(ShouldCheckPasswords(leak_type)
-                                       ? IDS_CREDENTIAL_LEAK_TITLE_CHECK
-                                       : IDS_CREDENTIAL_LEAK_TITLE_CHANGE);
+  if (base::FeatureList::IsEnabled(
+          password_manager::features::
+              kIOSEnablePasswordManagerBrandingUpdate)) {
+    return l10n_util::GetStringUTF16(
+        ShouldCheckPasswords(leak_type)
+            ? IDS_CREDENTIAL_LEAK_TITLE_CHECK_BRANDED
+            : IDS_CREDENTIAL_LEAK_TITLE_CHANGE);
+  } else {
+    return l10n_util::GetStringUTF16(ShouldCheckPasswords(leak_type)
+                                         ? IDS_CREDENTIAL_LEAK_TITLE_CHECK
+                                         : IDS_CREDENTIAL_LEAK_TITLE_CHANGE);
+  }
 }
 
 std::u16string GetLeakDetectionTooltip() {
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc
index 581bd8d..8c56ef5 100644
--- a/components/password_manager/core/common/password_manager_features.cc
+++ b/components/password_manager/core/common/password_manager_features.cc
@@ -73,6 +73,12 @@
 const base::Feature kInferConfirmationPasswordField = {
     "InferConfirmationPasswordField", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Feature flag that updates icons, strings, and views for Google Password
+// Manager.
+const base::Feature kIOSEnablePasswordManagerBrandingUpdate{
+    "IOSEnablePasswordManagerBrandingUpdate",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables password leak detection for unauthenticated users.
 const base::Feature kLeakDetectionUnauthenticated = {
     "LeakDetectionUnauthenticated", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h
index aeefd0d..0aea65e 100644
--- a/components/password_manager/core/common/password_manager_features.h
+++ b/components/password_manager/core/common/password_manager_features.h
@@ -28,6 +28,7 @@
 extern const base::Feature kFillingAcrossAffiliatedWebsites;
 extern const base::Feature kFillOnAccountSelect;
 extern const base::Feature kInferConfirmationPasswordField;
+extern const base::Feature kIOSEnablePasswordManagerBrandingUpdate;
 extern const base::Feature kLeakDetectionUnauthenticated;
 extern const base::Feature kPasswordChange;
 extern const base::Feature kPasswordChangeOnlyRecentCredentials;
diff --git a/components/password_manager_strings.grdp b/components/password_manager_strings.grdp
index 858d460a..7cede914 100644
--- a/components/password_manager_strings.grdp
+++ b/components/password_manager_strings.grdp
@@ -25,6 +25,9 @@
   <message name="IDS_CREDENTIAL_LEAK_TITLE_CHECK" desc="The title of the credential leak dialog when the user should check all passwords on passwords.google.com.">
     Check your passwords
   </message>
+  <message name="IDS_CREDENTIAL_LEAK_TITLE_CHECK_BRANDED" desc="The title of the credential leak dialog when the user should check all passwords on Google Password Manager.">
+    Check your saved passwords
+  </message>
   <message name="IDS_CREDENTIAL_LEAK_CHECK_PASSWORDS_MESSAGE" desc="The text that is used in credential leak detection dialog when the leaked credentials are saved and used on multiple sites. The leaked credentials may have been leaked by the current website, some other third-party website or even a third-party app used by the user. It could also be coincidental reuse of a trivial password used by some other users in the world and exposed in a public leak.">
     Chrome found the password you just used in a data breach. To secure your accounts, we recommend checking your saved passwords.
   </message>
@@ -37,6 +40,15 @@
   <message name="IDS_CREDENTIAL_LEAK_CHANGE_AND_CHECK_PASSWORDS_MESSAGE" desc="The text that is used in credential leak detection dialog when the leaked credentials were not saved but used on multiple sites. The leaked credentials may have been leaked by the current website, some other third-party website or even a third-party app used by the user. It could also be coincidental reuse of a trivial password used by some other users in the world and exposed in a public leak.">
     Chrome found the password you just used in a data breach. To secure your accounts, we recommend changing it now and then checking your saved passwords.
   </message>
+  <message name="IDS_CREDENTIAL_LEAK_CHECK_PASSWORDS_MESSAGE_BRANDED" desc="The text that is used in credential leak detection dialog when the leaked credentials are saved and used on multiple sites. The leaked credentials may have been leaked by the current website, some other third-party website or even a third-party app used by the user. It could also be coincidental reuse of a trivial password used by some other users in the world and exposed in a public leak.">
+    The password you just used was found in a data breach. To secure your accounts, Google Password Manager recommends checking your saved passwords.
+  </message>
+  <message name="IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_BRANDED" desc="The text that is used in credential leak detection dialog when the leaked credentials are not saved for other sites. The leaked credentials may have been leaked by the current website, some other third-party website or even a third-party app used by the user. It could also be coincidental reuse of a trivial password used by some other users in the world and exposed in a public leak.">
+    The password you just used was found in a data breach. Google Password Manager recommends changing this password now.
+  </message>
+  <message name="IDS_CREDENTIAL_LEAK_CHANGE_AND_CHECK_PASSWORDS_MESSAGE_BRANDED" desc="The text that is used in credential leak detection dialog when the leaked credentials were not saved but used on multiple sites. The leaked credentials may have been leaked by the current website, some other third-party website or even a third-party app used by the user. It could also be coincidental reuse of a trivial password used by some other users in the world and exposed in a public leak.">
+    The password you just used was found in a data breach. To secure your accounts, Google Password Manager recommends changing it now and then checking your saved passwords.
+  </message>
   <if expr="is_ios">
     <message name="IDS_IOS_SUGGEST_PASSWORD" desc="Button title in the keyboard accessory bar to show a dialog with a generated password. [Length: 20em] [iOS only]">
       Suggest Password...
diff --git a/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_CHANGE_AND_CHECK_PASSWORDS_MESSAGE_BRANDED.png.sha1 b/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_CHANGE_AND_CHECK_PASSWORDS_MESSAGE_BRANDED.png.sha1
new file mode 100644
index 0000000..29cbf2e
--- /dev/null
+++ b/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_CHANGE_AND_CHECK_PASSWORDS_MESSAGE_BRANDED.png.sha1
@@ -0,0 +1 @@
+a432fe2830864638180f88f4027015d2595509dd
\ No newline at end of file
diff --git a/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_BRANDED.png.sha1 b/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_BRANDED.png.sha1
new file mode 100644
index 0000000..29cbf2e
--- /dev/null
+++ b/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_BRANDED.png.sha1
@@ -0,0 +1 @@
+a432fe2830864638180f88f4027015d2595509dd
\ No newline at end of file
diff --git a/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_CHECK_PASSWORDS_MESSAGE_BRANDED.png.sha1 b/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_CHECK_PASSWORDS_MESSAGE_BRANDED.png.sha1
new file mode 100644
index 0000000..29cbf2e
--- /dev/null
+++ b/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_CHECK_PASSWORDS_MESSAGE_BRANDED.png.sha1
@@ -0,0 +1 @@
+a432fe2830864638180f88f4027015d2595509dd
\ No newline at end of file
diff --git a/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_TITLE_CHECK_BRANDED.png.sha1 b/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_TITLE_CHECK_BRANDED.png.sha1
new file mode 100644
index 0000000..29cbf2e
--- /dev/null
+++ b/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_TITLE_CHECK_BRANDED.png.sha1
@@ -0,0 +1 @@
+a432fe2830864638180f88f4027015d2595509dd
\ No newline at end of file
diff --git a/components/safe_browsing/content/browser/safe_browsing_navigation_observer.cc b/components/safe_browsing/content/browser/safe_browsing_navigation_observer.cc
index f02890c..4c121991 100644
--- a/components/safe_browsing/content/browser/safe_browsing_navigation_observer.cc
+++ b/components/safe_browsing/content/browser/safe_browsing_navigation_observer.cc
@@ -12,6 +12,7 @@
 #include "components/sessions/content/session_tab_helper.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/global_routing_id.h"
+#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -257,8 +258,10 @@
   // When navigating a newly created portal contents, establish an association
   // with its creator, so we can track the referrer chain across portal
   // activations.
-  if (web_contents()->IsPortal() &&
-      !web_contents()->GetController().GetLastCommittedEntry()) {
+  if (web_contents()->IsPortal() && web_contents()
+                                        ->GetController()
+                                        .GetLastCommittedEntry()
+                                        ->IsInitialEntry()) {
     content::RenderFrameHost* initiator_frame_host =
         navigation_handle->GetInitiatorFrameToken().has_value()
             ? content::RenderFrameHost::FromFrameToken(
diff --git a/components/security_interstitials/content/security_interstitial_controller_client.cc b/components/security_interstitials/content/security_interstitial_controller_client.cc
index 0f1ec1a..fe2d5202 100644
--- a/components/security_interstitials/content/security_interstitial_controller_client.cc
+++ b/components/security_interstitials/content/security_interstitial_controller_client.cc
@@ -10,6 +10,7 @@
 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
 #include "components/security_interstitials/content/settings_page_helper.h"
 #include "components/security_interstitials/core/metrics_helper.h"
+#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/referrer.h"
 
@@ -114,8 +115,12 @@
 
 bool SecurityInterstitialControllerClient::CanGoBackBeforeNavigation() {
   // If checking before navigating to the interstitial, back to safety is
-  // possible if there is already at least one prior entry.
-  return web_contents_->GetController().GetEntryCount() > 0;
+  // possible if there is already at least one prior entry that is not the
+  // initial entry. This preserves old behavior to when we return nullptr
+  // instead of the initial entry when no navigation has committed.
+  return !web_contents_->GetController()
+              .GetLastCommittedEntry()
+              ->IsInitialEntry();
 }
 
 }  // namespace security_interstitials
diff --git a/components/security_state/content/content_utils.cc b/components/security_state/content/content_utils.cc
index 4f1ca2b..182d146 100644
--- a/components/security_state/content/content_utils.cc
+++ b/components/security_state/content/content_utils.cc
@@ -21,7 +21,7 @@
 
   content::NavigationEntry* entry =
       web_contents->GetController().GetVisibleEntry();
-  if (!entry)
+  if (entry->IsInitialEntry())
     return state;
   // Set fields that are not dependent on the connection info.
   state->is_error_page = entry->GetPageType() == content::PAGE_TYPE_ERROR;
diff --git a/components/sync/engine/commit_and_get_updates_types.h b/components/sync/engine/commit_and_get_updates_types.h
index 92a74c2..4925bd1 100644
--- a/components/sync/engine/commit_and_get_updates_types.h
+++ b/components/sync/engine/commit_and_get_updates_types.h
@@ -60,10 +60,6 @@
   ~CommitResponseData();
 
   std::string id;
-  // The sync id that was sent in the request. Non-empty only if different from
-  // |id|. It could be different because the server can change the sync id
-  // (e.g. for newly created bookmarks),
-  std::string id_in_request;
   ClientTagHash client_tag_hash;
   int64_t sequence_number = 0;
   int64_t response_version = 0;
diff --git a/components/sync/engine/commit_contribution_impl.cc b/components/sync/engine/commit_contribution_impl.cc
index 70db8ec..16c3670 100644
--- a/components/sync/engine/commit_contribution_impl.cc
+++ b/components/sync/engine/commit_contribution_impl.cc
@@ -29,12 +29,6 @@
     const sync_pb::CommitResponse_EntryResponse& entry_response) {
   CommitResponseData response_data;
   response_data.id = entry_response.id_string();
-  if (response_data.id != commit_request.entity->id) {
-    // Server has changed the sync id in the request. Write back the
-    // original sync id. This is useful for data types without a notion of
-    // a client tag such as bookmarks.
-    response_data.id_in_request = commit_request.entity->id;
-  }
   response_data.response_version = entry_response.version();
   response_data.client_tag_hash = commit_request.entity->client_tag_hash;
   response_data.sequence_number = commit_request.sequence_number;
diff --git a/components/sync_bookmarks/bookmark_model_type_processor.cc b/components/sync_bookmarks/bookmark_model_type_processor.cc
index ca84f746..f275043 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor.cc
@@ -152,19 +152,12 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // |error_response_list| is ignored, because all errors are treated as
-  // transientand the processor with eventually retry.
-
+  // transient and the processor with eventually retry.
   for (const syncer::CommitResponseData& response : committed_response_list) {
-    // In order to save space, |response.id_in_request| is written when it's
-    // different from |response.id|. If it's empty, then there was no id change
-    // during the commit, and |response.id| carries both the old and new ids.
-    const std::string& old_sync_id =
-        response.id_in_request.empty() ? response.id : response.id_in_request;
     const SyncedBookmarkTracker::Entity* entity =
-        bookmark_tracker_->GetEntityForSyncId(old_sync_id);
+        bookmark_tracker_->GetEntityForClientTagHash(response.client_tag_hash);
     if (!entity) {
-      DLOG(WARNING) << "Received a commit response for an unknown entity: "
-                    << old_sync_id;
+      DLOG(WARNING) << "Received a commit response for an unknown entity.";
       continue;
     }
 
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.cc b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
index 0d90faf..16ae4c6 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler.cc
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
@@ -296,9 +296,7 @@
     }
 
     if (tracked_entity && tracked_entity->IsUnsynced()) {
-      ProcessConflict(*update, tracked_entity);
-      // |tracked_entity| might be deleted during processing conflict.
-      tracked_entity = bookmark_tracker_->GetEntityForSyncId(update_entity.id);
+      tracked_entity = ProcessConflict(*update, tracked_entity);
       if (!tracked_entity) {
         // During conflict resolution, the entity could be dropped in case of
         // a conflict between local and remote deletions. We shouldn't worry
@@ -657,7 +655,8 @@
   bookmark_model_->Remove(node);
 }
 
-void BookmarkRemoteUpdatesHandler::ProcessConflict(
+const SyncedBookmarkTracker::Entity*
+BookmarkRemoteUpdatesHandler::ProcessConflict(
     const syncer::UpdateResponseData& update,
     const SyncedBookmarkTracker::Entity* tracked_entity) {
   const syncer::EntityData& update_entity = update.entity;
@@ -676,7 +675,7 @@
     // Both have been deleted, delete the corresponding entity from the tracker.
     bookmark_tracker_->Remove(tracked_entity);
     DLOG(WARNING) << "Conflict: CHANGES_MATCH";
-    return;
+    return nullptr;
   }
 
   if (update_entity.is_deleted()) {
@@ -685,16 +684,17 @@
     bookmark_tracker_->UpdateServerVersion(tracked_entity,
                                            update.response_version);
     DLOG(WARNING) << "Conflict: USE_LOCAL";
-    return;
+    return tracked_entity;
   }
 
+  DCHECK(IsValidBookmarkSpecifics(update_entity.specifics.bookmark()));
+
   if (tracked_entity->metadata()->is_deleted()) {
     // Only local node has been deleted. It should be restored from the server
     // data as a remote creation.
     bookmark_tracker_->Remove(tracked_entity);
-    ProcessCreate(update);
     DLOG(WARNING) << "Conflict: USE_REMOTE";
-    return;
+    return ProcessCreate(update);
   }
 
   // No deletions, there are potentially conflicting updates.
@@ -713,7 +713,7 @@
                 << update_entity.parent_id;
     LogProblematicBookmark(
         RemoteBookmarkUpdateError::kMissingParentEntityInConflict);
-    return;
+    return tracked_entity;
   }
   const bookmarks::BookmarkNode* new_parent =
       new_parent_entity->bookmark_node();
@@ -726,7 +726,7 @@
         << "Could not update node. Parent node has been deleted already.";
     LogProblematicBookmark(
         RemoteBookmarkUpdateError::kMissingParentNodeInConflict);
-    return;
+    return tracked_entity;
   }
   // Either local and remote data match or server wins, and in both cases we
   // should squash any pending commits.
@@ -752,6 +752,7 @@
                       bookmark_model_, bookmark_tracker_, favicon_service_);
   }
   ReuploadEntityIfNeeded(update_entity, tracked_entity);
+  return tracked_entity;
 }
 
 void BookmarkRemoteUpdatesHandler::RemoveEntityAndChildrenFromTracker(
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.h b/components/sync_bookmarks/bookmark_remote_updates_handler.h
index 277f38b..94b7d51 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler.h
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/memory/raw_ptr.h"
 #include "components/sync/engine/commit_and_get_updates_types.h"
 #include "components/sync_bookmarks/synced_bookmark_tracker.h"
@@ -109,9 +110,13 @@
   // of remote deletions in which local wins. |tracked_entity| is the tracked
   // entity for that server_id. It is passed as a dependency instead of
   // performing a lookup inside ProcessDelete() to avoid wasting CPU cycles for
-  // doing another lookup (this code runs on the UI thread).
-  void ProcessConflict(const syncer::UpdateResponseData& update,
-                       const SyncedBookmarkTracker::Entity* tracked_entity);
+  // doing another lookup (this code runs on the UI thread). Returns the tracked
+  // entity (if any) as a result of resolving the conflict, which is often the
+  // same as the input |tracked_entity|, but may also be different, including
+  // null (if the conflict led to untracking).
+  const SyncedBookmarkTracker::Entity* ProcessConflict(
+      const syncer::UpdateResponseData& update,
+      const SyncedBookmarkTracker::Entity* tracked_entity) WARN_UNUSED_RESULT;
 
   // Recursively removes the entities corresponding to |node| and its children
   // from |bookmark_tracker_|.
diff --git a/components/translate/content/browser/content_translate_driver.cc b/components/translate/content/browser/content_translate_driver.cc
index ffd09d8..77b86c3 100644
--- a/components/translate/content/browser/content_translate_driver.cc
+++ b/components/translate/content/browser/content_translate_driver.cc
@@ -106,8 +106,7 @@
 // TranslateDriver methods
 
 bool ContentTranslateDriver::IsLinkNavigation() {
-  return web_contents()->GetController().GetLastCommittedEntry() &&
-         ui::PageTransitionCoreTypeIs(web_contents()
+  return ui::PageTransitionCoreTypeIs(web_contents()
                                           ->GetController()
                                           .GetLastCommittedEntry()
                                           ->GetTransitionType(),
@@ -167,7 +166,13 @@
 }
 
 bool ContentTranslateDriver::HasCurrentPage() {
-  return (web_contents()->GetController().GetLastCommittedEntry() != nullptr);
+  // TODO(https://crbug.com/524208): This function used to check the existence
+  // of GetLastCommittedEntry(), which will always exist now. Should its callers
+  // just assume HasCurrentPage() is true, and can we remove this function then?
+  return !web_contents()
+              ->GetController()
+              .GetLastCommittedEntry()
+              ->IsInitialEntry();
 }
 
 void ContentTranslateDriver::OpenUrlInNewTab(const GURL& url) {
@@ -334,8 +339,7 @@
     // associated, thus avoiding the potential for corner cases where the
     // detected language is attributed to the wrong page.
     auto* const entry = web_contents()->GetController().GetLastCommittedEntry();
-    if (entry != nullptr)
-      SetPageLanguageInNavigation(details.adopted_language, entry);
+    SetPageLanguageInNavigation(details.adopted_language, entry);
   }
 
   for (auto& observer : language_detection_observers())
diff --git a/content/BUILD.gn b/content/BUILD.gn
index 30f7f35..a0c915b 100644
--- a/content/BUILD.gn
+++ b/content/BUILD.gn
@@ -59,21 +59,18 @@
 # //content/browser target only in non-component builds (when there are no
 # linking problems) for when check is enabled.
 
-if (!is_nacl_nonsfi) {
-  content_shared_components = [
-    "//content/gpu:gpu_sources",
-    "//content/public/browser:browser_sources",
-    "//content/public/child:child_sources",
-    "//content/public/common:common_sources",
-    "//content/public/gpu:gpu_sources",
-    "//content/public/renderer:renderer_sources",
-    "//content/public/utility:utility_sources",
-  ]
+content_shared_components = [
+  "//content/gpu:gpu_sources",
+  "//content/public/browser:browser_sources",
+  "//content/public/child:child_sources",
+  "//content/public/common:common_sources",
+  "//content/public/gpu:gpu_sources",
+  "//content/public/renderer:renderer_sources",
+  "//content/public/utility:utility_sources",
+]
 
-  if (enable_plugins) {
-    content_shared_components +=
-        [ "//content/ppapi_plugin:ppapi_plugin_sources" ]
-  }
+if (enable_plugins) {
+  content_shared_components += [ "//content/ppapi_plugin:ppapi_plugin_sources" ]
 }
 
 if (is_component_build) {
@@ -81,27 +78,6 @@
     public_deps =
         content_shared_components + [ "//content/public/app:app_sources" ]
   }
-} else if (is_nacl_nonsfi) {
-  source_set("content") {
-    sources = [
-      "//sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc",
-      "common/sandbox_init_linux.cc",
-      "common/zygote/send_zygote_child_ping_linux.cc",
-      "public/common/content_switches.cc",
-      "public/common/content_switches.h",
-    ]
-    deps = [
-      "//base",
-      "//build:chromeos_buildflags",
-      "//media:media_buildflags",
-      "//ppapi/buildflags:buildflags",
-      "//printing/buildflags",
-      "//sandbox:sandbox_buildflags",
-      "//sandbox/linux:sandbox",
-      "//sandbox/policy",
-      "//sandbox/policy/mojom",
-    ]
-  }
 } else {
   group("content") {
     public_deps = content_shared_components
diff --git a/content/browser/back_forward_cache_basics_browsertest.cc b/content/browser/back_forward_cache_basics_browsertest.cc
index 431b0570..ce0b067 100644
--- a/content/browser/back_forward_cache_basics_browsertest.cc
+++ b/content/browser/back_forward_cache_basics_browsertest.cc
@@ -17,7 +17,9 @@
 
 // This file contains back/forward-cache tests that test basic functionality,
 // e.g. navigation, different responses and document structures.
-// Almost everything in here could have been written as a JS-only WPT.
+// Almost everything in here could have been written as a JS-only WPT. It was
+// forked from
+// https://source.chromium.org/chromium/chromium/src/+/main:content/browser/back_forward_cache_browsertest.cc;drc=804bb57be3441b6291c11e34d8f901e2b1c0b430
 //
 // When adding tests here consider adding a WPT intead. See
 // third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/README.md
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index ea5dae4e..f92f8843 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -2761,6 +2761,38 @@
     EXPECT_FALSE(fenced_frame_host->IsInBackForwardCache());
 }
 
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       RendererInitiatedNavigateToSameUrl) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // 1) Navigate to A.
+  ASSERT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+
+  // 2) Navigate to B.
+  ASSERT_TRUE(NavigateToURL(shell(), url_b));
+  RenderFrameHostImplWrapper rfh_b(current_frame_host());
+
+  // 3) Navigate to B again, renderer initiated.
+  ASSERT_TRUE(NavigateToURLFromRenderer(rfh_b.get(), url_b));
+  // This is treated as replacement, and RenderFrameHost does not change.
+  EXPECT_EQ(rfh_b.get(), current_frame_host());
+
+  // 4) Go back. Make sure we go back to A instead of B and restore from
+  // bfcache.
+  ASSERT_TRUE(HistoryGoBack(shell()->web_contents()));
+  EXPECT_EQ(current_frame_host(), rfh_a.get());
+  EXPECT_TRUE(rfh_b.get()->IsInBackForwardCache());
+  ExpectRestored(FROM_HERE);
+
+  // 5) Go forward and restore from bfcache.
+  ASSERT_TRUE(HistoryGoForward(shell()->web_contents()));
+  EXPECT_EQ(current_frame_host(), rfh_b.get());
+  ExpectRestored(FROM_HERE);
+}
+
 // BEFORE ADDING A NEW TEST HERE
 // Read the note at the top about the other files you could add it to.
 }  // namespace content
diff --git a/content/browser/back_forward_cache_features_browsertest.cc b/content/browser/back_forward_cache_features_browsertest.cc
index bf4a0745..af9bd3b 100644
--- a/content/browser/back_forward_cache_features_browsertest.cc
+++ b/content/browser/back_forward_cache_features_browsertest.cc
@@ -1601,6 +1601,116 @@
 }
 
 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       DoesNotCacheIfOpenIndexedDBConnection) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to A and use IndexedDB.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(
+                   "a.com", "/back_forward_cache/page_with_indexedDB.html")));
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+  EXPECT_TRUE(ExecJs(rfh_a.get(), "setupIndexedDBConnection()"));
+  RenderFrameDeletedObserver deleted(rfh_a.get());
+
+  // 2) Navigate away.
+  shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
+  // The page has an open IndexedDB connection so it should be deleted.
+  deleted.WaitUntilDeleted();
+
+  // 3) Go back to the page with IndexedDB.
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  ExpectNotRestored(
+      {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
+      {blink::scheduler::WebSchedulerTrackedFeature::kIndexedDBConnection}, {},
+      {}, {}, FROM_HERE);
+}
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       CacheIfIndexedDBConnectionClosedInPagehide) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to A and use IndexedDB, and close the connection on pagehide.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(
+                   "a.com", "/back_forward_cache/page_with_indexedDB.html")));
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+  EXPECT_TRUE(ExecJs(rfh_a.get(), "setupIndexedDBConnection()"));
+  // This registers a pagehide handler to close the IDB connection. This should
+  // remove the bfcache blocking.
+  EXPECT_TRUE(
+      ExecJs(rfh_a.get(), "registerPagehideToCloseIndexedDBConnection()"));
+
+  // 2) Navigate away.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+
+  // 3) Go back to the page with IndexedDB. The connection is closed so it
+  // should be restored from bfcache.
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  ExpectRestored(FROM_HERE);
+}
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       DoNotCacheIfIndexedDBTransactionNotCommitted) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to A and use IndexedDB.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(
+                   "a.com", "/back_forward_cache/page_with_indexedDB.html")));
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+  EXPECT_TRUE(ExecJs(rfh_a.get(), "setupIndexedDBConnection()"));
+  // This registers a pagehide handler to start a new transaction. This will
+  // block bfcache because there is an inflight transaction.
+  EXPECT_TRUE(ExecJs(rfh_a.get(), "registerPagehideToStartTransaction()"));
+
+  // 2) Navigate away.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
+
+  // 3) Go back to the page with IndexedDB.
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  ExpectNotRestored(
+      {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
+      {blink::scheduler::WebSchedulerTrackedFeature::
+           kOutstandingIndexedDBTransaction},
+      {}, {}, {}, FROM_HERE);
+}
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       CacheIfIndexedDBConnectionTransactionCommit) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to A and use IndexedDB.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(
+                   "a.com", "/back_forward_cache/page_with_indexedDB.html")));
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+  EXPECT_TRUE(ExecJs(rfh_a.get(), "setupIndexedDBConnection()"));
+  // This registers a pagehide handler to start and commit the IDB transactions.
+  // Since the transactions are ended inside the handler, the page is no longer
+  // blocked for inflight IDB transactions.
+  EXPECT_TRUE(
+      ExecJs(rfh_a.get(), "registerPagehideToStartAndCommitTransaction()"));
+
+  // 2) Navigate away.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+
+  // 3) Go back to the page with IndexedDB.
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  ExpectRestored(FROM_HERE);
+}
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
                        DoesNotCacheIfBroadcastChannelStillOpen) {
   ASSERT_TRUE(CreateHttpsServer()->Start());
 
diff --git a/content/browser/back_forward_cache_internal_browsertest.cc b/content/browser/back_forward_cache_internal_browsertest.cc
index 8f87a96..d7364f3 100644
--- a/content/browser/back_forward_cache_internal_browsertest.cc
+++ b/content/browser/back_forward_cache_internal_browsertest.cc
@@ -9,12 +9,15 @@
 #include "base/test/bind.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "build/build_config.h"
+#include "content/browser/renderer_host/back_forward_cache_disable.h"
 #include "content/browser/renderer_host/navigation_request.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/content_navigation_policy.h"
+#include "content/public/browser/browser_accessibility_state.h"
 #include "content/public/browser/disallow_activation_reason.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/test/back_forward_cache_util.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test_utils.h"
@@ -30,7 +33,8 @@
 // This file contains back/forward-cache tests that test or use internal
 // features, e.g. cache-flushing, crashes, verifying proxies and other
 // navigation internals. If you could write the test in JS or using only public
-// functions it probably doesn't belong in this file.
+// functions it probably doesn't belong in this file. It was forked from
+// https://source.chromium.org/chromium/chromium/src/+/main:content/browser/back_forward_cache_browsertest.cc;drc=db47c3a2e741f8ea55024e64ec932044024cbddc
 //
 // When adding tests consider also adding WPTs, although for internal tests,
 // this is often not an option. See
@@ -38,9 +42,9 @@
 
 using testing::_;
 using testing::Each;
-using testing::ElementsAre;
-using testing::Not;
-using testing::UnorderedElementsAreArray;
+using ::testing::ElementsAre;
+using ::testing::Not;
+using ::testing::UnorderedElementsAreArray;
 
 namespace content {
 
@@ -107,9 +111,9 @@
   // Ensure the visited frames are what we would expect for the page before
   // entering bfcache.
   EXPECT_THAT(CollectAllRenderFrameHosts(rfh_a),
-              testing::ElementsAre(rfh_a, rfh_b, rfh_d, rfh_c));
+              ::testing::ElementsAre(rfh_a, rfh_b, rfh_d, rfh_c));
   EXPECT_THAT(CollectAllRenderFrameHosts(web_contents()),
-              testing::ElementsAre(rfh_a, rfh_b, rfh_d, rfh_c));
+              ::testing::ElementsAre(rfh_a, rfh_b, rfh_d, rfh_c));
 
   // 2) Navigate to e.
   EXPECT_TRUE(NavigateToURL(shell(), url_e));
@@ -123,22 +127,23 @@
 
   // When starting iteration from the primary frame, we shouldn't see any of the
   // frames in bfcache.
-  EXPECT_THAT(CollectAllRenderFrameHosts(rfh_e), testing::ElementsAre(rfh_e));
+  EXPECT_THAT(CollectAllRenderFrameHosts(rfh_e), ::testing::ElementsAre(rfh_e));
 
   // When starting iteration from a bfcached RFH, we should see the frame itself
   // and its descendants in breadth first order.
   EXPECT_THAT(CollectAllRenderFrameHosts(rfh_a),
-              testing::ElementsAre(rfh_a, rfh_b, rfh_d, rfh_c));
+              ::testing::ElementsAre(rfh_a, rfh_b, rfh_d, rfh_c));
 
   // Ensure that starting iteration from a subframe of a bfcached frame also
   // works.
   EXPECT_THAT(CollectAllRenderFrameHosts(rfh_b),
-              testing::ElementsAre(rfh_b, rfh_c));
+              ::testing::ElementsAre(rfh_b, rfh_c));
 
   // When iterating over all RenderFrameHosts in a WebContents, we should see
   // the RFHs of both the primary page and the bfcached page.
-  EXPECT_THAT(CollectAllRenderFrameHosts(web_contents()),
-              testing::UnorderedElementsAre(rfh_a, rfh_b, rfh_c, rfh_d, rfh_e));
+  EXPECT_THAT(
+      CollectAllRenderFrameHosts(web_contents()),
+      ::testing::UnorderedElementsAre(rfh_a, rfh_b, rfh_c, rfh_d, rfh_e));
 
   {
     // If we stop iteration in |WebContents::ForEachRenderFrameHost|, we stop
@@ -226,22 +231,22 @@
   // When starting iteration from the bfcached RFH, we should not see the
   // speculative RFH.
   EXPECT_THAT(CollectAllRenderFrameHostsIncludingSpeculative(rfh_a),
-              testing::ElementsAre(rfh_a));
+              ::testing::ElementsAre(rfh_a));
 
   // When starting iteration from the primary frame, we shouldn't see the
   // bfcached RFH, but we should see the speculative RFH.
   EXPECT_THAT(CollectAllRenderFrameHostsIncludingSpeculative(rfh_b),
-              testing::UnorderedElementsAre(rfh_b, rfh_c));
+              ::testing::UnorderedElementsAre(rfh_b, rfh_c));
 
   // When starting iteration from the speculative RFH, we should only see
   // the speculative RFH. In particular, we should not see the bfcached RFH.
   EXPECT_THAT(CollectAllRenderFrameHostsIncludingSpeculative(rfh_c),
-              testing::ElementsAre(rfh_c));
+              ::testing::ElementsAre(rfh_c));
 
   // When iterating over all RenderFrameHosts in a WebContents, we should see
   // the RFHs of both the primary page and the bfcached page.
   EXPECT_THAT(CollectAllRenderFrameHostsIncludingSpeculative(web_contents()),
-              testing::UnorderedElementsAre(rfh_a, rfh_b, rfh_c));
+              ::testing::UnorderedElementsAre(rfh_a, rfh_b, rfh_c));
 }
 
 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
@@ -2273,7 +2278,7 @@
   // 2) Navigate to B, now A enters BackForwardCache. Check the
   // LifecycleStateImpl of both RenderFrameHost A and B.
   {
-    testing::NiceMock<MockWebContentsObserver> state_change_observer(
+    ::testing::NiceMock<MockWebContentsObserver> state_change_observer(
         web_contents());
     EXPECT_CALL(state_change_observer,
                 RenderFrameHostStateChanged(
@@ -2282,7 +2287,7 @@
     // We don't know |rfh_b| yet, so we'll match any frame.
     EXPECT_CALL(state_change_observer,
                 RenderFrameHostStateChanged(
-                    testing::Not(rfh_a),
+                    ::testing::Not(rfh_a),
                     RenderFrameHost::LifecycleState::kPendingCommit,
                     RenderFrameHost::LifecycleState::kActive));
 
@@ -2306,7 +2311,7 @@
   // 3) Go back to A and check again the LifecycleStateImpl of both
   // RenderFrameHost A and B.
   {
-    testing::NiceMock<MockWebContentsObserver> state_change_observer(
+    ::testing::NiceMock<MockWebContentsObserver> state_change_observer(
         web_contents());
     EXPECT_CALL(state_change_observer,
                 RenderFrameHostStateChanged(
@@ -2356,7 +2361,7 @@
 
   // Navigate to C(D), now A(B) enters BackForwardCache.
   {
-    testing::NiceMock<MockWebContentsObserver> state_change_observer(
+    ::testing::NiceMock<MockWebContentsObserver> state_change_observer(
         web_contents());
     EXPECT_CALL(state_change_observer,
                 RenderFrameHostStateChanged(
@@ -2369,14 +2374,14 @@
     // We don't know |rfh_c| and |rfh_d| yet, so we'll match any frame.
     EXPECT_CALL(state_change_observer,
                 RenderFrameHostStateChanged(
-                    testing::Not(testing::AnyOf(rfh_a, rfh_b)),
+                    ::testing::Not(::testing::AnyOf(rfh_a, rfh_b)),
                     RenderFrameHost::LifecycleState::kPendingCommit,
                     RenderFrameHost::LifecycleState::kActive))
         .Times(2);
     // Deletion of frame D's initial RFH.
     EXPECT_CALL(state_change_observer,
                 RenderFrameHostStateChanged(
-                    testing::Not(testing::AnyOf(rfh_a, rfh_b)),
+                    ::testing::Not(::testing::AnyOf(rfh_a, rfh_b)),
                     RenderFrameHost::LifecycleState::kActive,
                     RenderFrameHost::LifecycleState::kPendingDeletion));
 
@@ -2407,7 +2412,7 @@
 
   // Go back to A(B), A(B) is restored and C(D) enters BackForwardCache.
   {
-    testing::NiceMock<MockWebContentsObserver> state_change_observer(
+    ::testing::NiceMock<MockWebContentsObserver> state_change_observer(
         web_contents());
     EXPECT_CALL(state_change_observer,
                 RenderFrameHostStateChanged(
@@ -3284,9 +3289,9 @@
   shell->web_contents()->GetController().GoBack();
   nav_manager.WaitForFirstYieldAfterDidStartNavigation();
 
-  testing::NiceMock<MockWebContentsObserver> observer(shell->web_contents());
+  ::testing::NiceMock<MockWebContentsObserver> observer(shell->web_contents());
   EXPECT_CALL(observer, DidFinishNavigation(_))
-      .WillOnce(testing::Invoke([](NavigationHandle* handle) {
+      .WillOnce(::testing::Invoke([](NavigationHandle* handle) {
         EXPECT_FALSE(handle->HasCommitted());
         EXPECT_TRUE(handle->IsServedFromBackForwardCache());
         // This call checks that |rfh_restored_from_back_forward_cache| is not
@@ -3692,4 +3697,37 @@
   ExpectCached(rfhs[3], /*cached=*/true, /*backgrounded=*/false);
 }
 
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
+                       DisableBackForwardCacheForScreenReader) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+  BackForwardCacheDisabledTester tester;
+
+  // Use Screen Reader.
+  content::testing::ScopedContentAXModeSetter ax_mode_setter(
+      ui::AXMode::kScreenReader);
+
+  // Navigate to Page A.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostWrapper rfh_a(current_frame_host());
+  RenderFrameDeletedObserver deleted(rfh_a.get());
+  int process_id = current_frame_host()->GetProcess()->GetID();
+  int routing_id = current_frame_host()->GetRoutingID();
+
+  // Navigate away to Page B.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  deleted.WaitUntilDeleted();
+
+  // Navigate back.
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  auto reason = BackForwardCacheDisable::DisabledReason(
+      BackForwardCacheDisable::DisabledReasonId::kScreenReader);
+  ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
+                         kDisableForRenderFrameHostCalled},
+                    {}, {}, {reason}, {}, FROM_HERE);
+  EXPECT_TRUE(
+      tester.IsDisabledForFrameWithReason(process_id, routing_id, reason));
+}
+
 }  // namespace content
diff --git a/content/browser/child_process_launcher_browsertest.cc b/content/browser/child_process_launcher_browsertest.cc
index 91cfb6f0..f4ed49a5 100644
--- a/content/browser/child_process_launcher_browsertest.cc
+++ b/content/browser/child_process_launcher_browsertest.cc
@@ -71,8 +71,8 @@
   delete client;
   NavigationEntry* last_entry =
       shell()->web_contents()->GetController().GetLastCommittedEntry();
-  // Make sure we didn't navigate.
-  EXPECT_FALSE(last_entry);
+  // Make sure we didn't commit any navigation.
+  EXPECT_TRUE(last_entry->IsInitialEntry());
 
   // Navigate again and let the process spawn correctly.
   TestNavigationObserver nav_observer2(window->web_contents(), 1);
@@ -80,7 +80,7 @@
   nav_observer2.Wait();
   last_entry = shell()->web_contents()->GetController().GetLastCommittedEntry();
   // Make sure that we navigated to the proper URL.
-  ASSERT_TRUE(last_entry);
+  ASSERT_FALSE(last_entry->IsInitialEntry());
   EXPECT_EQ(last_entry->GetPageType(), PAGE_TYPE_NORMAL);
   EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), url);
 
@@ -91,7 +91,7 @@
   nav_observer3.Wait();
   last_entry = shell()->web_contents()->GetController().GetLastCommittedEntry();
   // Make sure that we navigated to the proper URL.
-  ASSERT_TRUE(last_entry);
+  ASSERT_FALSE(last_entry->IsInitialEntry());
   EXPECT_EQ(last_entry->GetPageType(), PAGE_TYPE_NORMAL);
   EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), url);
 }
diff --git a/content/browser/client_hints/client_hints.cc b/content/browser/client_hints/client_hints.cc
index b2d5a30c..cd90c0a 100644
--- a/content/browser/client_hints/client_hints.cc
+++ b/content/browser/client_hints/client_hints.cc
@@ -450,10 +450,6 @@
       .value_or(std::string());
 }
 
-bool IsPermissionsPolicyForClientHintsEnabled() {
-  return base::FeatureList::IsEnabled(features::kFeaturePolicyForClientHints);
-}
-
 bool IsSameOrigin(const GURL& url1, const GURL& url2) {
   return url::Origin::Create(url1).IsSameOriginWith(url::Origin::Create(url2));
 }
@@ -586,7 +582,7 @@
 
 bool IsClientHintAllowed(const ClientHintsExtendedData& data,
                          WebClientHintsType type) {
-  if (!IsPermissionsPolicyForClientHintsEnabled() || data.is_main_frame)
+  if (data.is_main_frame)
     return data.is_1p_origin;
   return (data.is_embedder_ua_reduced &&
           type == WebClientHintsType::kUAReduced) ||
@@ -967,24 +963,8 @@
                      const std::vector<WebClientHintsType>& hints,
                      base::TimeDelta* persist_duration) {
   DCHECK(delegate);
-
-  // TODO(https://crbug.com/1243060): Remove the checking and persistence of the
-  // expiration time.
-  const bool use_persist_duration =
-      persist_duration && !IsPermissionsPolicyForClientHintsEnabled();
-
-  if (use_persist_duration && persist_duration->is_zero())
-    return;
-
-  // JSON cannot store "non-finite" values (i.e. NaN or infinite) so
-  // base::TimeDelta::Max cannot be used. As this will be removed once the
-  // FeaturePolicyForClientHints feature is shipped, a reasonably large value
-  // was chosen instead.
-  base::TimeDelta duration =
-      use_persist_duration ? *persist_duration : base::Days(1000000);
-
   delegate->PersistClientHints(url::Origin::Create(url), hints,
-                               std::move(duration));
+                               base::Days(1000000));
 }
 
 std::vector<WebClientHintsType> LookupAcceptCHForCommit(
diff --git a/content/browser/client_hints/client_hints.h b/content/browser/client_hints/client_hints.h
index 78583c53..4760122 100644
--- a/content/browser/client_hints/client_hints.h
+++ b/content/browser/client_hints/client_hints.h
@@ -110,8 +110,7 @@
 // `persist_duration` can be nullptr, in which case, a long-enough expiration
 // time is chosen such that the hints won't expire.
 //
-// TODO(crbug.com/1243060): Remove `persist_duration` as an argument when
-// FeaturePolicyForClientHints is removed.
+// TODO(crbug.com/1243060): Remove `persist_duration`.
 CONTENT_EXPORT void PersistAcceptCH(
     const GURL& url,
     ClientHintsControllerDelegate* delegate,
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index 6acb486..e8420df 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -1576,6 +1576,9 @@
         case BackForwardCacheDisable::DisabledReasonId::kMediaSessionService:
           return Page::BackForwardCacheNotRestoredReasonEnum::
               ContentMediaSessionService;
+        case BackForwardCacheDisable::DisabledReasonId::kScreenReader:
+          return Page::BackForwardCacheNotRestoredReasonEnum::
+              ContentScreenReader;
       }
     case BackForwardCache::DisabledSource::kEmbedder:
       switch (static_cast<back_forward_cache::DisabledReasonId>(reason.id)) {
diff --git a/content/browser/fenced_frame/fenced_frame.cc b/content/browser/fenced_frame/fenced_frame.cc
index eca354e..0b54136a 100644
--- a/content/browser/fenced_frame/fenced_frame.cc
+++ b/content/browser/fenced_frame/fenced_frame.cc
@@ -42,7 +42,7 @@
   // apply for fenced frames, portals, and prerendered nested FrameTrees, hence
   // the decision to mark it as false.
   frame_tree_->Init(site_instance.get(), /*renderer_initiated_creation=*/false,
-                    /*main_frame_name=*/"");
+                    /*main_frame_name=*/"", /*opener=*/nullptr);
 
   // TODO(crbug.com/1199679): This should be moved to FrameTree::Init.
   web_contents_->NotifySwappedFromRenderManager(
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc
index 630d5fd7..97c9676 100644
--- a/content/browser/isolated_origin_browsertest.cc
+++ b/content/browser/isolated_origin_browsertest.cc
@@ -1979,11 +1979,14 @@
                   .requires_origin_keyed_process());
 }
 
-// This test creates a scenario where we have a frame without a
-// FrameNavigationEntry, and then we created another frame with the same origin
+// This test creates a scenario where we have a frame that is on the initial
+// NavigationEntry, and then we created another frame with the same origin
 // that opts-in to isolation. The opt-in triggers a walk of the session history
 // and the frame tree ... the session history won't pick up the first frame, but
 // the frame-tree walk should.
+// TODO(https://crbug.com/608402): Once every created frame is guaranteed to
+// have a FrameNavigationEntry and thus represented in the sesion history, we
+// probably can remove the frame-tree walk.
 IN_PROC_BROWSER_TEST_F(OriginIsolationOptInHeaderTest, FrameTreeTest) {
   EXPECT_TRUE(NavigateToURL(shell(),
                             https_server()->GetURL("bar.com", "/title1.html")));
@@ -2006,7 +2009,8 @@
   FrameTreeNode* tab2_child = tab2_root->child_at(0);
   GURL isolated_origin_url(
       https_server()->GetURL("isolated.foo.com", "/isolate_origin"));
-  // The subframe won't be isolated.
+  // Navigate the iframe in tab2 to `isolated_origin_url` without requesting
+  // isolation, so it won't be isolated.
   EXPECT_TRUE(NavigateFrameToURL(tab2_child, isolated_origin_url));
 
   // Do a browser-initiated navigation of tab1 to the same origin, but isolate
@@ -2048,12 +2052,11 @@
                           ->GetIsolationContext(),
                       isolated_origin, MakeOACIsolationState(false))
                   .requires_origin_keyed_process());
-  // Verify that the tab2 child frame has no FrameNavigationEntry.
-  // TODO(wjmaclean): when https://crbug.com/524208 is fixed, this next check
-  // will fail, and it should be removed with the CL that fixes 524208.
-  EXPECT_EQ(
-      nullptr,
-      tab2_shell->web_contents()->GetController().GetLastCommittedEntry());
+  // Verify that the tab2 child frame is on the initial NavigationEntry.
+  EXPECT_TRUE(tab2_shell->web_contents()
+                  ->GetController()
+                  .GetLastCommittedEntry()
+                  ->IsInitialEntry());
 
   // Now, create a second frame in tab2 and navigate it to
   // `isolated_origin_url`. Even though isolation is requested, it should not
diff --git a/content/browser/loader/url_loader_throttles.cc b/content/browser/loader/url_loader_throttles.cc
index 406c26c..2590a439 100644
--- a/content/browser/loader/url_loader_throttles.cc
+++ b/content/browser/loader/url_loader_throttles.cc
@@ -47,8 +47,7 @@
 
   ClientHintsControllerDelegate* client_hint_delegate =
       browser_context->GetClientHintsControllerDelegate();
-  if (base::FeatureList::IsEnabled(features::kFeaturePolicyForClientHints) &&
-      (base::FeatureList::IsEnabled(features::kCriticalClientHint) ||
+  if ((base::FeatureList::IsEnabled(features::kCriticalClientHint) ||
        base::FeatureList::IsEnabled(network::features::kAcceptCHFrame)) &&
       request.is_main_frame && net::HttpUtil::IsMethodSafe(request.method) &&
       client_hint_delegate &&
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 3dfba71..cba319b 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -5232,27 +5232,25 @@
 }
 
 // The test below verifies that an initial empty document has a functional
-// URLLoaderFactory.  Note that the same behavior is expected in the
-// ...NewPopupToEmptyUrl and in the ...NewPopupToAboutBlank testcases - the
-// differences in test expectations (around `GetController().GetEntryCount()`)
-// are unexpected and would need to be fixed as part of https://crbug.com/524208
-// (or maybe more broadly https://crbug.com/778318 and/or
-// https://github.com/whatwg/html/issues/3267).
+// URLLoaderFactory.
 IN_PROC_BROWSER_TEST_F(SubresourceLoadingTest,
                        URLLoaderFactoryInInitialEmptyDoc_NewPopupToEmptyUrl) {
   GURL opener_url(embedded_test_server()->GetURL("/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), opener_url));
 
-  content::WebContents* popup = nullptr;
+  WebContentsImpl* popup = nullptr;
   {
     WebContentsAddedObserver popup_observer;
     ASSERT_TRUE(ExecJs(shell(), "window.open('', '_blank')"));
-    popup = popup_observer.GetWebContents();
+    popup = static_cast<WebContentsImpl*>(popup_observer.GetWebContents());
   }
   WaitForLoadStop(popup);
 
   // Verify that we are at the initial empty document.
-  EXPECT_EQ(0, popup->GetController().GetEntryCount());
+  EXPECT_EQ(1, popup->GetController().GetEntryCount());
+  EXPECT_TRUE(popup->GetController().GetLastCommittedEntry()->IsInitialEntry());
+  EXPECT_TRUE(
+      popup->GetPrimaryFrameTree().root()->is_on_initial_empty_document());
 
   // Verify that the `popup` is at "about:blank", with expected origin, with
   // working `document.cookie`, and with working subresource loads.
@@ -5267,16 +5265,20 @@
   GURL opener_url(embedded_test_server()->GetURL("/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), opener_url));
 
-  content::WebContents* popup = nullptr;
+  WebContentsImpl* popup = nullptr;
   {
     WebContentsAddedObserver popup_observer;
     ASSERT_TRUE(ExecJs(shell(), "window.open('about:blank', '_blank')"));
-    popup = popup_observer.GetWebContents();
+    popup = static_cast<WebContentsImpl*>(popup_observer.GetWebContents());
   }
   WaitForLoadStop(popup);
 
-  // Verify that we are not at the initial empty document anymore.
+  // Verify that we are at the synchronously committed about:blank document.
   EXPECT_EQ(1, popup->GetController().GetEntryCount());
+  EXPECT_FALSE(
+      popup->GetController().GetLastCommittedEntry()->IsInitialEntry());
+  EXPECT_TRUE(
+      popup->GetPrimaryFrameTree().root()->is_on_initial_empty_document());
 
   // Verify other about:blank things.
   VerifyResultsOfAboutBlankNavigation(popup->GetMainFrame(),
@@ -5504,7 +5506,11 @@
 
   // Double-check that the new shell didn't commit any navigation and that it
   // has an opaque origin.
-  ASSERT_EQ(0, new_shell->web_contents()->GetController().GetEntryCount());
+  ASSERT_EQ(1, new_shell->web_contents()->GetController().GetEntryCount());
+  EXPECT_TRUE(new_shell->web_contents()
+                  ->GetController()
+                  .GetLastCommittedEntry()
+                  ->IsInitialEntry());
   EXPECT_EQ(GURL(), main_frame->GetLastCommittedURL());
   EXPECT_EQ("null", EvalJs(main_frame, "window.origin"));
 
diff --git a/content/browser/portal/portal.cc b/content/browser/portal/portal.cc
index 6d9e8f5..70433f3 100644
--- a/content/browser/portal/portal.cc
+++ b/content/browser/portal/portal.cc
@@ -496,7 +496,7 @@
 
   // If no navigation has yet committed in the portal, it cannot be activated as
   // this would lead to an empty tab contents (without even an about:blank).
-  if (portal_controller.GetLastCommittedEntryIndex() < 0) {
+  if (portal_controller.GetLastCommittedEntry()->IsInitialEntry()) {
     return std::make_pair(
         false,
         blink::mojom::PortalActivateResult::kRejectedDueToPortalNotReady);
diff --git a/content/browser/prerender/prerender_browsertest.cc b/content/browser/prerender/prerender_browsertest.cc
index 7f645da..98ca950 100644
--- a/content/browser/prerender/prerender_browsertest.cc
+++ b/content/browser/prerender/prerender_browsertest.cc
@@ -4456,8 +4456,9 @@
       PrerenderHost::FinalStatus::kCrossOriginNavigation, 1);
 }
 
-IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
-                       CancelEmbedderTriggerPrerenderingSameOriginRedirection) {
+IN_PROC_BROWSER_TEST_F(
+    PrerenderBrowserTest,
+    CancelEmbedderTriggeredPrerenderingSameOriginRedirection) {
   base::HistogramTester histogram_tester;
   const GURL kRedirectedUrl = GetUrl("/empty.html?prerender");
   const GURL kPrerenderingUrl =
@@ -4477,7 +4478,7 @@
 
   histogram_tester.ExpectUniqueSample(
       "Prerender.Experimental.PrerenderHostFinalStatus",
-      PrerenderHost::FinalStatus::kEmbedderTriggeredAndRedirected, 1);
+      PrerenderHost::FinalStatus::kEmbedderTriggeredAndSameOriginRedirected, 1);
 }
 
 IN_PROC_BROWSER_TEST_F(
@@ -4502,7 +4503,8 @@
 
   histogram_tester.ExpectUniqueSample(
       "Prerender.Experimental.PrerenderHostFinalStatus",
-      PrerenderHost::FinalStatus::kEmbedderTriggeredAndRedirected, 1);
+      PrerenderHost::FinalStatus::kEmbedderTriggeredAndCrossOriginRedirected,
+      1);
 }
 
 namespace {
diff --git a/content/browser/prerender/prerender_host.cc b/content/browser/prerender/prerender_host.cc
index fca6e971..afb35d8 100644
--- a/content/browser/prerender/prerender_host.cc
+++ b/content/browser/prerender/prerender_host.cc
@@ -89,7 +89,7 @@
         SiteInstance::Create(web_contents.GetBrowserContext());
     frame_tree_->Init(site_instance.get(),
                       /*renderer_initiated_creation=*/false,
-                      /*main_frame_name=*/"");
+                      /*main_frame_name=*/"", /*opener=*/nullptr);
 
     const auto& site_info =
         static_cast<SiteInstanceImpl*>(site_instance.get())->GetSiteInfo();
diff --git a/content/browser/prerender/prerender_host.h b/content/browser/prerender/prerender_host.h
index 25bae686..18c8463 100644
--- a/content/browser/prerender/prerender_host.h
+++ b/content/browser/prerender/prerender_host.h
@@ -84,8 +84,12 @@
     kAudioOutputDeviceRequested = 29,
     kMixedContent = 30,
     kTriggerBackgrounded = 31,
-    kEmbedderTriggeredAndRedirected = 32,
-    kMaxValue = kEmbedderTriggeredAndRedirected,
+    // Break down into kEmbedderTriggeredAndSameOriginRedirected and
+    // kEmbedderTriggeredAndCrossOriginRedirected for investigation.
+    // kEmbedderTriggeredAndRedirected = 32,
+    kEmbedderTriggeredAndSameOriginRedirected = 33,
+    kEmbedderTriggeredAndCrossOriginRedirected = 34,
+    kMaxValue = kEmbedderTriggeredAndCrossOriginRedirected,
   };
 
   PrerenderHost(const PrerenderAttributes& attributes,
diff --git a/content/browser/prerender/prerender_internals_handler_impl.cc b/content/browser/prerender/prerender_internals_handler_impl.cc
index 1cfba9d..a87bdf3 100644
--- a/content/browser/prerender/prerender_internals_handler_impl.cc
+++ b/content/browser/prerender/prerender_internals_handler_impl.cc
@@ -72,8 +72,10 @@
       return "MixedContent";
     case PrerenderHost::FinalStatus::kTriggerBackgrounded:
       return "TriggerBackgrounded";
-    case PrerenderHost::FinalStatus::kEmbedderTriggeredAndRedirected:
-      return "EmbedderTriggeredAndRedirected";
+    case PrerenderHost::FinalStatus::kEmbedderTriggeredAndSameOriginRedirected:
+      return "EmbedderTriggeredAndSameOriginRedirected";
+    case PrerenderHost::FinalStatus::kEmbedderTriggeredAndCrossOriginRedirected:
+      return "EmbedderTriggeredAndCrossOriginRedirected";
   }
   NOTREACHED();
   return "";
diff --git a/content/browser/prerender/prerender_navigation_throttle.cc b/content/browser/prerender/prerender_navigation_throttle.cc
index e1dbd4c..f59a044 100644
--- a/content/browser/prerender/prerender_navigation_throttle.cc
+++ b/content/browser/prerender/prerender_navigation_throttle.cc
@@ -128,9 +128,15 @@
     // redirection can be same-origin or cross-origin to the initial
     // prerendering URL.
     if (is_redirection) {
+      url::Origin initial_origin =
+          url::Origin::Create(prerender_host->GetInitialUrl());
       prerender_host_registry->CancelHost(
           frame_tree_node->frame_tree_node_id(),
-          PrerenderHost::FinalStatus::kEmbedderTriggeredAndRedirected);
+          initial_origin == prerendering_origin
+              ? PrerenderHost::FinalStatus::
+                    kEmbedderTriggeredAndSameOriginRedirected
+              : PrerenderHost::FinalStatus::
+                    kEmbedderTriggeredAndCrossOriginRedirected);
       return CANCEL;
     }
 
diff --git a/content/browser/renderer_host/back_forward_cache_disable.cc b/content/browser/renderer_host/back_forward_cache_disable.cc
index adf2c0c..e7d34947 100644
--- a/content/browser/renderer_host/back_forward_cache_disable.cc
+++ b/content/browser/renderer_host/back_forward_cache_disable.cc
@@ -32,6 +32,8 @@
       return "MediaSession";
     case BackForwardCacheDisable::DisabledReasonId::kMediaSessionService:
       return "MediaSessionService";
+    case BackForwardCacheDisable::DisabledReasonId::kScreenReader:
+      return "ScreenReader";
   }
 }
 
diff --git a/content/browser/renderer_host/back_forward_cache_disable.h b/content/browser/renderer_host/back_forward_cache_disable.h
index 242a121..955c787 100644
--- a/content/browser/renderer_host/back_forward_cache_disable.h
+++ b/content/browser/renderer_host/back_forward_cache_disable.h
@@ -39,6 +39,10 @@
 
     // kMediaPlay = 12, Removed after allowing media play (crbug.com/1246240).
 
+    // TODO(crbug.com/1271450): Screen readers do not recognize a navigation
+    // when the page is served from bfcache.
+    kScreenReader = 13,
+
     // New reasons should be accompanied by a comment as to why BackForwardCache
     // cannot be used in this case and a link to a bug to fix that if it is
     // fixable.
diff --git a/content/browser/renderer_host/blocked_scheme_navigation_browsertest.cc b/content/browser/renderer_host/blocked_scheme_navigation_browsertest.cc
index e0ee55a7..b2744778 100644
--- a/content/browser/renderer_host/blocked_scheme_navigation_browsertest.cc
+++ b/content/browser/renderer_host/blocked_scheme_navigation_browsertest.cc
@@ -454,8 +454,10 @@
     EXPECT_TRUE(
         new_shell->web_contents()->GetLastCommittedURL().spec().empty());
     // No navigation should commit.
-    EXPECT_FALSE(
-        new_shell->web_contents()->GetController().GetLastCommittedEntry());
+    EXPECT_TRUE(new_shell->web_contents()
+                    ->GetController()
+                    .GetLastCommittedEntry()
+                    ->IsInitialEntry());
     // Original page shouldn't navigate away.
     EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
   }
diff --git a/content/browser/renderer_host/cross_origin_opener_policy_status.cc b/content/browser/renderer_host/cross_origin_opener_policy_status.cc
index 114a2e9d..327f89f 100644
--- a/content/browser/renderer_host/cross_origin_opener_policy_status.cc
+++ b/content/browser/renderer_host/cross_origin_opener_policy_status.cc
@@ -142,7 +142,7 @@
 
 absl::optional<network::mojom::BlockedByResponseReason>
 CrossOriginOpenerPolicyStatus::SanitizeResponse(
-    network::mojom::URLResponseHead* response) const {
+    network::mojom::URLResponseHead* response) {
   const GURL& response_url = navigation_request_->common_params().url;
   SanitizeCoopHeaders(response_url, response);
 
@@ -164,6 +164,15 @@
     DCHECK(!response_url.SchemeIsBlob());
     DCHECK(!response_url.SchemeIsFileSystem());
     DCHECK(!response_url.SchemeIs(url::kDataScheme));
+
+    // We should force a COOP browsing instance swap to avoid certain
+    // opener+error pages exploits, see https://crbug.com/1256823 and
+    // https://github.com/whatwg/html/issues/7345.
+    require_browsing_instance_swap_ = true;
+    virtual_browsing_context_group_ =
+        CrossOriginOpenerPolicyAccessReportManager::
+            NextVirtualBrowsingContextGroup();
+
     return network::mojom::BlockedByResponseReason::
         kCoopSandboxedIFrameCannotNavigateToCoopPage;
   }
diff --git a/content/browser/renderer_host/cross_origin_opener_policy_status.h b/content/browser/renderer_host/cross_origin_opener_policy_status.h
index 050991b..84e9020 100644
--- a/content/browser/renderer_host/cross_origin_opener_policy_status.h
+++ b/content/browser/renderer_host/cross_origin_opener_policy_status.h
@@ -37,9 +37,10 @@
   ~CrossOriginOpenerPolicyStatus() override;
 
   // Sanitize the COOP header from the `response`.
-  // Return an error when COOP is used on sandboxed popups.
+  // Return an error, and swap browsing context group when COOP is used on
+  // sandboxed popups.
   absl::optional<network::mojom::BlockedByResponseReason> SanitizeResponse(
-      network::mojom::URLResponseHead* response) const;
+      network::mojom::URLResponseHead* response);
 
   // Called when receiving a redirect or the final response.
   void EnforceCOOP(const network::CrossOriginOpenerPolicy& response_coop,
diff --git a/content/browser/renderer_host/frame_tree.cc b/content/browser/renderer_host/frame_tree.cc
index d24175c..10d7137 100644
--- a/content/browser/renderer_host/frame_tree.cc
+++ b/content/browser/renderer_host/frame_tree.cc
@@ -755,7 +755,6 @@
   // BrowsingInstance of a bfcache RFH while it's in the cache.
   for (auto* frame_tree_node : SubtreeNodes(root())) {
     auto* frame_host = frame_tree_node->current_frame_host();
-
     if (previously_visited_origin == frame_host->GetLastCommittedOrigin())
       matching_site_instances.insert(frame_host->GetSiteInstance());
 
@@ -789,7 +788,8 @@
 
 void FrameTree::Init(SiteInstance* main_frame_site_instance,
                      bool renderer_initiated_creation,
-                     const std::string& main_frame_name) {
+                     const std::string& main_frame_name,
+                     RenderFrameHostImpl* opener) {
   // blink::FrameTree::SetName always keeps |unique_name| empty in case of a
   // main frame - let's do the same thing here.
   std::string unique_name;
@@ -797,6 +797,21 @@
   root_->render_manager()->InitRoot(main_frame_site_instance,
                                     renderer_initiated_creation);
   root_->SetFencedFrameNonceIfNeeded();
+
+  // The initial empty document should inherit the origin of its opener (the
+  // origin may change after the first commit), except when they are in
+  // different browsing context groups (`renderer_initiated_creation` is false),
+  // where it should use a new opaque origin.
+  // See also https://crbug.com/932067.
+  //
+  // Note that the origin of the new frame might depend on sandbox flags.
+  // Checking sandbox flags of the new frame should be safe at this point,
+  // because the flags should be already inherited when creating the root node.
+  DCHECK(!renderer_initiated_creation || opener);
+  root_->current_frame_host()->SetOriginDependentStateOfNewFrame(
+      renderer_initiated_creation ? opener->GetLastCommittedOrigin()
+                                  : url::Origin());
+  controller().CreateInitialEntry();
 }
 
 void FrameTree::DidAccessInitialMainDocument() {
diff --git a/content/browser/renderer_host/frame_tree.h b/content/browser/renderer_host/frame_tree.h
index 4964f9f..acf6a07 100644
--- a/content/browser/renderer_host/frame_tree.h
+++ b/content/browser/renderer_host/frame_tree.h
@@ -199,14 +199,17 @@
   ~FrameTree();
 
   // Initializes the main frame for this FrameTree. That is it creates the
-  // initial RenderFrameHost in the root node's RenderFrameHostManager. This
-  // method will call back into the delegates so it should only be called once
-  // they have completed their initialization.
+  // initial RenderFrameHost in the root node's RenderFrameHostManager, and also
+  // creates an initial NavigationEntry that potentially inherits `opener`'s
+  // origin in its NavigationController. This method will call back into the
+  // delegates so it should only be called once they have completed their
+  // initialization.
   // TODO(carlscab): It would be great if initialization could happened in the
   // constructor so we do not leave objects in a half initialized state.
   void Init(SiteInstance* main_frame_site_instance,
             bool renderer_initiated_creation,
-            const std::string& main_frame_name);
+            const std::string& main_frame_name,
+            RenderFrameHostImpl* opener);
 
   Type type() const { return type_; }
 
diff --git a/content/browser/renderer_host/frame_tree_browsertest.cc b/content/browser/renderer_host/frame_tree_browsertest.cc
index 6ac5917..fc9b73d6 100644
--- a/content/browser/renderer_host/frame_tree_browsertest.cc
+++ b/content/browser/renderer_host/frame_tree_browsertest.cc
@@ -1588,7 +1588,7 @@
     EXPECT_EQ(root->navigator().controller().GetEntryCount(),
               fenced_frame->navigator().controller().GetEntryCount());
   } else {
-    EXPECT_EQ(0, fenced_frame->navigator().controller().GetEntryCount());
+    EXPECT_EQ(1, fenced_frame->navigator().controller().GetEntryCount());
   }
 
   // 1. Navigate the fenced frame: both cross-document and fragment navigation.
diff --git a/content/browser/renderer_host/navigation_controller_android.cc b/content/browser/renderer_host/navigation_controller_android.cc
index c5e3345..a07d7ee 100644
--- a/content/browser/renderer_host/navigation_controller_android.cc
+++ b/content/browser/renderer_host/navigation_controller_android.cc
@@ -70,7 +70,8 @@
 
   return content::Java_NavigationControllerImpl_createNavigationEntry(
       env, index, j_url, j_virtual_url, j_original_url, j_referrer_url, j_title,
-      j_bitmap, entry->GetTransitionType(), j_timestamp);
+      j_bitmap, entry->GetTransitionType(), j_timestamp,
+      entry->IsInitialEntry());
 }
 
 static void JNI_NavigationControllerImpl_AddNavigationEntryToHistory(
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc
index aa808f1..a312771 100644
--- a/content/browser/renderer_host/navigation_controller_impl.cc
+++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -179,7 +179,7 @@
   if (should_replace_current_entry)
     return false;
   // Only convert to reload if at least one navigation committed.
-  if (!last_committed_entry)
+  if (last_committed_entry->IsInitialEntry())
     return false;
 
   // Skip navigations initiated by external applications.
@@ -269,7 +269,7 @@
   // in an error as the |params.url|. Since successful reload of an error page
   // should commit in the correct origin, setting the opaque origin on the
   // FrameNavigationEntry will be incorrect.
-  if (request->DidEncounterError())
+  if (request && request->DidEncounterError())
     return absl::nullopt;
 
   // We also currently don't save committed origins for loadDataWithBaseURL
@@ -279,7 +279,7 @@
   // URL used for the navigation.
   // TODO(https://crbug.com/1198406): Save committed origin in
   // FrameNavigationEntry for this case too.
-  if (request->IsLoadDataWithBaseURL())
+  if (request && request->IsLoadDataWithBaseURL())
     return absl::nullopt;
 
   return absl::make_optional(params.origin);
@@ -332,8 +332,10 @@
 void CopyReplacedNavigationEntryDataIfPreviouslyEmpty(
     NavigationEntryImpl* replaced_entry,
     NavigationEntryImpl* output_entry) {
-  if (output_entry->GetReplacedEntryData().has_value())
+  if (output_entry->GetReplacedEntryData().has_value() ||
+      replaced_entry->IsInitialEntry()) {
     return;
+  }
 
   ReplacedNavigationEntryData data;
   data.first_committed_url = replaced_entry->GetURL();
@@ -499,19 +501,19 @@
   return true;
 }
 
-bool ShouldStorePolicyContainerPoliciesInFrameNavigationEntry(
-    const NavigationRequest* request) {
+bool ShouldStorePolicyContainerPoliciesInFrameNavigationEntry(const GURL& url) {
   // For local schemes we need to store the policy container in the
   // FrameNavigationEntry, so that we can reload it in case of history
-  // navigation.
+  // navigation. Note that `url` can be empty in case this is called for the
+  // initial NavigationEntry, which should always store the
+  // PolicyContainerPolicies.
   //
   // TODO(https://crbug.com/1146361 and https://crbug.com/1146362): blob: and
   // filesystem: should be removed from this list when we have properly
   // implemented storing their policy container in the respective store.
-  return (request->common_params().url.SchemeIs(url::kAboutScheme) ||
-          request->common_params().url.SchemeIs(url::kDataScheme) ||
-          request->common_params().url.SchemeIsBlob() ||
-          request->common_params().url.SchemeIsFileSystem());
+  return (url.is_empty() || url.SchemeIs(url::kAboutScheme) ||
+          url.SchemeIs(url::kDataScheme) || url.SchemeIsBlob() ||
+          url.SchemeIsFileSystem());
 }
 
 }  // namespace
@@ -585,7 +587,8 @@
       nullptr,  // The site instance for tabs is sent on navigation
                 // (WebContents::GetSiteInstance).
       url_to_load, referrer, initiator_origin, std::u16string(), transition,
-      is_renderer_initiated, blob_url_loader_factory);
+      is_renderer_initiated, blob_url_loader_factory,
+      /* is_initial_entry = */ false);
   entry->SetVirtualURL(virtual_url);
   entry->set_user_typed_url(virtual_url);
   entry->set_update_virtual_url_with_url(reverse_on_redirect);
@@ -657,7 +660,8 @@
     RestoreType type,
     std::vector<std::unique_ptr<NavigationEntry>>* entries) {
   // Verify that this controller is unused and that the input is valid.
-  DCHECK_EQ(0, GetEntryCount());
+  DCHECK_EQ(1, GetEntryCount());
+  DCHECK(GetLastCommittedEntry()->IsInitialEntry());
   DCHECK(!GetPendingEntry());
   DCHECK(selected_navigation >= 0 &&
          selected_navigation < static_cast<int>(entries->size()));
@@ -665,6 +669,7 @@
 
   needs_reload_ = true;
   needs_reload_type_ = NeedsReloadType::kRestoreSession;
+  entries_.clear();
   entries_.reserve(entries->size());
   for (auto& entry : *entries)
     entries_.push_back(
@@ -762,10 +767,9 @@
 }
 
 bool NavigationControllerImpl::IsInitialBlankNavigation() {
-  // TODO(creis): Once we create a NavigationEntry for the initial blank page,
-  // we'll need to check for entry count 1 and restore_type NONE (to exclude
-  // the cloned tab case).
-  return IsInitialNavigation() && GetEntryCount() == 0;
+  return IsInitialNavigation() && GetEntryCount() == 1 &&
+         GetLastCommittedEntry()->IsInitialEntry() &&
+         GetLastCommittedEntry()->restore_type() == RestoreType::kNotRestored;
 }
 
 NavigationEntryImpl* NavigationControllerImpl::GetEntryWithUniqueID(
@@ -867,13 +871,13 @@
 
 int NavigationControllerImpl::GetLastCommittedEntryIndex() {
   // The last committed entry index must always be less than the number of
-  // entries.  If there are no entries, it must be -1.
+  // entries.
   DCHECK_LT(last_committed_entry_index_, GetEntryCount());
-  DCHECK(GetEntryCount() || last_committed_entry_index_ == -1);
   return last_committed_entry_index_;
 }
 
 int NavigationControllerImpl::GetEntryCount() {
+  DCHECK_GE(entries_.size(), 1u);
   DCHECK_LE(entries_.size(), max_entry_count());
   return static_cast<int>(entries_.size());
 }
@@ -1264,6 +1268,10 @@
     // in turn send it back here as part of |params| and it can be just
     // enforced and renderer process terminated on mismatch.
     details->did_replace_entry = true;
+  } else if (!params.history_list_was_cleared && !rfh->GetParent() &&
+             GetLastCommittedEntry()->IsInitialEntry()) {
+    // Make sure we always replace the initial NavigationEntry.
+    details->did_replace_entry = true;
   } else {
     // The renderer tells us whether the navigation replaces the current entry.
     details->did_replace_entry = params.should_replace_current_entry;
@@ -1437,26 +1445,25 @@
     NavigationRequest* navigation_request) {
   TraceReturnReason<tracing_category::kNavigation> trace_return(
       "ClassifyNavigation");
+  DCHECK(GetLastCommittedEntry());
+  if (navigation_request->is_synchronous_renderer_commit() &&
+      !navigation_request->IsSameDocument() && !rfh->GetParent() &&
+      params.should_replace_current_entry) {
+    // Ignore the synchronous about:blank commit for window.open() to preserve
+    // previous behavior.
+    trace_return.set_return_reason(
+        "synchronous about:blank for window.open(), ignore");
+    return NAVIGATION_TYPE_NAV_IGNORE;
+  }
 
   if (params.did_create_new_entry) {
-    // A new entry. We may or may not have a corresponding pending entry, and
-    // this may or may not be the main frame.
+    // A new entry for either the main frame or a subframe.
     if (!rfh->GetParent()) {
       trace_return.set_return_reason("new entry, no parent, new entry");
       return NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY;
     }
 
-    // When this is a new subframe navigation, we should have a committed page
-    // in which it's a subframe. This may not be the case when an iframe is
-    // navigated on a popup navigated to about:blank (the iframe would be
-    // written into the popup by script on the main page). For these cases,
-    // there isn't any navigation stuff we can do, so just ignore it.
-    if (!GetLastCommittedEntry()) {
-      trace_return.set_return_reason("new entry, no last committed, ignore");
-      return NAVIGATION_TYPE_NAV_IGNORE;
-    }
-
-    // Valid subframe navigation.
+    // Subframe navigation.
     trace_return.set_return_reason("new entry, new subframe");
     return NAVIGATION_TYPE_NEW_SUBFRAME;
   }
@@ -1467,15 +1474,8 @@
   if (rfh->GetParent()) {
     // All manual subframes would be did_create_new_entry and handled above, so
     // we know this is auto.
-    if (GetLastCommittedEntry()) {
-      trace_return.set_return_reason("subframe, last commmited, auto subframe");
-      return NAVIGATION_TYPE_AUTO_SUBFRAME;
-    }
-
-    // We ignore subframes created in non-committed pages; we'd appreciate if
-    // people stopped doing that.
-    trace_return.set_return_reason("subframe, no last commmited, ignore");
-    return NAVIGATION_TYPE_NAV_IGNORE;
+    trace_return.set_return_reason("subframe, last commmited, auto subframe");
+    return NAVIGATION_TYPE_AUTO_SUBFRAME;
   }
 
   const int nav_entry_id = navigation_request->commit_params().nav_entry_id;
@@ -1483,15 +1483,6 @@
     // This is a renderer-initiated navigation (nav_entry_id == 0), but didn't
     // create a new page.
 
-    // Just like above in the did_create_new_entry case, it's possible to
-    // scribble onto an uncommitted page. Again, there isn't any navigation
-    // stuff that we can do, so ignore it here as well.
-    NavigationEntry* last_committed = GetLastCommittedEntry();
-    if (!last_committed) {
-      trace_return.set_return_reason("nav entry 0, no last committed, ignore");
-      return NAVIGATION_TYPE_NAV_IGNORE;
-    }
-
     // This main frame navigation is not a history navigation (since
     // nav_entry_id is 0), but didn't create a new entry. So this must be a
     // reload or a replacement navigation, which will modify the existing entry.
@@ -1593,20 +1584,24 @@
     NavigationEntryImpl::UpdatePolicy update_policy,
     bool is_new_entry) {
   // Update the FrameNavigationEntry.
+
+  std::vector<GURL> redirects;
   entry->AddOrUpdateFrameEntry(
       rfh->frame_tree_node(), update_policy, params.item_sequence_number,
       params.document_sequence_number, params.app_history_key,
       rfh->GetSiteInstance(), nullptr, params.url,
       GetCommittedOriginForFrameEntry(params, request),
-      Referrer(*params.referrer), request->common_params().initiator_origin,
-      request->GetRedirectChain(), params.page_state, params.method,
-      params.post_id, nullptr /* blob_url_loader_factory */,
-      request->web_bundle_navigation_info()
+      Referrer(*params.referrer),
+      request ? request->common_params().initiator_origin : params.origin,
+      request ? request->GetRedirectChain() : redirects, params.page_state,
+      params.method, params.post_id, nullptr /* blob_url_loader_factory */,
+      (request && request->web_bundle_navigation_info())
           ? request->web_bundle_navigation_info()->Clone()
           : nullptr,
-      request->GetSubresourceWebBundleNavigationInfo(),
+      (request ? request->GetSubresourceWebBundleNavigationInfo() : nullptr),
       ComputePolicyContainerPoliciesForFrameEntry(
-          rfh, request->IsSameDocument(), request));
+          rfh, request && request->IsSameDocument(),
+          request ? request->common_params().url : params.url));
 
   if (rfh->GetParent()) {
     // Only modify the NavigationEntry for main frame navigations.
@@ -1617,13 +1612,15 @@
   // Don't use the page type from the pending entry. Some interstitial page
   // may have set the type to interstitial. Once we commit, however, the page
   // type must always be normal or error.
-  entry->set_page_type(request->DidEncounterError() ? PAGE_TYPE_ERROR
-                                                    : PAGE_TYPE_NORMAL);
+  entry->set_page_type((request && request->DidEncounterError())
+                           ? PAGE_TYPE_ERROR
+                           : PAGE_TYPE_NORMAL);
   if (is_new_entry) {
     // Some properties of the NavigationEntry are only set when the entry is
     // new (we aren't reusing it).
     entry->SetTransitionType(params.transition);
-    entry->SetOriginalRequestURL(request->GetOriginalRequestURL());
+    entry->SetOriginalRequestURL(request ? request->GetOriginalRequestURL()
+                                         : GURL::EmptyGURL());
     DCHECK_EQ(rfh->is_overriding_user_agent(), params.is_overriding_user_agent);
     entry->SetIsOverridingUserAgent(params.is_overriding_user_agent);
   } else {
@@ -1636,6 +1633,47 @@
   }
 }
 
+void NavigationControllerImpl::CreateInitialEntry() {
+  DCHECK_EQ(entries_.size(), 0u);
+  RenderFrameHostImpl* rfh = frame_tree_.root()->current_frame_host();
+  auto params = mojom::DidCommitProvisionalLoadParams::New();
+  // The initial NavigationEntry's URL is the empty URL. This preserves the old
+  // behavior of WebContent's GetLastCommittedURL() and GetVisibleURL() from
+  // before we have initial NavigationEntries.
+  params->url = GURL::EmptyGURL();
+  params->http_status_code = 0;
+  params->url_is_unreachable = false;
+  params->method = "GET";
+  params->should_replace_current_entry = false;
+  params->post_id = -1;
+  params->embedding_token = base::UnguessableToken::Create();
+  params->navigation_token = base::UnguessableToken::Create();
+  params->did_create_new_entry = true;
+  params->origin = rfh->GetLastCommittedOrigin();
+  params->should_update_history = true;
+  params->item_sequence_number = 0;
+  params->document_sequence_number = 0;
+  bool is_in_fenced_frame_tree = rfh->frame_tree_node()->IsInFencedFrameTree();
+  params->transition = is_in_fenced_frame_tree
+                           ? ui::PAGE_TRANSITION_AUTO_SUBFRAME
+                           : ui::PAGE_TRANSITION_LINK;
+  params->referrer = blink::mojom::Referrer::New();
+
+  // Create and insert the initial NavigationEntry.
+  auto new_entry = std::make_unique<NavigationEntryImpl>(
+      rfh->GetSiteInstance(), params->url, Referrer(*params->referrer),
+      rfh->GetLastCommittedOrigin(), std::u16string() /* title */,
+      ui::PAGE_TRANSITION_TYPED, false /* renderer_initiated */,
+      nullptr /* blob_url_loader_factory */, true /* is_initial_entry */);
+  UpdateNavigationEntryDetails(
+      new_entry.get(), rfh, *params, nullptr /* request */,
+      NavigationEntryImpl::UpdatePolicy::kUpdate, true /* is_new_entry */);
+
+  InsertOrReplaceEntry(std::move(new_entry), false /* replace_entry */,
+                       false /* was_post_commit_error */,
+                       is_in_fenced_frame_tree);
+}
+
 void NavigationControllerImpl::RendererDidNavigateToNewEntry(
     RenderFrameHostImpl* rfh,
     const mojom::DidCommitProvisionalLoadParams& params,
@@ -1720,7 +1758,8 @@
         initiator_origin,
         std::u16string(),  // title
         params.transition, request->IsRendererInitiated(),
-        nullptr);  // blob_url_loader_factory
+        nullptr,  // blob_url_loader_factory
+        false);   // is_initial_entry
 
     // Find out whether the new entry needs to update its virtual URL on URL
     // change and set up the entry accordingly. This is needed to correctly
@@ -1957,7 +1996,7 @@
           : nullptr,
       request->GetSubresourceWebBundleNavigationInfo(),
       ComputePolicyContainerPoliciesForFrameEntry(rfh, is_same_document,
-                                                  request));
+                                                  request->GetURL()));
 
   std::unique_ptr<NavigationEntryImpl> new_entry =
       GetLastCommittedEntry()->CloneAndReplace(
@@ -2089,11 +2128,15 @@
   NavigationControllerImpl* source =
       static_cast<NavigationControllerImpl*>(temp);
   // Verify that we look new.
-  DCHECK_EQ(0, GetEntryCount());
+  DCHECK_EQ(1, GetEntryCount());
+  DCHECK(GetLastCommittedEntry()->IsInitialEntry());
   DCHECK(!GetPendingEntry());
+  entries_.clear();
 
-  if (source->GetEntryCount() == 0)
-    return;  // Nothing new to do.
+  if (source->GetEntryCount() == 0) {
+    NOTREACHED();
+    return;
+  }
 
   needs_reload_ = needs_reload;
   needs_reload_type_ = NeedsReloadType::kCopyStateFrom;
@@ -2129,10 +2172,8 @@
   // Insert the entries from source. Ignore any pending entry, since it has not
   // committed in source.
   int max_source_index = source->last_committed_entry_index_;
-  if (max_source_index == -1)
-    max_source_index = source->GetEntryCount();
-  else
-    max_source_index++;
+  DCHECK_NE(max_source_index, -1);
+  max_source_index++;
 
   // Ignore the source's current entry if merging with replacement.
   // TODO(davidben): This should preserve entries forward of the current
@@ -2378,11 +2419,6 @@
 
   FrameTreeNode* node = render_frame_host->frame_tree_node();
 
-  // Don't allow an entry replacement if there is no entry to replace.
-  // http://crbug.com/457149
-  if (GetEntryCount() == 0)
-    should_replace_current_entry = false;
-
   // Create a NavigationEntry for the transfer, without making it the pending
   // entry. Subframe transfers should have a clone of the last committed entry
   // with a FrameNavigationEntry for the target frame. Main frame transfers
@@ -2393,23 +2429,13 @@
   std::unique_ptr<NavigationEntryImpl> entry;
   if (!render_frame_host->is_main_frame()) {
     // Subframe case: create FrameNavigationEntry.
-    if (GetLastCommittedEntry()) {
-      entry = GetLastCommittedEntry()->Clone();
-      entry->set_extra_headers(extra_headers);
-      // TODO(arthursonzogni): What about |is_renderer_initiated|?
-      // Renderer-initiated navigation that target a remote frame are currently
-      // classified as browser-initiated when this one has already navigated.
-      // See https://crbug.com/722251.
-    } else {
-      // If there's no last committed entry, create an entry for about:blank
-      // with a subframe entry for our destination.
-      // TODO(creis): Ensure this case can't exist in https://crbug.com/524208.
-      entry = NavigationEntryImpl::FromNavigationEntry(CreateNavigationEntry(
-          GURL(url::kAboutBlankURL), referrer, initiator_origin,
-          source_site_instance, page_transition, is_renderer_initiated,
-          extra_headers, browser_context_,
-          nullptr /* blob_url_loader_factory */));
-    }
+    CHECK(GetLastCommittedEntry());
+    entry = GetLastCommittedEntry()->Clone();
+    entry->set_extra_headers(extra_headers);
+    // TODO(arthursonzogni): What about |is_renderer_initiated|?
+    // Renderer-initiated navigation that target a remote frame are currently
+    // classified as browser-initiated when this one has already navigated.
+    // See https://crbug.com/722251.
     // The UpdatePolicy doesn't matter here. |entry| is only used as a parameter
     // to CreateNavigationRequestFromLoadParams(), so while kReplace might
     // remove child FrameNavigationEntries (e.g., if this is a cross-process
@@ -2528,7 +2554,7 @@
 }
 
 bool NavigationControllerImpl::IsUnmodifiedBlankTab() {
-  return IsInitialNavigation() && !GetLastCommittedEntry() &&
+  return IsInitialNavigation() && GetLastCommittedEntry()->IsInitialEntry() &&
          !frame_tree_.has_accessed_initial_main_document();
 }
 
@@ -2631,9 +2657,7 @@
 
 int NavigationControllerImpl::GetPendingEntryIndex() {
   // The pending entry index must always be less than the number of entries.
-  // If there are no entries, it must be exactly -1.
   DCHECK_LT(pending_entry_index_, GetEntryCount());
-  DCHECK(GetEntryCount() != 0 || pending_entry_index_ == -1);
   return pending_entry_index_;
 }
 
@@ -3164,14 +3188,13 @@
   }
 
   // If this navigation is an "Enter-in-omnibox" with the initial about:blank
-  // document (so no last commit), then we should copy the document polices from
-  // RenderFrameHost's PolicyContainerHost. The NavigationRequest will create a
-  // new PolicyContainerHost with the document policies from the
-  // |pending_entry_|, and that PolicyContainerHost will be put in the final
-  // RenderFrameHost for the navigation. This way, we ensure that we keep
-  // enforcing the right policies on the initial empty document after the
-  // reload.
-  if (!GetLastCommittedEntry() && params.url.IsAboutBlank()) {
+  // document, then we should copy the document polices from RenderFrameHost's
+  // PolicyContainerHost. The NavigationRequest will create a new
+  // PolicyContainerHost with the document policies from the |pending_entry_|,
+  // and that PolicyContainerHost will be put in the final RenderFrameHost for
+  // the navigation. This way, we ensure that we keep enforcing the right
+  // policies on the initial empty document after the reload.
+  if (GetLastCommittedEntry()->IsInitialEntry() && params.url.IsAboutBlank()) {
     if (node->current_frame_host() &&
         node->current_frame_host()->policy_container_host()) {
       pending_entry_->GetFrameEntry(node)->set_policy_container_policies(
@@ -3267,19 +3290,8 @@
 
   // For subframes, create a pending entry with a corresponding frame entry.
   if (!node->IsMainFrame()) {
-    if (GetLastCommittedEntry()) {
-      entry = GetLastCommittedEntry()->Clone();
-    } else {
-      // If there's no last committed entry, create an entry for about:blank
-      // with a subframe entry for our destination.
-      // TODO(creis): Ensure this case can't exist in https://crbug.com/524208.
-      entry = NavigationEntryImpl::FromNavigationEntry(CreateNavigationEntry(
-          GURL(url::kAboutBlankURL), params.referrer, params.initiator_origin,
-          params.source_site_instance.get(), params.transition_type,
-          params.is_renderer_initiated, extra_headers_crlf, browser_context_,
-          blob_url_loader_factory));
-    }
-
+    CHECK(GetLastCommittedEntry());
+    entry = GetLastCommittedEntry()->Clone();
     entry->AddOrUpdateFrameEntry(
         node, NavigationEntryImpl::UpdatePolicy::kReplace, -1, -1, "", nullptr,
         static_cast<SiteInstanceImpl*>(params.source_site_instance.get()),
@@ -3554,6 +3566,13 @@
     bool is_browser_initiated) {
   DCHECK(frame_entry);
   GURL dest_url = frame_entry->url();
+  if (entry->IsInitialEntry() && frame_tree_node->IsMainFrame()) {
+    // The main frame of an initial NavigationEntry has an empty URL. Convert it
+    // to about:blank instead. This should only happen when the initial
+    // NavigationEntry is reloaded.
+    DCHECK(dest_url.is_empty());
+    dest_url = GURL("about:blank");
+  }
   absl::optional<url::Origin> origin_to_commit =
       frame_entry->committed_origin();
 
@@ -3836,6 +3855,7 @@
     entries_.insert(entries_.begin() + i,
                     source->entries_[i]->CloneWithoutSharing(context.get()));
   }
+  DCHECK_GE(entries_.size(), 1u);
   DCHECK(pending_entry_index_ == -1 ||
          pending_entry_ == GetEntryAtIndex(pending_entry_index_));
 }
@@ -3938,15 +3958,12 @@
 NavigationControllerImpl::ComputePolicyContainerPoliciesForFrameEntry(
     RenderFrameHostImpl* rfh,
     bool is_same_document,
-    NavigationRequest* request) {
-  if (!ShouldStorePolicyContainerPoliciesInFrameNavigationEntry(request))
+    const GURL& url) {
+  if (!ShouldStorePolicyContainerPoliciesInFrameNavigationEntry(url))
     return nullptr;
 
   if (is_same_document) {
-    // TODO(https://crbug.com/524208): Remove this nullptr check when we can
-    // ensure we always have a FrameNavigationEntry here.
-    if (!GetLastCommittedEntry())
-      return nullptr;
+    CHECK(GetLastCommittedEntry());
 
     FrameNavigationEntry* previous_frame_entry =
         GetLastCommittedEntry()->GetFrameEntry(rfh->frame_tree_node());
@@ -4080,6 +4097,11 @@
     SiteInstance* site_instance,
     int64_t previous_item_sequence_number) {
   std::vector<blink::mojom::AppHistoryEntryPtr> entries;
+  if (GetLastCommittedEntry()->IsInitialEntry()) {
+    // Don't process the initial entry.
+    DCHECK_EQ(GetEntryCount(), 1);
+    return entries;
+  }
   int offset = direction == Direction::kForward ? 1 : -1;
   for (int i = entry_index + offset; i >= 0 && i < GetEntryCount();
        i += offset) {
@@ -4104,6 +4126,7 @@
               frame_state.item_sequence_number,
               frame_state.document_sequence_number,
               frame_state.app_history_state.value_or(std::u16string()));
+
       DCHECK(pending_origin.CanBeDerivedFrom(GURL(entry->url)));
       entries.push_back(std::move(entry));
       previous_item_sequence_number = frame_entry->item_sequence_number();
diff --git a/content/browser/renderer_host/navigation_controller_impl.h b/content/browser/renderer_host/navigation_controller_impl.h
index afa2b04..c36ee04f 100644
--- a/content/browser/renderer_host/navigation_controller_impl.h
+++ b/content/browser/renderer_host/navigation_controller_impl.h
@@ -154,6 +154,11 @@
   bool IsEntryMarkedToBeSkipped(int index) override;
   BackForwardCacheImpl& GetBackForwardCache() override;
 
+  // Creates the initial NavigationEntry for the NavigationController when its
+  // FrameTree is being initialized. See NavigationEntry::IsInitialEntry() on
+  // what this means.
+  void CreateInitialEntry();
+
   // Starts a navigation in a newly created subframe as part of a history
   // navigation. Returns true if the history navigation could start, false
   // otherwise.  If this returns false, the caller should do a regular
@@ -677,7 +682,7 @@
   std::unique_ptr<PolicyContainerPolicies>
   ComputePolicyContainerPoliciesForFrameEntry(RenderFrameHostImpl* rfh,
                                               bool is_same_document,
-                                              NavigationRequest* request);
+                                              const GURL& url);
 
   // Adds details from a committed navigation to `entry` and the
   // FrameNavigationEntry corresponding to `rfh`.
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
index 7059f39c..b39c84f 100644
--- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -1859,26 +1859,25 @@
 
 }  // namespace
 
-// Some pages create a popup, then write an iframe into it. This causes a
+// Some pages create a popup, then write an iframe into it. This used to cause a
 // subframe navigation without having any committed entry. Such navigations
-// just get thrown on the ground, but we shouldn't crash.
-//
-// This test actually hits NAVIGATION_TYPE_NAV_IGNORE four times. Two of them,
-// the initial window.open() and the iframe creation, don't try to create
-// navigation entries, and the third and fourth, the new navigations, try to.
+// used to just get thrown on the ground, but we shouldn't crash.
 IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, SubframeOnEmptyPage) {
   // Navigate to a page to force the renderer process to start.
   EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
 
-  // Pop open a new window with no last committed entry.
+  // Pop open a new window with only the initial entry.
   Shell* new_shell = OpenBlankWindow(contents());
   FrameTreeNode* new_root =
       static_cast<WebContentsImpl*>(new_shell->web_contents())
           ->GetPrimaryFrameTree()
           .root();
+  EXPECT_TRUE(new_shell->web_contents()
+                  ->GetController()
+                  .GetLastCommittedEntry()
+                  ->IsInitialEntry());
 
   // Make a new iframe in it.
-  NoNavigationsObserver observer(new_shell->web_contents());
   {
     LoadCommittedCapturer capturer(new_shell->web_contents());
     std::string script =
@@ -1888,20 +1887,29 @@
   }
   ASSERT_EQ(1U, new_root->child_count());
   ASSERT_NE(nullptr, new_root->child_at(0));
+  // We created a FrameNavigationEntry for the new iframe.
+  EXPECT_TRUE(
+      static_cast<NavigationEntryImpl*>(
+          new_shell->web_contents()->GetController().GetLastCommittedEntry())
+          ->GetFrameEntry(new_root->child_at(0)));
 
   // Navigate it cross-site.
   GURL frame_url = embedded_test_server()->GetURL(
       "foo.com", "/navigation_controller/simple_page_2.html");
   {
-    LoadCommittedCapturer capturer(new_shell->web_contents());
+    LoadCommittedCapturer capturer(new_root->child_at(0));
     std::string script = JsReplace("location.assign($1);", frame_url);
     EXPECT_TRUE(ExecJs(new_root->child_at(0), script));
     capturer.Wait();
   }
 
-  // Success is not crashing, and not navigating.
-  EXPECT_EQ(nullptr,
-            new_shell->web_contents()->GetController().GetLastCommittedEntry());
+  // We successfully navigated in the iframe.
+  EXPECT_EQ(
+      frame_url,
+      static_cast<NavigationEntryImpl*>(
+          new_shell->web_contents()->GetController().GetLastCommittedEntry())
+          ->GetFrameEntry(new_root->child_at(0))
+          ->url());
 
   // A nested iframe with a cross-site URL should also be able to commit.
   GURL grandchild_url(embedded_test_server()->GetURL(
@@ -1914,6 +1922,12 @@
   }
   ASSERT_EQ(1U, new_root->child_at(0)->child_count());
   EXPECT_EQ(grandchild_url, new_root->child_at(0)->child_at(0)->current_url());
+  EXPECT_EQ(
+      grandchild_url,
+      static_cast<NavigationEntryImpl*>(
+          new_shell->web_contents()->GetController().GetLastCommittedEntry())
+          ->GetFrameEntry(new_root->child_at(0)->child_at(0))
+          ->url());
 }
 
 // Test that the renderer is not killed after an auto subframe navigation if the
@@ -3882,16 +3896,17 @@
     }
   }
 
-  // Navigates |web_contents| to |url| then checks if its navigation type is
-  // NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY and whether other related properties
-  // are consistent with the type. Whether the navigation is renderer-initiated
-  // or not depends on the renderer vs browser initiated parameter of this test
-  // class.
-  void NavigateWindowAndCheckNavigationTypeIsNewEntry(
-      WebContentsImpl* web_contents,
-      const GURL& url,
-      bool wait_for_previous_navigations = true,
-      bool expect_same_document = false) {
+  // Navigates |web_contents| to |url| then check its navigation type and
+  // whether other related properties are consistent with the type. Whether the
+  // navigation is renderer-initiated or not depends on the renderer vs browser
+  // initiated parameter of this test class.
+  void NavigateWindowAndCheck(WebContentsImpl* web_contents,
+                              const GURL& url,
+                              bool wait_for_previous_navigations = true,
+                              bool expect_same_document = false,
+                              NavigationType expected_navigation_type =
+                                  NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY,
+                              bool expect_replace = true) {
     FrameTreeNode* root = web_contents->GetPrimaryFrameTree().root();
     LoadCommittedDetailsObserver load_details_observer(web_contents);
     FrameNavigateParamsCapturer capturer(root);
@@ -3916,8 +3931,8 @@
     capturer.Wait();
     load_details_observer.Wait();
 
-    EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
-    EXPECT_FALSE(capturer.did_replace_entry());
+    EXPECT_EQ(expected_navigation_type, capturer.navigation_type());
+    EXPECT_EQ(expect_replace, capturer.did_replace_entry());
 
     // Check both NavigationHandle and LoadCommittedDetails for whether this was
     // considered same-document, as these have diverged in the past.
@@ -4221,54 +4236,58 @@
   {
     SCOPED_TRACE(testing::Message() << " Testing case 1.");
 
-    // Create a new blank window that won't create a NavigationEntry.
+    // Create a new blank window.
     Shell* new_shell = OpenBlankWindow(contents());
     WebContentsImpl* new_contents =
         static_cast<WebContentsImpl*>(new_shell->web_contents());
     NavigationControllerImpl& controller = new_contents->GetController();
-    EXPECT_EQ(0, controller.GetEntryCount());
-    EXPECT_FALSE(controller.GetLastCommittedEntry());
+    // Since the new window did a synchronous about:blank commit but it got
+    // dropped, it is still on the initial NavigationEntry.
+    EXPECT_TRUE(controller.GetLastCommittedEntry()->IsInitialEntry());
 
     // Navigating the window to |url_2| will be classified as NEW_ENTRY and will
-    // add a new entry.
-    NavigateWindowAndCheckNavigationTypeIsNewEntry(new_contents, url_2);
+    // replace the previous entry.
+    NavigateWindowAndCheck(new_contents, url_2);
     EXPECT_EQ(1, controller.GetEntryCount());
-    EXPECT_TRUE(controller.GetLastCommittedEntry());
+    EXPECT_FALSE(controller.GetLastCommittedEntry()->IsInitialEntry());
   }
 
   // 2) Navigate to about:blank on a new window that hasn't done any navigation.
   {
     SCOPED_TRACE(testing::Message() << " Testing case 2.");
 
-    // Create a new blank window that won't create a NavigationEntry.
+    // Create a new blank window.
     Shell* new_shell = OpenBlankWindow(contents());
     WebContentsImpl* new_contents =
         static_cast<WebContentsImpl*>(new_shell->web_contents());
     NavigationControllerImpl& controller = new_contents->GetController();
-    EXPECT_EQ(0, controller.GetEntryCount());
-    EXPECT_FALSE(controller.GetLastCommittedEntry());
+    EXPECT_EQ(1, controller.GetEntryCount());
+    NavigationEntry* last_entry = controller.GetLastCommittedEntry();
+    EXPECT_TRUE(last_entry->IsInitialEntry());
 
     // The window should be on the initial empty document.
     FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
     EXPECT_TRUE(new_root->is_on_initial_empty_document());
 
     // Navigating the window to about:blank will be classified as NEW_ENTRY
-    // and will add a new entry.
-    NavigateWindowAndCheckNavigationTypeIsNewEntry(new_contents,
-                                                   GURL("about:blank"));
+    // and will replace the initial entry.
+    NavigateWindowAndCheck(new_contents, GURL("about:blank"));
     EXPECT_EQ(1, controller.GetEntryCount());
-    EXPECT_TRUE(controller.GetLastCommittedEntry());
+    EXPECT_NE(last_entry, controller.GetLastCommittedEntry());
+    last_entry = controller.GetLastCommittedEntry();
 
     // The window is no longer on the initial empty document.
     EXPECT_FALSE(new_root->is_on_initial_empty_document());
 
     // Navigating the window to about:blank#foo will be classified as a same-
     // document NEW_ENTRY, and will add a new entry.
-    NavigateWindowAndCheckNavigationTypeIsNewEntry(
-        new_contents, GURL("about:blank#foo"),
-        true /* wait_for_previous_navigations */,
-        true /* expect_same_document */);
+    NavigateWindowAndCheck(new_contents, GURL("about:blank#foo"),
+                           true /* wait_for_previous_navigations */,
+                           true /* expect_same_document */,
+                           NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY,
+                           false /* expect_replace */);
     EXPECT_EQ(2, controller.GetEntryCount());
+    EXPECT_NE(last_entry, controller.GetLastCommittedEntry());
 
     // The window is still marked as no longer being on the initial empty
     // document.
@@ -4280,26 +4299,35 @@
   {
     SCOPED_TRACE(testing::Message() << " Testing case 3.");
 
-    // Create a new blank window that won't create a NavigationEntry.
+    // Create a new blank window.
     Shell* new_shell = OpenBlankWindow(contents());
     WebContentsImpl* new_contents =
         static_cast<WebContentsImpl*>(new_shell->web_contents());
     NavigationControllerImpl& controller = new_contents->GetController();
-    EXPECT_EQ(0, controller.GetEntryCount());
-    EXPECT_FALSE(controller.GetLastCommittedEntry());
+    EXPECT_EQ(1, controller.GetEntryCount());
+    NavigationEntry* last_entry = controller.GetLastCommittedEntry();
+    EXPECT_TRUE(last_entry->IsInitialEntry());
 
     // The window should be on the initial empty document.
     FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
     EXPECT_TRUE(new_root->is_on_initial_empty_document());
 
     // Navigating the window to about:blank#foo will be classified as a same-
-    // document NEW_ENTRY, and will add a new entry.
-    NavigateWindowAndCheckNavigationTypeIsNewEntry(
-        new_contents, GURL("about:blank#foo"),
-        true /* wait_for_previous_navigations */,
-        true /* expect_same_document */);
+    // document replacement, and will be classified as EXISTING_ENTRY and modify
+    // the last NavigationEntry for browser-initiated navigations, but it will
+    // be classified as NEW_ENTRY for renderer-initiated navigations, because
+    // of how main frame initial empty documents are handled in the renderer.
+    // TODO(https://crbug.com/1215096): Fix the renderer-initiated navigation
+    // case.
+    NavigateWindowAndCheck(new_contents, GURL("about:blank#foo"),
+                           true /* wait_for_previous_navigations */,
+                           true /* expect_same_document */,
+                           renderer_initiated()
+                               ? NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY
+                               : NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY);
     EXPECT_EQ(1, controller.GetEntryCount());
-    EXPECT_TRUE(controller.GetLastCommittedEntry());
+    EXPECT_EQ(renderer_initiated(),
+              last_entry != controller.GetLastCommittedEntry());
 
     // The window should still be on the initial empty document.
     EXPECT_TRUE(new_root->is_on_initial_empty_document());
@@ -4310,15 +4338,16 @@
   {
     SCOPED_TRACE(testing::Message() << " Testing case 4.");
 
-    // Create a new window with URL set to about:blank, which will create a
-    // NavigationEntry.
+    // Create a new window with URL set to about:blank.
     Shell* new_shell = OpenWindow(contents(), GURL("about:blank"));
     WebContentsImpl* new_contents =
         static_cast<WebContentsImpl*>(new_shell->web_contents());
     NavigationControllerImpl& controller = new_contents->GetController();
     EXPECT_EQ(1, controller.GetEntryCount());
+    // Since the new window did a synchronous about:blank commit, it is no
+    // longer on the initial NavigationEntry.
     NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
-    EXPECT_TRUE(last_entry);
+    EXPECT_FALSE(last_entry->IsInitialEntry());
 
     // The window should be on the initial empty document.
     FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
@@ -4326,10 +4355,11 @@
 
     // Do a navigation on the window to about:blank#foo, creating a
     // same-document navigation.
-    NavigateWindowAndCheckNavigationTypeIsNewEntry(
-        new_contents, GURL("about:blank#foo"),
-        true /* wait_for_previous_navigations */,
-        true /* expect_same_document */);
+    NavigateWindowAndCheck(new_contents, GURL("about:blank#foo"),
+                           true /* wait_for_previous_navigations */,
+                           true /* expect_same_document */,
+                           NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY,
+                           false /* expect_replace */);
     EXPECT_EQ(2, controller.GetEntryCount());
     EXPECT_NE(last_entry, controller.GetLastCommittedEntry());
     // Check that we did a same-document navigation (the DSN stays the same).
@@ -4343,7 +4373,10 @@
 
     // Navigating the window to |url_2| will be classified as NEW_ENTRY and will
     // add a new entry.
-    NavigateWindowAndCheckNavigationTypeIsNewEntry(new_contents, url_2);
+    NavigateWindowAndCheck(
+        new_contents, url_2, true /* wait_for_previous_navigations */,
+        false /* expect_same_document */, NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY,
+        false /* expect_replace */);
     EXPECT_EQ(3, controller.GetEntryCount());
     EXPECT_NE(last_entry, controller.GetLastCommittedEntry());
 
@@ -4357,24 +4390,24 @@
     SCOPED_TRACE(testing::Message() << " Testing case 5.");
 
     // Create a new window with URL set to a URL that never commits, which will
-    // not create a NavigationEntry.
+    // stay on the initial NavigationEntry.
     Shell* new_shell = OpenWindow(contents(), hung_url);
     WebContentsImpl* new_contents =
         static_cast<WebContentsImpl*>(new_shell->web_contents());
     NavigationControllerImpl& controller = new_contents->GetController();
-    EXPECT_EQ(0, controller.GetEntryCount());
-    EXPECT_FALSE(controller.GetLastCommittedEntry());
+    EXPECT_EQ(1, controller.GetEntryCount());
+    EXPECT_TRUE(controller.GetLastCommittedEntry()->IsInitialEntry());
 
     // The window should be on the initial empty document.
     FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
     EXPECT_TRUE(new_root->is_on_initial_empty_document());
 
     // Navigate to |url_2|, and ensure that we won't wait for the |hung_url|
-    // navigation to finish.
-    NavigateWindowAndCheckNavigationTypeIsNewEntry(
-        new_contents, url_2, false /* wait_for_previous_navigations */);
+    // navigation to finish. The initial NavigationEntry will be replaced.
+    NavigateWindowAndCheck(new_contents, url_2,
+                           false /* wait_for_previous_navigations */);
     EXPECT_EQ(1, controller.GetEntryCount());
-    EXPECT_TRUE(controller.GetLastCommittedEntry());
+    EXPECT_FALSE(controller.GetLastCommittedEntry()->IsInitialEntry());
 
     // The window is no longer on the initial empty document.
     EXPECT_FALSE(new_root->is_on_initial_empty_document());
@@ -4384,13 +4417,12 @@
   {
     SCOPED_TRACE(testing::Message() << " Testing case 6.");
 
-    // Create a new blank window that won't create a NavigationEntry.
+    // Create a new blank window.
     Shell* new_shell = OpenBlankWindow(contents());
     WebContentsImpl* new_contents =
         static_cast<WebContentsImpl*>(new_shell->web_contents());
     NavigationControllerImpl& controller = new_contents->GetController();
-    EXPECT_EQ(0, controller.GetEntryCount());
-    EXPECT_FALSE(controller.GetLastCommittedEntry());
+    EXPECT_EQ(1, controller.GetEntryCount());
 
     // The window should be on its initial empty document.
     FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
@@ -4410,7 +4442,7 @@
 
     // The document.open() changed the window's URL in the renderer to be the
     // same as the main tab's URL, but doesn't actually commit a navigation.
-    EXPECT_EQ(0, controller.GetEntryCount());
+    EXPECT_EQ(1, controller.GetEntryCount());
     EXPECT_EQ(GURL("about:blank"),
               new_contents->GetMainFrame()->GetLastCommittedURL());
     EXPECT_EQ(main_window_url,
@@ -4420,8 +4452,8 @@
     EXPECT_FALSE(new_root->is_on_initial_empty_document());
 
     // Navigating the window to |url_2| will be classified as NEW_ENTRY and will
-    // add a new entry.
-    NavigateWindowAndCheckNavigationTypeIsNewEntry(new_contents, url_2);
+    // replace the previous entry.
+    NavigateWindowAndCheck(new_contents, url_2);
     EXPECT_EQ(1, controller.GetEntryCount());
     EXPECT_TRUE(controller.GetLastCommittedEntry());
   }
@@ -4432,23 +4464,23 @@
     SCOPED_TRACE(testing::Message() << " Testing case 7.");
 
     // Create a new window with URL set to a javascript: URL that replaces the
-    // document, which will not create a NavigationEntry.
+    // document, which will stay on the initial NavigationEntry.
     Shell* new_shell = OpenWindow(contents(), GURL("javascript:'foo'"));
     WebContentsImpl* new_contents =
         static_cast<WebContentsImpl*>(new_shell->web_contents());
     NavigationControllerImpl& controller = new_contents->GetController();
-    EXPECT_EQ(0, controller.GetEntryCount());
-    EXPECT_FALSE(controller.GetLastCommittedEntry());
+    EXPECT_EQ(1, controller.GetEntryCount());
+    EXPECT_TRUE(controller.GetLastCommittedEntry()->IsInitialEntry());
 
     // The window should be on its initial empty document.
     FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
     EXPECT_TRUE(new_root->is_on_initial_empty_document());
 
     // Navigating the window to |url_2| will be classified as NEW_ENTRY and will
-    // add a new entry.
-    NavigateWindowAndCheckNavigationTypeIsNewEntry(new_contents, url_2);
+    // replace the initial entry.
+    NavigateWindowAndCheck(new_contents, url_2);
     EXPECT_EQ(1, controller.GetEntryCount());
-    EXPECT_TRUE(controller.GetLastCommittedEntry());
+    EXPECT_FALSE(controller.GetLastCommittedEntry()->IsInitialEntry());
 
     // The window is no longer on the initial empty document.
     EXPECT_FALSE(new_root->is_on_initial_empty_document());
@@ -4462,14 +4494,14 @@
   GURL main_window_url(embedded_test_server()->GetURL("/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), main_window_url));
 
-  // Create a new blank window that won't create a NavigationEntry.
+  // Create a new blank window that will stay on the initial NavigationEntry.
   Shell* new_shell = OpenBlankWindow(contents());
   WebContentsImpl* new_contents =
       static_cast<WebContentsImpl*>(new_shell->web_contents());
   NavigationControllerImpl& controller = new_contents->GetController();
   FrameTreeNode* root = new_contents->GetPrimaryFrameTree().root();
-  EXPECT_EQ(0, controller.GetEntryCount());
-  EXPECT_FALSE(controller.GetLastCommittedEntry());
+  EXPECT_EQ(1, controller.GetEntryCount());
+  EXPECT_TRUE(controller.GetLastCommittedEntry());
 
   {
     // Do a same-document navigation.
@@ -4491,6 +4523,186 @@
   }
 }
 
+// Tests that the initial NavigationEntry retains its "initial" status on
+// session restore and subframe navigation.
+IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
+                       InitialNavigationEntryRetainsStatus) {
+  GURL main_window_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_window_url));
+
+  // Pop open a new window which won't commit a navigation, so it will stay at
+  // the initial NavigationEntry.
+  GURL no_commit_url(embedded_test_server()->GetURL("/page204.html"));
+  Shell* new_shell = OpenWindow(contents(), no_commit_url);
+  WebContentsImpl* new_contents =
+      static_cast<WebContentsImpl*>(new_shell->web_contents());
+  // Stop the navigation so that it won't affect future navigations.
+  new_contents->Stop();
+  NavigationControllerImpl& controller = new_contents->GetController();
+  NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
+  EXPECT_TRUE(last_entry->IsInitialEntry());
+
+  GURL subframe_url(embedded_test_server()->GetURL("/title2.html"));
+  {
+    // Create a subframe and navigate it to `subframe_url`.
+    CreateSubframe(new_contents, "child_frame", subframe_url,
+                   true /* wait_for_navigation */);
+
+    // The initial NavigationEntry keeps its "initial" status even when a
+    // subframe navigated and added a FrameNavigationEntry inside the initial
+    // NavigationEntry.
+    EXPECT_EQ(last_entry, controller.GetLastCommittedEntry());
+    EXPECT_TRUE(last_entry->IsInitialEntry());
+    ASSERT_EQ(1U, last_entry->root_node()->children.size());
+    scoped_refptr<FrameNavigationEntry> frame_entry =
+        last_entry->root_node()->children[0]->frame_entry.get();
+    EXPECT_EQ(subframe_url, frame_entry->url());
+  }
+
+  FrameTreeNode* root = new_contents->GetPrimaryFrameTree().root();
+  FrameTreeNode* child = root->child_at(0);
+  {
+    // Reload the subframe.
+    FrameNavigateParamsCapturer capturer(child);
+    child->current_frame_host()->Reload();
+    capturer.Wait();
+
+    // We reused the previous NavigationEntry and it retains its "initial"
+    // status.
+    EXPECT_FALSE(capturer.did_replace_entry());
+    EXPECT_EQ(last_entry, controller.GetLastCommittedEntry());
+    EXPECT_TRUE(last_entry->IsInitialEntry());
+    scoped_refptr<FrameNavigationEntry> frame_entry =
+        last_entry->root_node()->children[0]->frame_entry.get();
+    EXPECT_EQ(subframe_url, frame_entry->url());
+  }
+
+  // Restore the initial NavigationEntry in a new tab.
+  Shell* restore_shell = Shell::CreateNewWindow(
+      controller.GetBrowserContext(), GURL::EmptyGURL(), nullptr, gfx::Size());
+  NavigationControllerImpl& restore_controller =
+      static_cast<NavigationControllerImpl&>(
+          restore_shell->web_contents()->GetController());
+  restore_controller.CopyStateFrom(&controller, false /* needs_reload */);
+
+  EXPECT_EQ(1, restore_controller.GetEntryCount());
+  EXPECT_EQ(0, restore_controller.GetLastCommittedEntryIndex());
+  NavigationEntryImpl* restored_entry =
+      restore_controller.GetLastCommittedEntry();
+
+  // The entry keep its "initial" status, and retain its FrameNavigationEntries.
+  EXPECT_TRUE(restored_entry->IsInitialEntry());
+  EXPECT_EQ(GURL::EmptyGURL(), restored_entry->root_node()->frame_entry->url());
+  ASSERT_EQ(1U, restored_entry->root_node()->children.size());
+  EXPECT_EQ(subframe_url,
+            restored_entry->root_node()->children[0]->frame_entry->url());
+}
+
+// Tests that the initial NavigationEntry loses its "initial" status when
+// any navigation commits on the main frame, including navigations where the
+// initial NavigationEntry is reused.
+IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
+                       InitialNavigationEntryLosesStatus) {
+  GURL main_window_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_window_url));
+
+  {
+    // Pop open a new window which won't commit a navigation, so it will stay at
+    // the initial NavigationEntry.
+    GURL no_commit_url(embedded_test_server()->GetURL("/page204.html"));
+    Shell* new_shell = OpenWindow(contents(), no_commit_url);
+    WebContentsImpl* new_contents =
+        static_cast<WebContentsImpl*>(new_shell->web_contents());
+    // Stop the navigation so that it won't affect future navigations.
+    new_contents->Stop();
+    NavigationControllerImpl& controller = new_contents->GetController();
+    NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
+    EXPECT_TRUE(last_entry->IsInitialEntry());
+    EXPECT_EQ(GURL::EmptyGURL(), last_entry->GetURL());
+
+    // Navigate it to another URL.
+    EXPECT_TRUE(NavigateToURL(new_contents, main_window_url));
+
+    // We replaced the previous NavigationEntry and it's no longer on the
+    // initial NavigationEntry.
+    EXPECT_NE(last_entry, controller.GetLastCommittedEntry());
+    last_entry = controller.GetLastCommittedEntry();
+    EXPECT_FALSE(last_entry->IsInitialEntry());
+    EXPECT_EQ(main_window_url, last_entry->GetURL());
+  }
+
+  {
+    // Pop open a new window with window.open(), which will stay at the initial
+    // NavigationEntry.
+    Shell* new_shell = OpenBlankWindow(contents());
+    WebContentsImpl* new_contents =
+        static_cast<WebContentsImpl*>(new_shell->web_contents());
+    // Stop the navigation so that it won't affect future navigations.
+    new_contents->Stop();
+    NavigationControllerImpl& controller = new_contents->GetController();
+    NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
+    EXPECT_TRUE(last_entry->IsInitialEntry());
+    EXPECT_EQ(GURL::EmptyGURL(), last_entry->GetURL());
+
+    // Reload it.
+    FrameTreeNode* root = new_contents->GetPrimaryFrameTree().root();
+    FrameNavigateParamsCapturer capturer(root);
+    controller.Reload(ReloadType::NORMAL, false /* check_for_repost */);
+    capturer.Wait();
+
+    // We reused the previous NavigationEntry, but it loses its "initial"
+    // status.
+    EXPECT_EQ(last_entry, controller.GetLastCommittedEntry());
+    EXPECT_FALSE(last_entry->IsInitialEntry());
+    EXPECT_EQ(GURL("about:blank"), last_entry->GetURL());
+  }
+
+  {
+    // Pop open a new window which won't commit a navigation, so it will stay at
+    // the initial NavigationEntry.
+    GURL no_commit_url(embedded_test_server()->GetURL("/page204.html"));
+    Shell* new_shell = OpenWindow(contents(), no_commit_url);
+    WebContentsImpl* new_contents =
+        static_cast<WebContentsImpl*>(new_shell->web_contents());
+    // Stop the navigation so that it won't affect future navigations.
+    new_contents->Stop();
+    NavigationControllerImpl& controller = new_contents->GetController();
+    NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
+    EXPECT_TRUE(last_entry->IsInitialEntry());
+    EXPECT_EQ(GURL::EmptyGURL(), last_entry->GetURL());
+
+    // Create a subframe and navigate it to `subframe_url`.
+    GURL subframe_url(embedded_test_server()->GetURL("/title1.html"));
+    CreateSubframe(new_contents, "child_frame", subframe_url,
+                   true /* wait_for_navigation */);
+    // Navigate the subframe to another URL.
+    FrameTreeNode* child =
+        new_contents->GetPrimaryFrameTree().root()->child_at(0);
+
+    // The initial NavigationEntry keeps its "initial" status even when a
+    // subframe navigated and added a FrameNavigationEntry inside the initial
+    // NavigationEntry.
+    EXPECT_EQ(last_entry, controller.GetLastCommittedEntry());
+    EXPECT_TRUE(last_entry->IsInitialEntry());
+    EXPECT_EQ(GURL::EmptyGURL(), last_entry->GetURL());
+    EXPECT_EQ(subframe_url, child->current_url());
+
+    // Navigate the subframe to another URL.
+    FrameNavigateParamsCapturer capturer(child);
+    GURL subframe_url_2(embedded_test_server()->GetURL("/title2.html"));
+    NavigateFrameToURL(child, subframe_url_2);
+    capturer.Wait();
+
+    // The subframe creates a new NavigationEntry, which replaces the initial
+    // NavigationEntry.
+    EXPECT_NE(last_entry, controller.GetLastCommittedEntry());
+    last_entry = controller.GetLastCommittedEntry();
+    EXPECT_FALSE(last_entry->IsInitialEntry());
+    EXPECT_EQ(GURL::EmptyGURL(), last_entry->GetURL());
+    EXPECT_EQ(subframe_url_2, child->current_url());
+  }
+}
+
 // Tests that reloading a synchronously loaded about:blank document (whose load
 // is triggered by browsing context creation) won't crash.
 IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
@@ -4498,37 +4710,37 @@
   GURL main_window_url(embedded_test_server()->GetURL("/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), main_window_url));
 
-  // Create a new blank window that won't create a NavigationEntry. This will
-  // trigger a synchronous load to about:blank.
+  // Create a new blank window. This will trigger a synchronous load to
+  // about:blank.
   Shell* new_shell = OpenBlankWindow(contents());
   WebContentsImpl* new_contents =
       static_cast<WebContentsImpl*>(new_shell->web_contents());
   NavigationControllerImpl& controller = new_contents->GetController();
   FrameTreeNode* root = new_contents->GetPrimaryFrameTree().root();
-  EXPECT_EQ(0, controller.GetEntryCount());
-  EXPECT_FALSE(controller.GetLastCommittedEntry());
+  EXPECT_EQ(1, controller.GetEntryCount());
+  EXPECT_TRUE(controller.GetLastCommittedEntry()->IsInitialEntry());
 
   {
-    // Reload the tab. The navigation will be ignored by the browser because
-    // there is no NavigationEntry for it.
-    // TODO(https://crbug.com/524208): Fix this.
-    NoNavigationsObserver observer(new_contents);
+    // Reload the tab.
+    FrameNavigateParamsCapturer capturer(root);
     controller.Reload(ReloadType::NORMAL, false /* check_for_repost */);
-    // Check that the renderer is still alive and no NavigationEntry is added.
-    EXPECT_TRUE(ExecJs(new_shell, "true"));
-    EXPECT_EQ(0, controller.GetEntryCount());
+    capturer.Wait();
+    // Check that the renderer is still alive and the NavigationEntry is no
+    // longer the initial NavigationEntry.
+    EXPECT_EQ(1, controller.GetEntryCount());
+    EXPECT_FALSE(controller.GetLastCommittedEntry()->IsInitialEntry());
   }
 
   {
-    // Reload the tab, bypassing the cache. The navigation will be ignored by
-    // the browser because there is no NavigationEntry for it.
-    // TODO(https://crbug.com/524208): Fix this.
-    NoNavigationsObserver observer(new_contents);
+    // Reload the tab, bypassing the cache.
+    FrameNavigateParamsCapturer capturer(root);
     controller.Reload(ReloadType::BYPASSING_CACHE,
                       false /* check_for_repost */);
-    // Check that the renderer is still alive and no NavigationEntry is added.
-    EXPECT_TRUE(ExecJs(new_shell, "true"));
-    EXPECT_EQ(0, controller.GetEntryCount());
+    capturer.Wait();
+    // Check that the renderer is still alive and the NavigationEntry is no
+    // longer the initial NavigationEntry.
+    EXPECT_EQ(1, controller.GetEntryCount());
+    EXPECT_FALSE(controller.GetLastCommittedEntry()->IsInitialEntry());
   }
 
   // Navigate the tab to a page that has an about:blank iframe, which will load
@@ -4536,7 +4748,7 @@
   GURL url_with_synchronous_blank_iframe(embedded_test_server()->GetURL(
       "/navigation_controller/page_with_iframe.html"));
   EXPECT_TRUE(NavigateToURL(new_shell, url_with_synchronous_blank_iframe));
-  EXPECT_EQ(1, controller.GetEntryCount());
+  EXPECT_EQ(2, controller.GetEntryCount());
 
   {
     // Reload the tab. This also reloads the iframe and re-triggers the
@@ -4552,7 +4764,7 @@
     // added.
     EXPECT_TRUE(ExecJs(new_shell, "true"));
     EXPECT_TRUE(ExecJs(root->child_at(0), "true"));
-    EXPECT_EQ(1, controller.GetEntryCount());
+    EXPECT_EQ(2, controller.GetEntryCount());
   }
   {
     // Reload the tab, bypassing the cache. This also reloads the iframe and
@@ -4569,7 +4781,7 @@
     // added.
     EXPECT_TRUE(ExecJs(new_shell, "true"));
     EXPECT_TRUE(ExecJs(root->child_at(0), "true"));
-    EXPECT_EQ(1, controller.GetEntryCount());
+    EXPECT_EQ(2, controller.GetEntryCount());
   }
 }
 
@@ -12974,8 +13186,6 @@
   EXPECT_TRUE(ExecJs(root, "var w = window.open()"));
   Shell* new_shell = new_shell_observer.GetShell();
   ASSERT_NE(new_shell->web_contents(), shell()->web_contents());
-  EXPECT_FALSE(
-      new_shell->web_contents()->GetController().GetLastCommittedEntry());
 
   // Navigate it to a cross-site URL that redirects to a data: URL.  Since it is
   // an unsafe redirect, it will result in a blocked navigation and error page.
diff --git a/content/browser/renderer_host/navigation_controller_impl_unittest.cc b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
index e8d120e..7b7feb1 100644
--- a/content/browser/renderer_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
@@ -365,11 +365,11 @@
   NavigationControllerImpl& controller = controller_impl();
 
   EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_FALSE(controller.GetVisibleEntry());
-  EXPECT_FALSE(controller.GetLastCommittedEntry());
+  EXPECT_TRUE(controller.GetVisibleEntry()->IsInitialEntry());
+  EXPECT_TRUE(controller.GetLastCommittedEntry()->IsInitialEntry());
   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
-  EXPECT_EQ(controller.GetEntryCount(), 0);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
+  EXPECT_EQ(controller.GetEntryCount(), 1);
   EXPECT_FALSE(controller.CanGoBack());
   EXPECT_FALSE(controller.CanGoForward());
 }
@@ -459,10 +459,10 @@
   EXPECT_EQ(0U, navigation_list_pruned_counter_);
 
   // The load should now be pending.
-  EXPECT_EQ(controller.GetEntryCount(), 0);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
+  EXPECT_EQ(controller.GetEntryCount(), 1);
+  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_FALSE(controller.GetLastCommittedEntry());
+  EXPECT_TRUE(controller.GetLastCommittedEntry()->IsInitialEntry());
   ASSERT_TRUE(controller.GetPendingEntry());
   EXPECT_EQ(controller.GetPendingEntry(), controller.GetVisibleEntry());
   EXPECT_FALSE(controller.CanGoBack());
@@ -486,9 +486,9 @@
   EXPECT_EQ(controller.GetEntryCount(), 1);
   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetLastCommittedEntry()->IsInitialEntry());
   EXPECT_FALSE(controller.GetPendingEntry());
-  ASSERT_TRUE(controller.GetVisibleEntry());
+  ASSERT_FALSE(controller.GetVisibleEntry()->IsInitialEntry());
   EXPECT_FALSE(controller.CanGoBack());
   EXPECT_FALSE(controller.CanGoForward());
   EXPECT_EQ(0, controller.GetLastCommittedEntry()
@@ -512,7 +512,7 @@
   EXPECT_EQ(controller.GetEntryCount(), 1);
   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetLastCommittedEntry()->IsInitialEntry());
   ASSERT_TRUE(controller.GetPendingEntry());
   EXPECT_EQ(controller.GetPendingEntry(), controller.GetVisibleEntry());
   // TODO(darin): maybe this should really be true?
@@ -531,9 +531,9 @@
   EXPECT_EQ(controller.GetEntryCount(), 2);
   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
-  EXPECT_TRUE(controller.GetLastCommittedEntry());
+  EXPECT_FALSE(controller.GetLastCommittedEntry()->IsInitialEntry());
   EXPECT_FALSE(controller.GetPendingEntry());
-  ASSERT_TRUE(controller.GetVisibleEntry());
+  ASSERT_FALSE(controller.GetVisibleEntry()->IsInitialEntry());
   EXPECT_TRUE(controller.CanGoBack());
   EXPECT_FALSE(controller.CanGoForward());
 
@@ -1062,7 +1062,7 @@
   EXPECT_EQ(0U, navigation_list_pruned_counter_);
   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   EXPECT_TRUE(controller.GetPendingEntry());
-  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   EXPECT_EQ(1, delegate->navigation_state_change_count());
 
   // Certain rare cases can make a direct DidCommitProvisionalLoad call without
@@ -1073,8 +1073,10 @@
   // change, so that we do not keep displaying kNewURL.
   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   EXPECT_FALSE(controller.GetPendingEntry());
-  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
-  EXPECT_EQ(2, delegate->navigation_state_change_count());
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+  // The pending entry deletion and commit of the new NavigationEntry both
+  // counts as "navigation state change".
+  EXPECT_EQ(3, delegate->navigation_state_change_count());
 
   contents()->SetDelegate(nullptr);
 }
@@ -1101,7 +1103,7 @@
   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   EXPECT_TRUE(controller.GetPendingEntry());
   EXPECT_EQ(kNewURL, controller.GetPendingEntry()->GetURL());
-  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   EXPECT_EQ(1, delegate->navigation_state_change_count());
 
   // It may abort before committing, if it's a download or due to a stop or
@@ -1113,7 +1115,7 @@
   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   EXPECT_TRUE(controller.GetPendingEntry());
   EXPECT_EQ(kNewURL, controller.GetPendingEntry()->GetURL());
-  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   EXPECT_EQ(2, delegate->navigation_state_change_count());
   NavigationEntry* pending_entry = controller.GetPendingEntry();
 
@@ -1123,7 +1125,7 @@
   EXPECT_TRUE(controller.GetPendingEntry());
   EXPECT_EQ(kNewURL, controller.GetPendingEntry()->GetURL());
   EXPECT_EQ(pending_entry, controller.GetPendingEntry());
-  EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
 
   contents()->SetDelegate(nullptr);
 }
@@ -2255,8 +2257,8 @@
   EXPECT_EQ(1, controller.GetEntryCount());
 }
 
-TEST_F(NavigationControllerTest, PushStateWithoutPreviousEntry) {
-  ASSERT_FALSE(controller_impl().GetLastCommittedEntry());
+TEST_F(NavigationControllerTest, PushStateWithOnlyInitialEntry) {
+  ASSERT_TRUE(controller_impl().GetLastCommittedEntry()->IsInitialEntry());
   GURL url("http://foo");
   auto params = mojom::DidCommitProvisionalLoadParams::New();
   params->did_create_new_entry = true;
@@ -2671,7 +2673,7 @@
   // we must revert to showing about:blank to avoid a URL spoof.
   main_test_rfh()->DidAccessInitialMainDocument();
   EXPECT_TRUE(contents()->HasAccessedInitialDocument());
-  EXPECT_FALSE(controller.GetVisibleEntry());
+  EXPECT_TRUE(controller.GetVisibleEntry()->IsInitialEntry());
   EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
 }
 
@@ -2715,7 +2717,7 @@
   // we must revert to showing about:blank to avoid a URL spoof.
   main_test_rfh()->DidAccessInitialMainDocument();
   EXPECT_TRUE(contents()->HasAccessedInitialDocument());
-  EXPECT_FALSE(controller.GetVisibleEntry());
+  EXPECT_TRUE(controller.GetVisibleEntry()->IsInitialEntry());
   EXPECT_FALSE(controller.GetPendingEntry());
 }
 
@@ -2753,7 +2755,7 @@
   // we must revert to showing about:blank to avoid a URL spoof.
   main_test_rfh()->DidAccessInitialMainDocument();
   EXPECT_TRUE(contents()->HasAccessedInitialDocument());
-  EXPECT_FALSE(controller.GetVisibleEntry());
+  EXPECT_TRUE(controller.GetVisibleEntry()->IsInitialEntry());
   EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
 }
 
@@ -2793,7 +2795,7 @@
   // show this page anymore.
   main_test_rfh()->DidAccessInitialMainDocument();
   EXPECT_TRUE(contents()->HasAccessedInitialDocument());
-  EXPECT_FALSE(controller.GetVisibleEntry());
+  EXPECT_TRUE(controller.GetVisibleEntry()->IsInitialEntry());
   EXPECT_FALSE(controller.GetPendingEntry());
 }
 
@@ -2958,11 +2960,11 @@
       ui::PAGE_TRANSITION_RELOAD));
 }
 
-// Test requesting and triggering a lazy reload without any committed entry nor
-// pending entry.
-TEST_F(NavigationControllerTest, LazyReloadWithoutCommittedEntry) {
+// Test requesting and triggering a lazy reload when there's only the initial
+// entry.
+TEST_F(NavigationControllerTest, LazyReloadWithOnlyInitialEntry) {
   NavigationControllerImpl& controller = controller_impl();
-  ASSERT_EQ(-1, controller.GetLastCommittedEntryIndex());
+  ASSERT_TRUE(controller.GetLastCommittedEntry()->IsInitialEntry());
   EXPECT_FALSE(controller.NeedsReload());
   controller.SetNeedsReload();
   EXPECT_TRUE(controller.NeedsReload());
@@ -2972,9 +2974,9 @@
   ASSERT_FALSE(controller.NeedsReload());
 }
 
-// Test requesting and triggering a lazy reload without any committed entry and
-// only a pending entry.
-TEST_F(NavigationControllerTest, LazyReloadWithOnlyPendingEntry) {
+// Test requesting and triggering a lazy reload when there's only the initial
+// entry and a pending entry.
+TEST_F(NavigationControllerTest, LazyReloadWithOnlyInitialAndPendingEntry) {
   NavigationControllerImpl& controller = controller_impl();
   const GURL url("http://foo");
   controller.LoadURL(url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
@@ -4275,10 +4277,10 @@
 }
 
 // Test that if an empty WebContents is navigated via frame proxy with
-// replacement, the NavigationRequest does not specify replacement, since there
-// is no entry to replace.
+// replacement, the NavigationRequest does specifies replacement, to replace the
+// initial entry.
 TEST_F(NavigationControllerTest,
-       NavigateFromFrameProxyWithReplacementWithoutEntries) {
+       NavigateFromFrameProxyWithReplacementWithOnlyInitialEntry) {
   const GURL main_url("http://foo1");
   const GURL other_contents_url("http://foo2");
   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), main_url);
@@ -4293,8 +4295,9 @@
   FrameTreeNode* node = other_contents_impl->GetPrimaryFrameTree().root();
   RenderFrameHostImpl* frame = node->current_frame_host();
 
-  // The newly created contents has no entries.
-  EXPECT_EQ(0, other_controller.GetEntryCount());
+  // The newly created contents has 1 entry, the initial entry.
+  EXPECT_EQ(1, other_controller.GetEntryCount());
+  EXPECT_TRUE(other_controller.GetLastCommittedEntry()->IsInitialEntry());
 
   // Simulate the main WebContents navigating the new WebContents with
   // replacement.
@@ -4310,9 +4313,8 @@
   NavigationRequest* request = node->navigation_request();
   ASSERT_TRUE(request);
 
-  // Since the new WebContents had no entries, the request is not done with
-  // replacement.
-  EXPECT_FALSE(request->common_params().should_replace_current_entry);
+  // The request was done with replacement.
+  EXPECT_TRUE(request->common_params().should_replace_current_entry);
 }
 
 // Tests that calling RemoveForwareEntries() clears all forward entries
diff --git a/content/browser/renderer_host/navigation_entry_impl.cc b/content/browser/renderer_host/navigation_entry_impl.cc
index 9bc9572..7f7a610 100644
--- a/content/browser/renderer_host/navigation_entry_impl.cc
+++ b/content/browser/renderer_host/navigation_entry_impl.cc
@@ -360,7 +360,8 @@
                           std::u16string(),
                           ui::PAGE_TRANSITION_LINK,
                           false,
-                          nullptr) {}
+                          nullptr,
+                          /* is_initial_entry = */ false) {}
 
 NavigationEntryImpl::NavigationEntryImpl(
     scoped_refptr<SiteInstanceImpl> instance,
@@ -370,7 +371,8 @@
     const std::u16string& title,
     ui::PageTransition transition_type,
     bool is_renderer_initiated,
-    scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory)
+    scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
+    bool is_initial_entry)
     : frame_tree_(std::make_unique<TreeNode>(
           nullptr,
           base::MakeRefCounted<FrameNavigationEntry>(
@@ -408,7 +410,8 @@
       reload_type_(ReloadType::NONE),
       started_from_context_menu_(false),
       ssl_error_(false),
-      should_skip_on_back_forward_ui_(false) {}
+      should_skip_on_back_forward_ui_(false),
+      is_initial_entry_(is_initial_entry) {}
 
 NavigationEntryImpl::~NavigationEntryImpl() {}
 
@@ -715,9 +718,18 @@
   return can_load_local_resources_;
 }
 
+bool NavigationEntryImpl::IsInitialEntry() {
+  return is_initial_entry_;
+}
+
 std::unique_ptr<NavigationEntryImpl> NavigationEntryImpl::Clone() const {
-  return CloneAndReplaceInternal(nullptr, false, nullptr, nullptr, nullptr,
-                                 ClonePolicy::kShareFrameEntries);
+  std::unique_ptr<NavigationEntryImpl> entry =
+      CloneAndReplaceInternal(nullptr, false, nullptr, nullptr, nullptr,
+                              ClonePolicy::kShareFrameEntries);
+  // When we are not deep-copying, the NavigationEntry is going to be used for
+  // a new committed navigation, so it loses its "initial" status.
+  entry->set_is_initial_entry(false);
+  return entry;
 }
 
 std::unique_ptr<NavigationEntryImpl> NavigationEntryImpl::CloneWithoutSharing(
@@ -733,9 +745,13 @@
     bool clone_children_of_target,
     FrameTreeNode* target_frame_tree_node,
     FrameTreeNode* root_frame_tree_node) const {
-  return CloneAndReplaceInternal(
+  std::unique_ptr<NavigationEntryImpl> entry = CloneAndReplaceInternal(
       frame_navigation_entry, clone_children_of_target, target_frame_tree_node,
       root_frame_tree_node, nullptr, ClonePolicy::kShareFrameEntries);
+  // When we are not deep-copying, the NavigationEntry is going to be used for
+  // a new committed navigation, so it loses its "initial" status.
+  entry->set_is_initial_entry(false);
+  return entry;
 }
 
 std::unique_ptr<NavigationEntryImpl>
@@ -784,6 +800,7 @@
   copy->CloneDataFrom(*this);
   copy->replaced_entry_data_ = replaced_entry_data_;
   copy->should_skip_on_back_forward_ui_ = should_skip_on_back_forward_ui_;
+  copy->is_initial_entry_ = is_initial_entry_;
 
   return copy;
 }
@@ -977,6 +994,18 @@
         document_sequence_number)
       root_node()->children.clear();
 
+    if (!url.is_empty()) {
+      // A navigation committed on the main frame, so the NavigationEntry loses
+      // its "initial NavigationEntry" status. Note that the initial entry
+      // creation path also goes through this function, but we know not to
+      // remove the status in that case because it uses the empty URL.
+      // TODO(https://crbug.com/1215096): Consider to remove the initial entry
+      // status after subframe navigations too, when the initial empty document
+      // replacement behavior is more consistent, and we've determined that
+      // exposing more history entries to WebView is OK.
+      is_initial_entry_ = false;
+    }
+
     root_node()->frame_entry->UpdateEntry(
         frame_tree_node->unique_name(), item_sequence_number,
         document_sequence_number, app_history_key, site_instance,
diff --git a/content/browser/renderer_host/navigation_entry_impl.h b/content/browser/renderer_host/navigation_entry_impl.h
index c7c5748..5653ee8 100644
--- a/content/browser/renderer_host/navigation_entry_impl.h
+++ b/content/browser/renderer_host/navigation_entry_impl.h
@@ -108,7 +108,8 @@
       const std::u16string& title,
       ui::PageTransition transition_type,
       bool is_renderer_initiated,
-      scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory);
+      scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
+      bool is_initial_entry);
 
   NavigationEntryImpl(const NavigationEntryImpl&) = delete;
   NavigationEntryImpl& operator=(const NavigationEntryImpl&) = delete;
@@ -116,6 +117,7 @@
   ~NavigationEntryImpl() override;
 
   // NavigationEntry implementation:
+  bool IsInitialEntry() override;
   int GetUniqueID() override;
   PageType GetPageType() override;
   void SetURL(const GURL& url) override;
@@ -428,6 +430,10 @@
     back_forward_cache_metrics_ = metrics;
   }
 
+  void set_is_initial_entry(bool is_initial_entry) {
+    is_initial_entry_ = is_initial_entry;
+  }
+
  private:
   std::unique_ptr<NavigationEntryImpl> CloneAndReplaceInternal(
       scoped_refptr<FrameNavigationEntry> frame_entry,
@@ -557,6 +563,19 @@
   // with implement back-forward cache.
   // It is preserved at commit but not persisted.
   scoped_refptr<BackForwardCacheMetrics> back_forward_cache_metrics_;
+
+  // Whether this NavigationEntry is the initial NavigationEntry or not. The
+  // initial NavigationEntry is created when the FrameTree is created, so it is
+  // not really associated with any navigation, but represents a placeholder
+  // NavigationEntry for the "initial empty document", which commits in the
+  // renderer on frame creation but doesn't notify the browser of the commit.
+  // The initial NavigationEntry gets replaced or loses its "initial" status on
+  // the next navigation on the main frame, even if the frame stays on the
+  // initial empty document (e.g. same-document navigation on the initial empty
+  // document). The initial NavigationEntry also never gets restored on session
+  // restore, because we never restore tabs with only the initial
+  // NavigationEntry.
+  bool is_initial_entry_ = false;
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/navigation_entry_impl_unittest.cc b/content/browser/renderer_host/navigation_entry_impl_unittest.cc
index a1513a93..db902bc 100644
--- a/content/browser/renderer_host/navigation_entry_impl_unittest.cc
+++ b/content/browser/renderer_host/navigation_entry_impl_unittest.cc
@@ -53,7 +53,7 @@
         instance_, GURL("test:url"),
         Referrer(GURL("from"), network::mojom::ReferrerPolicy::kDefault),
         kInitiatorOrigin, u"title", ui::PAGE_TRANSITION_TYPED, false,
-        nullptr /* blob_url_loader_factory */);
+        nullptr /* blob_url_loader_factory */, false /* is_initial_entry */);
   }
 
   void TearDown() override {}
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 60e901c..eea70788 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -860,7 +860,7 @@
   int pending_index = controller.GetPendingEntryIndex();
 
   // +1 for non history navigation.
-  if (current_index == -1 || pending_index == -1)
+  if (pending_index == -1)
     return 1;
 
   return pending_index - current_index;
@@ -2076,10 +2076,13 @@
         common_params_->url, *common_params_->referrer);
   }
 
-  if (ShouldReplaceCurrentEntryForSameUrlNavigation())
-    common_params_->should_replace_current_entry = true;
-
-  if (ShouldReplaceCurrentEntryForNavigationFromInitialEmptyDocument()) {
+  // If the navigation explicitly requested for history list clearing (e.g. when
+  // running layout tests), don't do a replacement (since there won't be any
+  // entry to replace after the navigation).
+  if (commit_params_->should_clear_history_list) {
+    common_params_->should_replace_current_entry = false;
+  } else if (ShouldReplaceCurrentEntryForSameUrlNavigation() ||
+             ShouldReplaceCurrentEntryForNavigationFromInitialEmptyDocument()) {
     common_params_->should_replace_current_entry = true;
   }
 
@@ -6956,6 +6959,8 @@
 // https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigating-across-documents:hh-replace
 bool NavigationRequest::ShouldReplaceCurrentEntryForSameUrlNavigation() const {
   DCHECK_LE(state_, WILL_START_NAVIGATION);
+  DCHECK_GE(frame_tree_node_->navigator().controller().GetEntryCount(), 1);
+
   // Not a same-url navigation. Note that this is comparing against the "last
   // loading URL" since this is what was used in the renderer check that was
   // moved here. This means for error pages we should compare against the URL
@@ -6978,9 +6983,6 @@
     return false;
   }
 
-  // Never replace if there is no NavigationEntry to replace.
-  if (!frame_tree_node_->navigator().controller().GetEntryCount())
-    return false;
   // Reloads and history navigations have special handling and don't need to
   // set |common_params_->should_replace_current_entry|.
   if (common_params_->navigation_type !=
@@ -7011,22 +7013,6 @@
 bool NavigationRequest::
     ShouldReplaceCurrentEntryForNavigationFromInitialEmptyDocument() const {
   DCHECK_LE(state_, WILL_START_NAVIGATION);
-
-  // Never replace if there is no NavigationEntry to replace.
-  if (!frame_tree_node_->navigator().controller().GetEntryCount())
-    return false;
-
-  if (IsInMainFrame()) {
-    // Currently we only handle subframe initial empty document replacements.
-    // TODO(https://crbug.com/1215096): Handle main frame navigations too.
-    return false;
-  }
-
-  if (!frame_tree_node_->is_on_initial_empty_document()) {
-    // Return if we're not on the initial empty document.
-    return false;
-  }
-
   if (common_params_->navigation_type !=
           blink::mojom::NavigationType::SAME_DOCUMENT &&
       common_params_->navigation_type !=
@@ -7036,22 +7022,30 @@
     return false;
   }
 
-  // If the navigation explicitly requested for history list clearing (e.g. when
-  // running layout tests), don't do a replacement (since there won't be any
-  // entry to replace after the navigation).
-  return !commit_params_->should_clear_history_list;
+  if (!frame_tree_node_->is_on_initial_empty_document()) {
+    // Return if we're not on the initial empty document.
+    return false;
+  }
+
+  if (IsInMainFrame()) {
+    // We don't currently do initial empty document replacement on main frames,
+    // but we always replace the initial NavigationEntry on the next navigation
+    // on the main frame.
+    return frame_tree_node_->navigator()
+        .controller()
+        .GetLastCommittedEntry()
+        ->IsInitialEntry();
+  }
+  return true;
 }
 
 bool NavigationRequest::ShouldReplaceCurrentEntryForFailedNavigation() const {
   DCHECK(state_ == CANCELING || state_ == WILL_FAIL_REQUEST);
+  DCHECK_GE(frame_tree_node_->navigator().controller().GetEntryCount(), 1);
 
   if (common_params_->should_replace_current_entry)
     return true;
 
-  // Never replace if there is no NavigationEntry to replace.
-  if (!frame_tree_node_->navigator().controller().GetEntryCount())
-    return false;
-
   auto page_state =
       blink::PageState::CreateFromEncodedData(commit_params_->page_state);
   // Failed history navigations with valid PageState should not do replacement.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 7085955c..a062f4c 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -6725,16 +6725,6 @@
 
   RenderFrameHostImpl* new_main_rfh =
       new_frame_tree->root()->current_frame_host();
-
-  // When the popup is created, it hasn't committed any navigation yet - its
-  // initial empty document should inherit the origin of its opener (the origin
-  // may change after the first commit). See also https://crbug.com/932067.
-  //
-  // Note that that origin of the new frame might depend on sandbox flags.
-  // Checking sandbox flags of the new frame should be safe at this point,
-  // because the flags should be already inherited by the CreateNewWindow call
-  // above.
-  new_main_rfh->SetOriginDependentStateOfNewFrame(GetLastCommittedOrigin());
   new_main_rfh->cross_origin_embedder_policy_ = popup_coep;
 
   new_main_rfh->virtual_browsing_context_group_ =
@@ -8666,6 +8656,16 @@
     return;
 
   ui::AXMode ax_mode = delegate_->GetAccessibilityMode();
+
+  // Disable BackForwardCache if ScreenReader is on.
+  // TODO(crbug.com/1271450): Screen readers do not recognize a navigation when
+  // the page is served from bfcache.
+  if (ax_mode.has_mode(ui::AXMode::kScreenReader)) {
+    BackForwardCache::DisableForRenderFrameHost(
+        this, BackForwardCacheDisable::DisabledReason(
+                  BackForwardCacheDisable::DisabledReasonId::kScreenReader));
+  }
+
   if (!ax_mode.has_mode(ui::AXMode::kWebContents)) {
     // Resetting the Remote signals the renderer to shutdown accessibility
     // in the renderer.
@@ -11473,7 +11473,16 @@
   // For other navigations, the CommonNavigationParams' value supplied by the
   // browser to the renderer at commit time can be used, as the renderer will
   // always follow it.
-  return request->IsSameDocument()
+  // Note: We will always replace the initial NavigationEntry (CommonParams'
+  // should_replace_current_entry will be true) but the renderer doesn't know
+  // about it so DidCommitParams' should_replace_current_entry might differ,
+  // which is why we depend on the DidCommitParams for that case (for now).
+  return (request->IsSameDocument() ||
+          (request->IsInMainFrame() && request->frame_tree_node()
+                                           ->navigator()
+                                           .controller()
+                                           .GetLastCommittedEntry()
+                                           ->IsInitialEntry()))
              ? params.should_replace_current_entry
              : request->common_params().should_replace_current_entry;
 }
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index dbb0ff2f..bc8d5f6 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -2400,6 +2400,12 @@
   // children, or nullptr if there is no such node.
   FrameTreeNode* NextSibling() const;
 
+  // Set the |last_committed_origin_|, |isolation_info_|, and
+  // |permissions_policy_| of |this| frame, inheriting the origin from
+  // |new_frame_creator| as appropriate (e.g. depending on whether |this| frame
+  // should be sandboxed / should have an opaque origin instead).
+  void SetOriginDependentStateOfNewFrame(const url::Origin& new_frame_creator);
+
  protected:
   friend class RenderFrameHostFactory;
 
@@ -2956,12 +2962,6 @@
   // Update this frame's last committed origin.
   void SetLastCommittedOrigin(const url::Origin& origin);
 
-  // Set the |last_committed_origin_|, |isolation_info_|, and
-  // |permissions_policy_| of |this| frame, inheriting the origin from
-  // |new_frame_creator| as appropriate (e.g. depending on whether |this| frame
-  // should be sandboxed / should have an opaque origin instead).
-  void SetOriginDependentStateOfNewFrame(const url::Origin& new_frame_creator);
-
   // Called when a navigation commits successfully to |url|. This will update
   // |last_committed_site_info_| with the SiteInfo corresponding to |url|.
   // Note that this will recompute the SiteInfo from |url| rather than using
diff --git a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
index bc01ed2..4a709bb92 100644
--- a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
@@ -3004,7 +3004,8 @@
 
   // The popup navigation should be cancelled and therefore shouldn't
   // contribute an extra history entry.
-  EXPECT_EQ(0, popup->GetController().GetEntryCount());
+  EXPECT_EQ(1, popup->GetController().GetEntryCount());
+  EXPECT_TRUE(popup->GetController().GetLastCommittedEntry()->IsInitialEntry());
 }
 
 IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
@@ -3029,8 +3030,8 @@
   )";
   ExecuteScriptAsync(web_contents(), kScript);
 
-  // Wait for the new popup to be created (this will be before the popup commits
-  // the initial about:blank page).
+  // Wait for the new popup to be created (this will be before the popup finish
+  // the synchronous about:blank commit in the browser).
   WebContents* popup = popup_observer.GetWebContents();
   EXPECT_EQ(main_origin, popup->GetMainFrame()->GetLastCommittedOrigin());
   EXPECT_EQ(
@@ -3038,7 +3039,7 @@
       static_cast<RenderFrameHostImpl*>(popup->GetMainFrame())->storage_key());
 
   // A round-trip to the renderer process is an indirect way to wait for
-  // DidCommitProvisionalLoad IPC for the initial about:blank page.
+  // DidCommitProvisionalLoad IPC for the synchronous about:blank commit.
   // WaitForLoadStop cannot be used, because this commit won't raise
   // NOTIFICATION_LOAD_STOP.
   EXPECT_EQ(123, EvalJs(popup, "123"));
@@ -3047,8 +3048,10 @@
       blink::StorageKey(main_origin),
       static_cast<RenderFrameHostImpl*>(popup->GetMainFrame())->storage_key());
 
-  // The about:blank navigation shouldn't contribute an extra history entry.
-  EXPECT_EQ(0, popup->GetController().GetEntryCount());
+  // The synchronous about:blank commit should be ignored, and won't replace the
+  // initial NavigationEntry.
+  EXPECT_EQ(1, popup->GetController().GetEntryCount());
+  EXPECT_TRUE(popup->GetController().GetLastCommittedEntry()->IsInitialEntry());
 }
 
 IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index b1804a9..d7cdf5e4 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -1901,7 +1901,7 @@
   // https://crbug.com/766630.
   NavigationEntry* current_entry =
       GetNavigationController().GetLastCommittedEntry();
-  bool current_is_view_source_mode = current_entry
+  bool current_is_view_source_mode = !current_entry->IsInitialEntry()
                                          ? current_entry->IsViewSourceMode()
                                          : dest_is_view_source_mode;
 
diff --git a/content/browser/renderer_host/render_frame_host_manager_browsertest.cc b/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
index bb25c67..db775c8 100644
--- a/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
@@ -1457,8 +1457,11 @@
       shell()->web_contents()->GetSiteInstance());
   EXPECT_EQ(orig_site_instance, post_nav_site_instance);
   EXPECT_EQ("/nocontent", shell()->web_contents()->GetVisibleURL().path());
-  EXPECT_FALSE(
-      shell()->web_contents()->GetController().GetLastCommittedEntry());
+  EXPECT_TRUE(shell()
+                  ->web_contents()
+                  ->GetController()
+                  .GetLastCommittedEntry()
+                  ->IsInitialEntry());
 
   // Renderer-initiated navigations should work.
   std::u16string expected_title = u"Title Of Awesomeness";
@@ -1511,15 +1514,18 @@
   }
 };
 
-// Helper to wait until a WebContent's NavigationController has a visible entry.
+// Helper to wait until a WebContent's NavigationController has a visible entry
+// that is not the initial NavigationEntry.
 class VisibleEntryWaiter : public WebContentsObserver {
  public:
   explicit VisibleEntryWaiter(WebContents* web_contents)
       : WebContentsObserver(web_contents) {}
 
   void Wait() {
-    if (web_contents()->GetController().GetVisibleEntry())
-      return;
+    if (auto* entry = web_contents()->GetController().GetVisibleEntry()) {
+      if (!entry->IsInitialEntry())
+        return;
+    }
     run_loop_.Run();
   }
 
@@ -1632,9 +1638,9 @@
   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
 
   // At this point, we should no longer be showing the destination URL.
-  // The visible entry should be null, resulting in about:blank in the address
-  // bar.
-  EXPECT_FALSE(contents->GetController().GetVisibleEntry());
+  // The visible entry should be the initial entry, resulting in about:blank in
+  // the address bar.
+  EXPECT_TRUE(contents->GetController().GetVisibleEntry()->IsInitialEntry());
 }
 
 // Same as ShowLoadingURLUntilSpoof, but reloads the new popup before modifying
@@ -1690,9 +1696,9 @@
   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
 
   // At this point, we should no longer be showing the destination URL.
-  // The visible entry should be null, resulting in about:blank in the address
-  // bar.
-  EXPECT_FALSE(contents->GetController().GetVisibleEntry());
+  // The visible entry should be the initial entry, resulting in about:blank in
+  // the address bar.
+  EXPECT_TRUE(contents->GetController().GetVisibleEntry()->IsInitialEntry());
 }
 
 // Similar but using document.open(): once a Document is opened, subsequent
@@ -1741,9 +1747,9 @@
   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
 
   // At this point, we should no longer be showing the destination URL.
-  // The visible entry should be null, resulting in about:blank in the address
-  // bar.
-  EXPECT_FALSE(contents->GetController().GetVisibleEntry());
+  // The visible entry should be the initial entry, resulting in about:blank in
+  // the address bar.
+  EXPECT_TRUE(contents->GetController().GetVisibleEntry()->IsInitialEntry());
 }
 
 IN_PROC_BROWSER_TEST_P(RenderFrameHostManagerTest,
@@ -2177,7 +2183,9 @@
   // navigation.
   WebContents* contents = new_shell->web_contents();
   EXPECT_FALSE(contents->GetController().IsInitialNavigation());
-  EXPECT_FALSE(contents->GetController().GetVisibleEntry());
+  // The visible entry should be the initial entry, resulting in about:blank in
+  // the address bar.
+  EXPECT_TRUE(contents->GetController().GetVisibleEntry()->IsInitialEntry());
 }
 
 // Crashes under ThreadSanitizer, http://crbug.com/356758.
@@ -2191,7 +2199,8 @@
 // renderer.
 IN_PROC_BROWSER_TEST_P(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
   StartEmbeddedServer();
-  EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/empty.html")));
 
   // Visit a page on first site.
   EXPECT_TRUE(
@@ -2314,7 +2323,7 @@
       shell()->web_contents()->GetMainFrame()->GetRenderViewHost();
   SiteInstance* blank_site_instance =
       shell()->web_contents()->GetMainFrame()->GetSiteInstance();
-  EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
+  EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL());
   EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
   rvh_observers.EnsureRVHGetsDestructed(blank_rvh);
 
diff --git a/content/browser/renderer_host/render_frame_host_manager_unittest.cc b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
index 4fddb30..4bbf9e2 100644
--- a/content/browser/renderer_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
@@ -909,7 +909,8 @@
   NavigationEntryImpl entry1(
       nullptr /* instance */, kUrl1, Referrer(), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_TYPED,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   host = NavigateToEntry(manager, &entry1);
 
   // The RenderFrameHost created in Init will be reused.
@@ -934,7 +935,8 @@
       nullptr /* instance */, kUrl2,
       Referrer(kUrl1, network::mojom::ReferrerPolicy::kDefault),
       kInitiatorOrigin, std::u16string() /* title */, ui::PAGE_TRANSITION_LINK,
-      true /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      true /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   host = NavigateToEntry(manager, &entry2);
 
   // The RenderFrameHost created in Init will be reused.
@@ -957,7 +959,8 @@
       nullptr /* instance */, kUrl3,
       Referrer(kUrl2, network::mojom::ReferrerPolicy::kDefault), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_LINK,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   host = NavigateToEntry(manager, &entry3);
 
   // A new RenderFrameHost should be created.
@@ -1000,7 +1003,8 @@
   NavigationEntryImpl entry(
       nullptr /* instance */, kUrl, Referrer(), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_TYPED,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   RenderFrameHostImpl* host = NavigateToEntry(manager, &entry);
 
   // We commit the pending RenderFrameHost immediately because the previous
@@ -1051,7 +1055,8 @@
   NavigationEntryImpl entry1(
       nullptr /* instance */, kUrl1, Referrer(), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_TYPED,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   RenderFrameHostImpl* host1 = NavigateToEntry(manager1, &entry1);
 
   // We should have a pending navigation to the WebUI RenderViewHost.
@@ -1083,7 +1088,8 @@
   NavigationEntryImpl entry2(
       nullptr /* instance */, kUrl2, Referrer(), kInitiatorOrigin,
       std::u16string() /* title */, ui::PAGE_TRANSITION_LINK,
-      true /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      true /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   RenderFrameHostImpl* host2 = NavigateToEntry(manager2, &entry2);
 
   // No cross-process transition happens because we are already in the right
@@ -1462,7 +1468,8 @@
   NavigationEntryImpl entry1(
       nullptr /* instance */, kUrl1, Referrer(), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_TYPED,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   host = NavigateToEntry(manager, &entry1);
 
   // The RenderFrameHost created in Init will be reused.
@@ -1486,7 +1493,8 @@
       nullptr /* instance */, kUrl2,
       Referrer(kUrl1, network::mojom::ReferrerPolicy::kDefault),
       kInitiatorOrigin, std::u16string() /* title */, ui::PAGE_TRANSITION_LINK,
-      true /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      true /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   host = NavigateToEntry(manager, &entry2);
 
   // The RenderFrameHost created in Init will be reused.
@@ -1540,7 +1548,8 @@
   NavigationEntryImpl entry1(
       nullptr /* instance */, kUrl1, Referrer(), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_TYPED,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   RenderFrameHostImpl* host = NavigateToEntry(manager, &entry1);
 
   // The RenderFrameHost created in Init will be reused.
@@ -1563,7 +1572,8 @@
   NavigationEntryImpl entry2(
       nullptr /* instance */, kUrl2, Referrer(), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_TYPED,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   RenderFrameHostImpl* host2 = NavigateToEntry(manager, &entry2);
 
   // A new RenderFrameHost should be created.
@@ -1864,7 +1874,8 @@
   NavigationEntryImpl entryA(
       nullptr /* instance */, kUrlA, Referrer(), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_TYPED,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   RenderFrameHostImpl* host1 = NavigateToEntry(iframe1, &entryA);
 
   // The RenderFrameHost created in Init will be reused.
@@ -1883,7 +1894,8 @@
       nullptr /* instance */, kUrlB,
       Referrer(kUrlA, network::mojom::ReferrerPolicy::kDefault), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_LINK,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   host1 = NavigateToEntry(iframe1, &entryB);
   RenderFrameHostImpl* host2 = NavigateToEntry(iframe2, &entryB);
 
@@ -2019,7 +2031,8 @@
       nullptr /* instance */, kUrl2,
       Referrer(kUrl1, network::mojom::ReferrerPolicy::kDefault), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_LINK,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   RenderFrameHostImpl* cross_site = NavigateToEntry(iframe, &entry);
   DidNavigateFrame(iframe, cross_site);
 
@@ -2074,7 +2087,8 @@
   NavigationEntryImpl webui_entry(
       nullptr /* instance */, kWebUIUrl, Referrer(), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_TYPED,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   RenderFrameHostManager* main_rfhm = contents()->GetRenderManagerForTesting();
   RenderFrameHostImpl* webui_rfh = NavigateToEntry(main_rfhm, &webui_entry);
   EXPECT_EQ(webui_rfh, GetPendingFrameHost(main_rfhm));
@@ -2086,7 +2100,8 @@
   NavigationEntryImpl subframe_entry(
       nullptr /* instance */, kSubframeUrl, Referrer(), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_LINK,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   RenderFrameHostImpl* bar_rfh =
       NavigateToEntry(subframe_rfhm, &subframe_entry);
   EXPECT_FALSE(bar_rfh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
@@ -2451,7 +2466,8 @@
       nullptr /* instance */, kUrlB,
       Referrer(kUrlA, network::mojom::ReferrerPolicy::kDefault), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_LINK,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   TestRenderFrameHost* host1 =
       static_cast<TestRenderFrameHost*>(NavigateToEntry(child1, &entryB));
 
@@ -2472,7 +2488,8 @@
       nullptr /* instance */, kUrlC,
       Referrer(kUrlA, network::mojom::ReferrerPolicy::kDefault), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_LINK,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   TestRenderFrameHost* host3 =
       static_cast<TestRenderFrameHost*>(NavigateToEntry(child3, &entryC));
 
@@ -2556,7 +2573,8 @@
       nullptr /* instance */, kUrlB,
       Referrer(kUrlA, network::mojom::ReferrerPolicy::kDefault), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_LINK,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   TestRenderFrameHost* hostB =
       static_cast<TestRenderFrameHost*>(NavigateToEntry(child, &entryB));
   DidNavigateFrame(child, hostB);
@@ -2572,7 +2590,8 @@
       nullptr /* instance */, kUrlC,
       Referrer(kUrlA, network::mojom::ReferrerPolicy::kDefault), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_LINK,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   TestRenderFrameHost* hostC =
       static_cast<TestRenderFrameHost*>(NavigateToEntry(child, &entryC));
 
@@ -2624,7 +2643,8 @@
   NavigationEntryImpl entry(
       nullptr /* instance */, kInitUrl, Referrer(), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_RELOAD,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   entry.set_restore_type(RestoreType::kRestored);
   NavigateToEntry(manager, &entry);
 
@@ -2920,7 +2940,8 @@
   NavigationEntryImpl entry(
       nullptr /* instance */, kUrl, Referrer(), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_TYPED,
-      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
+      false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
   FrameNavigationEntry* frame_entry = entry.root_node()->frame_entry.get();
   FrameTreeNode* frame_tree_node =
       manager->current_frame_host()->frame_tree_node();
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc
index c730f2f..3b18222 100644
--- a/content/browser/site_instance_impl_unittest.cc
+++ b/content/browser/site_instance_impl_unittest.cc
@@ -432,7 +432,8 @@
 
   NavigationEntryImpl* e1 = new NavigationEntryImpl(
       instance, url, Referrer(), absl::nullopt, std::u16string(),
-      ui::PAGE_TRANSITION_LINK, false, nullptr /* blob_url_loader_factory */);
+      ui::PAGE_TRANSITION_LINK, false, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
 
   // Redundantly setting e1's SiteInstance shouldn't affect the ref count.
   e1->set_site_instance(instance);
@@ -442,7 +443,8 @@
   // Add a second reference
   NavigationEntryImpl* e2 = new NavigationEntryImpl(
       instance, url, Referrer(), absl::nullopt, std::u16string(),
-      ui::PAGE_TRANSITION_LINK, false, nullptr /* blob_url_loader_factory */);
+      ui::PAGE_TRANSITION_LINK, false, nullptr /* blob_url_loader_factory */,
+      false /* is_initial_entry */);
 
   instance = nullptr;
   EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index e861afd..f8c23d687 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1820,7 +1820,7 @@
 
 bool WebContentsImpl::ShouldOverrideUserAgentForRendererInitiatedNavigation() {
   NavigationEntryImpl* current_entry = GetController().GetLastCommittedEntry();
-  if (!current_entry)
+  if (current_entry->IsInitialEntry())
     return should_override_user_agent_in_new_tabs_;
 
   switch (renderer_initiated_user_agent_override_option_) {
@@ -1895,13 +1895,8 @@
   }
 
   NavigationEntry* entry = GetNavigationEntryForTitle();
-  if (entry) {
-    return entry->GetTitleForDisplay();
-  }
-
-  // |page_title_when_no_navigation_entry_| is finally used
-  // if no title cannot be retrieved.
-  return page_title_when_no_navigation_entry_;
+  CHECK(entry);
+  return entry->GetTitleForDisplay();
 }
 
 SiteInstanceImpl* WebContentsImpl::GetSiteInstance() {
@@ -2973,7 +2968,7 @@
 
   primary_frame_tree_.Init(site_instance.get(),
                            params.renderer_initiated_creation,
-                           params.main_frame_name);
+                           params.main_frame_name, GetOriginalOpener());
 
   WebContentsViewDelegate* delegate =
       GetContentClient()->browser()->GetWebContentsViewDelegate(this);
@@ -5858,7 +5853,7 @@
       referrer_for_view_source, initiator_for_view_source,
       title_for_view_source, ui::PAGE_TRANSITION_LINK,
       /* is_renderer_initiated = */ false,
-      /* blob_url_loader_factory = */ nullptr);
+      /* blob_url_loader_factory = */ nullptr, /* is_initial_entry = */ false);
   const GURL url(content::kViewSourceScheme + std::string(":") +
                  frame_entry->url().spec());
   navigation_entry->SetVirtualURL(url);
@@ -6352,28 +6347,17 @@
 
 bool WebContentsImpl::UpdateTitleForEntryImpl(NavigationEntryImpl* entry,
                                               const std::u16string& title) {
+  CHECK(entry);
   std::u16string final_title;
   base::TrimWhitespace(title, base::TRIM_ALL, &final_title);
 
-  // If a page is created via window.open and never navigated,
-  // there will be no navigation entry. In this situation,
-  // |page_title_when_no_navigation_entry_| will be used for page title.
-  // For a title update from a non-primary frame tree, |entry| will always be
-  // non-null.
-  if (entry) {
-    if (final_title == entry->GetTitle())
-      return false;  // Nothing changed, don't bother.
+  if (final_title == entry->GetTitle())
+    return false;  // Nothing changed, don't bother.
 
-    entry->SetTitle(final_title);
+  entry->SetTitle(final_title);
+  // The title for display may differ from the title just set; grab it.
+  final_title = entry->GetTitleForDisplay();
 
-    // The title for display may differ from the title just set; grab it.
-    final_title = entry->GetTitleForDisplay();
-  } else {
-    if (page_title_when_no_navigation_entry_ == final_title)
-      return false;  // Nothing changed, don't bother.
-
-    page_title_when_no_navigation_entry_ = final_title;
-  }
   return true;
 }
 
@@ -6382,8 +6366,7 @@
   // NavigationController.
   DCHECK(!entry || GetController().GetEntryWithUniqueIDIncludingPending(
                        entry->GetUniqueID()));
-  std::u16string final_title = entry ? entry->GetTitleForDisplay()
-                                     : page_title_when_no_navigation_entry_;
+  std::u16string final_title = entry->GetTitleForDisplay();
   bool did_web_contents_title_change = entry == GetNavigationEntryForTitle();
   if (did_web_contents_title_change)
     view_->SetPageTitle(final_title);
@@ -7441,8 +7424,12 @@
 
   // We can handle title updates when we don't have an entry in
   // UpdateTitleForEntry, but only if the update is from the current RFH.
-  if (!entry && render_frame_host != GetMainFrame())
-    return;
+  if (!entry) {
+    if (render_frame_host != GetMainFrame())
+      return;
+    // Use the last committed entry to attach the title to.
+    entry = GetController().GetLastCommittedEntry();
+  }
 
   // TODO(evan): make use of title_direction.
   // http://code.google.com/p/chromium/issues/detail?id=27094
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index ea8b1d5..246d89e7 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -1832,9 +1832,7 @@
   // display title.
   void NotifyTitleUpdateForEntry(NavigationEntryImpl* entry);
   // Returns the navigation entry whose title is used as the display title for
-  // this WebContents (i.e. for WebContents::GetTitle()). This value can be
-  // null, in which case a fallback title is used (see
-  // |page_title_when_no_navigation_entry_|).
+  // this WebContents (i.e. for WebContents::GetTitle()).
   NavigationEntry* GetNavigationEntryForTitle();
 
   // Data for core operation ---------------------------------------------------
@@ -1934,9 +1932,6 @@
 
   // Data for current page -----------------------------------------------------
 
-  // When a title cannot be taken from any entry, this title will be used.
-  std::u16string page_title_when_no_navigation_entry_;
-
   // The last published theme color.
   absl::optional<SkColor> last_sent_theme_color_;
 
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index f7d54b1..32a9eed 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -3258,8 +3258,12 @@
         &success));
     new_shell = new_shell_observer.GetShell();
     new_contents = new_shell->web_contents();
-    // Delaying popup holds the initial load.
-    EXPECT_FALSE(WaitForLoadStop(new_contents));
+    // Delaying popup holds the initial load of |url|.
+    EXPECT_TRUE(WaitForLoadStop(new_contents));
+    EXPECT_TRUE(new_contents->GetController()
+                    .GetLastCommittedEntry()
+                    ->IsInitialEntry());
+    EXPECT_NE(url, new_contents->GetLastCommittedURL());
   }
 
   EXPECT_FALSE(new_contents->GetDelegate());
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index ca48327..4f02748 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -1504,14 +1504,14 @@
 // Test that NavigationEntries have the correct page state after going
 // forward and back.  Prevents regression for bug 1116137.
 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
-
-  // Navigate to URL.  There should be no committed entry yet.
+  // Navigate to URL.  Before the navigation finishes, there should be only the
+  // initial NavigationEntry.
   const GURL url("http://www.google.com");
   auto navigation =
       NavigationSimulator::CreateBrowserInitiated(url, contents());
   navigation->ReadyToCommit();
   NavigationEntry* entry = controller().GetLastCommittedEntry();
-  EXPECT_EQ(nullptr, entry);
+  EXPECT_TRUE(entry->IsInitialEntry());
 
   // Committed entry should have page state.
   navigation->Commit();
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 342d66d..5eca7ee9 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -351,8 +351,6 @@
           // the feature is in stable with no issues.
           {"DialogFocusNewSpecBehavior",
            blink::features::kDialogFocusNewSpecBehavior},
-          {"FeaturePolicyForClientHints",
-           features::kFeaturePolicyForClientHints},
           {"EditingNG", blink::features::kEditingNG},
           {"FileHandling", blink::features::kFileHandlingAPI},
           {"Fledge", blink::features::kFledge},
diff --git a/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
index e9d3b7f..e9f32c1 100644
--- a/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
@@ -320,9 +320,9 @@
     @CalledByNative
     private static NavigationEntry createNavigationEntry(int index, GURL url, GURL virtualUrl,
             GURL originalUrl, GURL referrerUrl, String title, Bitmap favicon, int transition,
-            long timestamp) {
+            long timestamp, boolean isInitialEntry) {
         return new NavigationEntry(index, url, virtualUrl, originalUrl, referrerUrl, title, favicon,
-                transition, timestamp);
+                transition, timestamp, isInitialEntry);
     }
 
     @NativeMethods
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/NavigationEntry.java b/content/public/android/java/src/org/chromium/content_public/browser/NavigationEntry.java
index 9bb1963..9d927ca 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/NavigationEntry.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/NavigationEntry.java
@@ -24,13 +24,14 @@
     private Bitmap mFavicon;
     private int mTransition;
     private long mTimestamp;
+    private final boolean mIsInitialEntry;
 
     /**
      * Default constructor.
      */
     public NavigationEntry(int index, @NonNull GURL url, @NonNull GURL virtualUrl,
             @NonNull GURL originalUrl, @NonNull GURL referrerUrl, String title, Bitmap favicon,
-            int transition, long timestamp) {
+            int transition, long timestamp, boolean isInitialEntry) {
         mIndex = index;
         mUrl = url;
         mVirtualUrl = virtualUrl;
@@ -40,6 +41,7 @@
         mFavicon = favicon;
         mTransition = transition;
         mTimestamp = timestamp;
+        mIsInitialEntry = isInitialEntry;
     }
 
     /**
@@ -121,4 +123,11 @@
     public long getTimestamp() {
         return mTimestamp;
     }
+
+    /**
+     * @return Whether the entry is the initial entry or not.
+     */
+    public boolean isInitialEntry() {
+        return mIsInitialEntry;
+    }
 }
diff --git a/content/public/browser/navigation_controller.h b/content/public/browser/navigation_controller.h
index fdfb016..0fd31df 100644
--- a/content/public/browser/navigation_controller.h
+++ b/content/public/browser/navigation_controller.h
@@ -342,7 +342,6 @@
   // Returns the entry that should be displayed to the user in the address bar.
   // This is the pending entry if a navigation is in progress *and* is safe to
   // display to the user (see below), or the last committed entry otherwise.
-  // NOTE: This can be nullptr if no entry has committed!
   //
   // A pending entry is safe to display if it started in the browser process or
   // if it's a renderer-initiated navigation in a new tab which hasn't been
@@ -354,12 +353,13 @@
   // it is the pending_entry_index_.
   virtual int GetCurrentEntryIndex() = 0;
 
-  // Returns the last committed entry, which may be null if there are no
-  // committed entries.
+  // Returns the last "committed" entry. Note that even when no navigation has
+  // actually committed, this will never return null as long as the FrameTree
+  // associated with the NavigationController is already initialized, as a
+  // FrameTree will always start with the initial NavigationEntry.
   virtual NavigationEntry* GetLastCommittedEntry() = 0;
 
-  // Returns the index of the last committed entry.  It will be -1 if there are
-  // no entries.
+  // Returns the index of the last committed entry.
   virtual int GetLastCommittedEntryIndex() = 0;
 
   // Returns true if the source for the current entry can be viewed.
diff --git a/content/public/browser/navigation_entry.h b/content/public/browser/navigation_entry.h
index ba431fd..a3ebf55 100644
--- a/content/public/browser/navigation_entry.h
+++ b/content/public/browser/navigation_entry.h
@@ -44,6 +44,13 @@
 
   CONTENT_EXPORT static std::unique_ptr<NavigationEntry> Create();
 
+  // True if this entry is the initial NavigationEntry, which is created when a
+  // FrameTree is first initialized. The initial NavigationEntry, unlike other
+  // NavigationEntries, is not associated with any committed navigation in the
+  // main frame. After any navigation committed in the main frame, the
+  // NavigationEntry will be replaced, or at least lose its "initial" status.
+  virtual bool IsInitialEntry() = 0;
+
   // Page-related stuff --------------------------------------------------------
 
   // A unique ID is preserved across commits and redirects, which means that
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 291a022..6114e66 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -350,7 +350,9 @@
   // "view-source:" prefix for view source URLs, unlike NavigationEntry::GetURL
   // and NavigationHandle::GetURL). The last committed page is the current
   // security context and the content that is actually displayed within the tab.
-  // See also GetVisibleURL above, which may differ from this URL.
+  // See also GetVisibleURL above, which may differ from this URL. Note that
+  // this might return an empty GURL if no navigation has committed in the
+  // WebContents' main frame.
   virtual const GURL& GetLastCommittedURL() = 0;
 
   // Returns the main frame for the currently active view. Always non-null
diff --git a/content/public/browser/web_contents_user_data.h b/content/public/browser/web_contents_user_data.h
index 0fbeadc2..7803f4d 100644
--- a/content/public/browser/web_contents_user_data.h
+++ b/content/public/browser/web_contents_user_data.h
@@ -91,7 +91,7 @@
 // This macro declares a static variable inside the class that inherits from
 // WebContentsUserData The address of this static variable is used as the key to
 // store/retrieve an instance of the class on/from a WebState.
-#define WEB_CONTENTS_USER_DATA_KEY_DECL() static constexpr int kUserDataKey = 0
+#define WEB_CONTENTS_USER_DATA_KEY_DECL() static const int kUserDataKey = 0
 
 // This macro instantiates the static variable declared by the previous macro.
 // It must live in a .cc file to ensure that there is only one instantiation
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 909909a7a..d3ff9ae 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -315,10 +315,6 @@
     "ExtraSafelistedRequestHeadersForOutOfBlinkCors",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Controls whether Client Hints are guarded by Permissions Policy.
-const base::Feature kFeaturePolicyForClientHints{
-    "FeaturePolicyForClientHints", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Whether to initialize the font manager when the renderer starts on a
 // background thread.
 const base::Feature kFontManagerEarlyInit{"FontManagerEarlyInit",
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 870e7e6d..f1bc59f 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -80,7 +80,6 @@
     kExperimentalContentSecurityPolicyFeatures;
 CONTENT_EXPORT extern const base::Feature
     kExtraSafelistedRequestHeadersForOutOfBlinkCors;
-CONTENT_EXPORT extern const base::Feature kFeaturePolicyForClientHints;
 CONTENT_EXPORT extern const base::Feature kFontManagerEarlyInit;
 CONTENT_EXPORT extern const base::Feature kFontSrcLocalMatching;
 #if !defined(OS_ANDROID)
diff --git a/content/public/common/content_switch_dependent_feature_overrides.cc b/content/public/common/content_switch_dependent_feature_overrides.cc
index c76dba9..d6aed7e 100644
--- a/content/public/common/content_switch_dependent_feature_overrides.cc
+++ b/content/public/common/content_switch_dependent_feature_overrides.cc
@@ -43,9 +43,6 @@
        std::cref(features::kExperimentalContentSecurityPolicyFeatures),
        base::FeatureList::OVERRIDE_ENABLE_FEATURE},
       {switches::kEnableExperimentalWebPlatformFeatures,
-       std::cref(features::kFeaturePolicyForClientHints),
-       base::FeatureList::OVERRIDE_ENABLE_FEATURE},
-      {switches::kEnableExperimentalWebPlatformFeatures,
        std::cref(blink::features::kUserAgentClientHint),
        base::FeatureList::OVERRIDE_ENABLE_FEATURE},
       {switches::kEnableExperimentalWebPlatformFeatures,
diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc
index 14a62c6..b6811f9 100644
--- a/content/test/content_browser_test_utils_internal.cc
+++ b/content/test/content_browser_test_utils_internal.cc
@@ -200,8 +200,9 @@
   EXPECT_TRUE(ExecJs(root, "last_opened_window = window.open()"));
   Shell* new_shell = new_shell_observer.GetShell();
   EXPECT_NE(new_shell->web_contents(), web_contents);
-  EXPECT_FALSE(
+  EXPECT_TRUE(
       new_shell->web_contents()->GetController().GetLastCommittedEntry());
+  EXPECT_EQ(1, new_shell->web_contents()->GetController().GetEntryCount());
   return new_shell;
 }
 
diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h
index a1ca184..ce279a1 100644
--- a/content/test/content_browser_test_utils_internal.h
+++ b/content/test/content_browser_test_utils_internal.h
@@ -98,7 +98,7 @@
 CollectAllRenderFrameHostsIncludingSpeculative(WebContentsImpl* web_contents);
 
 // Open a new popup passing no URL to window.open, which results in a blank page
-// and no last committed entry. Returns the newly created shell. Also saves the
+// and only the initial entry. Returns the newly created shell. Also saves the
 // reference to the opened window in the "last_opened_window" variable in JS.
 Shell* OpenBlankWindow(WebContentsImpl* web_contents);
 
diff --git a/content/test/data/back_forward_cache/page_with_indexedDB.html b/content/test/data/back_forward_cache/page_with_indexedDB.html
new file mode 100644
index 0000000..95800362
--- /dev/null
+++ b/content/test/data/back_forward_cache/page_with_indexedDB.html
@@ -0,0 +1,49 @@
+<!doctype html>
+  <title>IndexedDB test</title>
+<script>
+'use strict';
+let db;
+
+async function setupIndexedDBConnection() {
+  db = await new Promise((resolve, reject) => {
+    let request = window.indexedDB.open('testdb', 1);
+    request.onsuccess = () => resolve(request.result);
+    request.onerror = (error) => reject(error);;
+    request.onupgradeneeded = () => {
+    request.result.createObjectStore('store');
+    };
+  });
+}
+
+
+function registerPagehideToCloseIndexedDBConnection() {
+  addEventListener('pagehide', () => {
+    db.close();
+  });
+}
+
+function registerPagehideToStartTransaction() {
+  addEventListener('pagehide', () => {
+    let transaction = db.transaction(['store'], 'readwrite');
+    let store = transaction.objectStore('store');
+    store.put("key", "value");
+
+    // Queue a request to close the connection.
+    db.close();
+  });
+}
+
+function registerPagehideToStartAndCommitTransaction() {
+  addEventListener('pagehide', () => {
+    let transaction = db.transaction(['store'], 'readwrite');
+    let store = transaction.objectStore('store');
+    store.put("key", "value");
+
+    // Call commit to run the transaction right away.
+    transaction.commit();
+    // Close the connection.
+    db.close();
+  });
+}
+
+</script>
diff --git a/content/web_test/browser/devtools_protocol_test_bindings.cc b/content/web_test/browser/devtools_protocol_test_bindings.cc
index 6cbe0b5..6273c76 100644
--- a/content/web_test/browser/devtools_protocol_test_bindings.cc
+++ b/content/web_test/browser/devtools_protocol_test_bindings.cc
@@ -89,23 +89,21 @@
 }
 
 void DevToolsProtocolTestBindings::HandleMessageFromTest(base::Value message) {
-  std::string method;
-  base::ListValue* params = nullptr;
-  base::DictionaryValue* dict = nullptr;
-  if (!message.GetAsDictionary(&dict) || !dict->GetString("method", &method)) {
+  const std::string* method = nullptr;
+  if (!message.is_dict() || !(method = message.FindStringKey("method"))) {
     return;
   }
 
-  dict->GetList("params", &params);
-
-  if (method == "dispatchProtocolMessage" && params &&
+  const base::Value* params = message.FindListKey("params");
+  if (*method == "dispatchProtocolMessage" && params &&
       params->GetList().size() == 1) {
-    std::string protocol_message;
-    if (!params->GetString(0, &protocol_message))
+    const std::string* protocol_message = params->GetList()[0].GetIfString();
+    if (!protocol_message)
       return;
+
     if (agent_host_) {
       agent_host_->DispatchProtocolMessage(
-          this, base::as_bytes(base::make_span(protocol_message)));
+          this, base::as_bytes(base::make_span(*protocol_message)));
     }
     return;
   }
diff --git a/content/web_test/browser/web_test_control_host.cc b/content/web_test/browser/web_test_control_host.cc
index 5006de83..67caf5f 100644
--- a/content/web_test/browser/web_test_control_host.cc
+++ b/content/web_test/browser/web_test_control_host.cc
@@ -129,8 +129,7 @@
   std::string url = web_test_string_util::NormalizeWebTestURL(
       base::UTF16ToUTF8(frame_state.url_string.value_or(std::u16string())));
   result.append(url);
-  DCHECK(frame_state.target);
-  if (!frame_state.target->empty()) {
+  if (frame_state.target && !frame_state.target->empty()) {
     std::string unique_name = base::UTF16ToUTF8(*frame_state.target);
     result.append(" (in frame \"");
     result.append(
diff --git a/docs/session_history.md b/docs/session_history.md
index 5071a789..fd57dd3 100644
--- a/docs/session_history.md
+++ b/docs/session_history.md
@@ -114,12 +114,5 @@
    subframe navigations do not, and renderer-initiated main frame navigations
    may clear an existing browser-initiated pending NavigationEntry (using
    PendingEntryRef) without replacing it with a new one.
- * Some main frame documents may not have a corresponding NavigationEntry
-   even after commit (e.g., the initial empty document, per
-   [issue 524208](https://crbug.com/524208)).
  * Some subframe documents may not have a corresponding FrameNavigationEntry
    after commit (e.g., see [issue 608402](https://crbug.com/608402)).
- * FrameNavigationEntries should be shared between NavigationEntries when they
-   do not change (e.g., to support history.replaceState after subframe
-   navigations), but this is not yet supported.
-   See [issue 373041](https://crbug.com/373041).
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index cbd3215..4620cbd 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -899,7 +899,7 @@
     const blink::UserAgentOverride& ua_override) {
   content::NavigationController& controller = web_contents()->GetController();
   content::NavigationEntry* entry = controller.GetVisibleEntry();
-  if (!entry)
+  if (entry->IsInitialEntry())
     return;
   entry->SetIsOverridingUserAgent(!ua_override.ua_string_override.empty());
   web_contents()->GetController().Reload(content::ReloadType::NORMAL, false);
diff --git a/extensions/browser/process_manager.cc b/extensions/browser/process_manager.cc
index 406727c..bee1c92 100644
--- a/extensions/browser/process_manager.cc
+++ b/extensions/browser/process_manager.cc
@@ -485,11 +485,11 @@
     // extension urls are loaded in that SiteInstance).
     content::NavigationController& controller = web_contents->GetController();
     content::NavigationEntry* entry = controller.GetLastCommittedEntry();
-    // If there is no last committed entry, check the pending entry. This can
-    // happen in cases where we query this before any entry is fully committed,
-    // such as when attributing a WebContents for the TaskManager. If there is
-    // a committed navigation, use that instead.
-    if (!entry)
+    // If the "last committed" entry is the initial entry, check the pending
+    // entry. This can happen in cases where we query this before any entry is
+    // fully committed, such as when attributing a WebContents for the
+    // TaskManager. If there is a committed navigation, use that instead.
+    if (entry->IsInitialEntry())
       entry = controller.GetPendingEntry();
     if (!entry ||
         extension_registry_->enabled_extensions().GetExtensionOrAppByURL(
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn
index 38c2df9..ec331810 100644
--- a/extensions/shell/BUILD.gn
+++ b/extensions/shell/BUILD.gn
@@ -265,10 +265,6 @@
 
     if (is_linux || is_chromeos) {
       deps += [ "//components/nacl/loader:nacl_helper" ]
-
-      if (enable_nacl_nonsfi) {
-        deps += [ "//components/nacl/loader:helper_nonsfi" ]
-      }
     }
   }
 }
diff --git a/fuchsia/engine/browser/navigation_controller_impl.cc b/fuchsia/engine/browser/navigation_controller_impl.cc
index dc7253b3..c48438e 100644
--- a/fuchsia/engine/browser/navigation_controller_impl.cc
+++ b/fuchsia/engine/browser/navigation_controller_impl.cc
@@ -125,7 +125,7 @@
       [this](zx_status_t status) { SetEventListener(nullptr, {}); });
 
   // Immediately send the current navigation state, even if it is empty.
-  if (web_contents_->GetController().GetVisibleEntry() == nullptr) {
+  if (web_contents_->GetController().GetVisibleEntry()->IsInitialEntry()) {
     waiting_for_navigation_event_ack_ = true;
     navigation_listener_->OnNavigationStateChanged(
         fuchsia::web::NavigationState(), [this]() {
@@ -141,7 +141,7 @@
 NavigationControllerImpl::GetVisibleNavigationState() const {
   content::NavigationEntry* const entry =
       web_contents_->GetController().GetVisibleEntry();
-  if (!entry)
+  if (entry->IsInitialEntry())
     return fuchsia::web::NavigationState();
 
   fuchsia::web::NavigationState state;
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index ee8ea147..a942765 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -807,7 +807,8 @@
      flag_descriptions::kIOSEnablePasswordManagerBrandingUpdateName,
      flag_descriptions::kIOSEnablePasswordManagerBrandingUpdateDescription,
      flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(kIOSEnablePasswordManagerBrandingUpdate)},
+     FEATURE_VALUE_TYPE(
+         password_manager::features::kIOSEnablePasswordManagerBrandingUpdate)},
 };
 
 bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/main/browser_agent_util.mm b/ios/chrome/browser/main/browser_agent_util.mm
index f3ac000..9fa9fa1 100644
--- a/ios/chrome/browser/main/browser_agent_util.mm
+++ b/ios/chrome/browser/main/browser_agent_util.mm
@@ -63,8 +63,8 @@
   if (!browser->GetBrowserState()->IsOffTheRecord())
     SendTabToSelfBrowserAgent::CreateForBrowser(browser);
 
-  // WebStateDelegateBrowserAgent requires TabInsertionBrowserAgent.
-  WebStateDelegateBrowserAgent::CreateForBrowser(browser);
+  WebStateDelegateBrowserAgent::CreateForBrowser(
+      browser, TabInsertionBrowserAgent::FromBrowser(browser));
 
   // ViewSourceBrowserAgent requires TabInsertionBrowserAgent, and is only used
   // in debug builds.
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm
index b643630..b912a81 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm
@@ -71,7 +71,8 @@
     SceneStateBrowserAgent::CreateForBrowser(browser_.get(), scene_state_);
     WebNavigationBrowserAgent::CreateForBrowser(browser_.get());
     TabInsertionBrowserAgent::CreateForBrowser(browser_.get());
-    WebStateDelegateBrowserAgent::CreateForBrowser(browser_.get());
+    WebStateDelegateBrowserAgent::CreateForBrowser(
+        browser_.get(), TabInsertionBrowserAgent::FromBrowser(browser_.get()));
 
     IncognitoReauthSceneAgent* reauthAgent = [[IncognitoReauthSceneAgent alloc]
         initWithReauthModule:[[ReauthenticationModule alloc] init]];
diff --git a/ios/chrome/browser/ui/passwords/password_breach_view_controller.mm b/ios/chrome/browser/ui/passwords/password_breach_view_controller.mm
index 98b3257..39e1deb6 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_view_controller.mm
+++ b/ios/chrome/browser/ui/passwords/password_breach_view_controller.mm
@@ -4,9 +4,9 @@
 
 #import "ios/chrome/browser/ui/passwords/password_breach_view_controller.h"
 
+#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/passwords/password_constants.h"
-#include "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/common/ui/confirmation_alert/confirmation_alert_action_handler.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -31,7 +31,9 @@
   self.helpButtonAccessibilityLabel =
       l10n_util::GetNSString(IDS_IOS_HELP_ACCESSIBILITY_LABEL);
 
-  if (base::FeatureList::IsEnabled(kIOSEnablePasswordManagerBrandingUpdate)) {
+  if (base::FeatureList::IsEnabled(
+          password_manager::features::
+              kIOSEnablePasswordManagerBrandingUpdate)) {
     self.image = [UIImage imageNamed:@"password_breach_illustration"];
     self.secondaryActionString = l10n_util::GetNSString(IDS_NOT_NOW);
     self.showDismissBarButton = NO;
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/BUILD.gn b/ios/chrome/browser/ui/popup_menu/overflow_menu/BUILD.gn
index 68eb92a..f51603c 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/BUILD.gn
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/BUILD.gn
@@ -103,6 +103,7 @@
   ]
   deps = [
     "//base",
+    "//components/password_manager/core/common",
     "//ios/chrome/browser/ui:feature_flags",
   ]
 }
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.mm b/ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.mm
index 343bb2bb..52aa22c 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.mm
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.mm
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #import "ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 #import "ios/chrome/browser/ui/ui_feature_flags.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -24,7 +25,7 @@
 bool IsPasswordManagerBrandingUpdateEnabled() {
   if (IsNewOverflowMenuEnabled()) {
     return base::FeatureList::IsEnabled(
-        kIOSEnablePasswordManagerBrandingUpdate);
+        password_manager::features::kIOSEnablePasswordManagerBrandingUpdate);
   }
 
   return false;
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc
index 0c15d71..c9dda905 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.cc
+++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -40,12 +40,6 @@
     "DefaultBrowserFullscreenPromoExperiment",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Feature flag that updates icons, strings, and views for Google Password
-// Manager.
-const base::Feature kIOSEnablePasswordManagerBrandingUpdate{
-    "IOSEnablePasswordManagerBrandingUpdate",
-    base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kIOSNewOmniboxImplementation{
     "kIOSNewOmniboxImplementation", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/ios/chrome/browser/ui/ui_feature_flags.h b/ios/chrome/browser/ui/ui_feature_flags.h
index a0607b9..9354f00 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.h
+++ b/ios/chrome/browser/ui/ui_feature_flags.h
@@ -49,10 +49,6 @@
 // Feature flag that experiments with the default browser fullscreen promo UI.
 extern const base::Feature kDefaultBrowserFullscreenPromoExperiment;
 
-// Feature flag that updates icons, strings, and views for Google Password
-// Manager.
-extern const base::Feature kIOSEnablePasswordManagerBrandingUpdate;
-
 // Feature flag that shows iOS 15 context menu, instead of tooltip popover,
 // during a location bar long press gesture.
 extern const base::Feature kIOSLocationBarUseNativeContextMenu;
diff --git a/ios/chrome/browser/web/web_state_delegate_browser_agent.h b/ios/chrome/browser/web/web_state_delegate_browser_agent.h
index 1af7ff4..87865e9 100644
--- a/ios/chrome/browser/web/web_state_delegate_browser_agent.h
+++ b/ios/chrome/browser/web/web_state_delegate_browser_agent.h
@@ -7,11 +7,14 @@
 
 #include <CoreFoundation/CoreFoundation.h>
 
+#include "base/scoped_multi_source_observation.h"
+#include "base/scoped_observation.h"
 #include "ios/chrome/browser/main/browser_observer.h"
 #include "ios/chrome/browser/main/browser_user_data.h"
 #import "ios/chrome/browser/ui/dialogs/overlay_java_script_dialog_presenter.h"
+#include "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "ios/chrome/browser/web_state_list/web_state_list_observer.h"
-#import "ios/web/public/web_state_delegate.h"
+#include "ios/web/public/web_state_delegate.h"
 #include "ios/web/public/web_state_observer.h"
 
 @class ContextMenuConfigurationProvider;
@@ -25,9 +28,10 @@
 // added to the browser's WebStateList (and unassigning them when they leave).
 // This browser agent must be created after TabInsertionBrowserAgent.
 class WebStateDelegateBrowserAgent
-    : BrowserObserver,
+    : public BrowserObserver,
       public BrowserUserData<WebStateDelegateBrowserAgent>,
-      WebStateListObserver,
+      public WebStateListObserver,
+      public web::WebStateObserver,
       public web::WebStateDelegate {
  public:
   ~WebStateDelegateBrowserAgent() override;
@@ -37,6 +41,10 @@
   WebStateDelegateBrowserAgent& operator=(const WebStateDelegateBrowserAgent&) =
       delete;
 
+  // Factory.
+  static void CreateForBrowser(Browser* browser,
+                               TabInsertionBrowserAgent* tab_insertion_agent);
+
   // Sets the UI providers to be used for WebStateDelegate tasks that require
   // them.
   // If providers are added, factor these params into a Params struct.
@@ -49,10 +57,12 @@
   void ClearUIProviders();
 
  private:
-  explicit WebStateDelegateBrowserAgent(Browser* browser);
   friend class BrowserUserData<WebStateDelegateBrowserAgent>;
   BROWSER_USER_DATA_KEY_DECL();
 
+  WebStateDelegateBrowserAgent(Browser* browser,
+                               TabInsertionBrowserAgent* tab_insertion_agent);
+
   // WebStateListObserver::
   void WebStateInsertedAt(WebStateList* web_state_list,
                           web::WebState* web_state,
@@ -65,9 +75,14 @@
   void WebStateDetachedAt(WebStateList* web_state_list,
                           web::WebState* web_state,
                           int index) override;
+
   // BrowserObserver::
   void BrowserDestroyed(Browser* browser) override;
 
+  // web::WebStateObserver:
+  void WebStateRealized(web::WebState* web_state) override;
+  void WebStateDestroyed(web::WebState* web_state) override;
+
   // web::WebStateDelegate:
   web::WebState* CreateNewWebState(web::WebState* source,
                                    const GURL& url,
@@ -99,11 +114,25 @@
   id<CRWResponderInputView> GetResponderInputView(
       web::WebState* source) override;
 
-  WebStateList* web_state_list_;
-  TabInsertionBrowserAgent* tab_insertion_agent_;
+  // Helper methods to set/clear the WebState delegate if it is realized,
+  // or to listen for the realization of the WebState.
+  void SetWebStateDelegate(web::WebState* web_state);
+  void ClearWebStateDelegate(web::WebState* web_state);
+
+  WebStateList* web_state_list_ = nullptr;
+  TabInsertionBrowserAgent* tab_insertion_agent_ = nullptr;
 
   OverlayJavaScriptDialogPresenter java_script_dialog_presenter_;
 
+  // Scoped observations of Browser, WebStateList and WebStates.
+  base::ScopedObservation<Browser, BrowserObserver> browser_observation_{this};
+
+  base::ScopedObservation<WebStateList, WebStateListObserver>
+      web_state_list_observation_{this};
+
+  base::ScopedMultiSourceObservation<web::WebState, web::WebStateObserver>
+      web_state_observations_{this};
+
   // These providers are owned by other objects.
   __weak ContextMenuConfigurationProvider* context_menu_provider_;
   __weak id<CRWResponderInputView> input_view_provider_;
diff --git a/ios/chrome/browser/web/web_state_delegate_browser_agent.mm b/ios/chrome/browser/web/web_state_delegate_browser_agent.mm
index e5c512e4..e973f39 100644
--- a/ios/chrome/browser/web/web_state_delegate_browser_agent.mm
+++ b/ios/chrome/browser/web/web_state_delegate_browser_agent.mm
@@ -19,7 +19,6 @@
 #import "ios/chrome/browser/web/repost_form_tab_helper.h"
 #import "ios/chrome/browser/web/web_state_container_view_provider.h"
 #import "ios/chrome/browser/web_state_list/tab_insertion_browser_agent.h"
-#import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/components/security_interstitials/ios_blocking_page_tab_helper.h"
 #import "ios/web/public/ui/context_menu_params.h"
 
@@ -48,14 +47,33 @@
 }
 }  // namespace
 
-WebStateDelegateBrowserAgent::WebStateDelegateBrowserAgent(Browser* browser)
+// static
+void WebStateDelegateBrowserAgent::CreateForBrowser(
+    Browser* browser,
+    TabInsertionBrowserAgent* tab_insertion_agent) {
+  DCHECK(browser);
+
+  if (!FromBrowser(browser)) {
+    browser->SetUserData(UserDataKey(),
+                         base::WrapUnique(new WebStateDelegateBrowserAgent(
+                             browser, tab_insertion_agent)));
+  }
+}
+
+WebStateDelegateBrowserAgent::WebStateDelegateBrowserAgent(
+    Browser* browser,
+    TabInsertionBrowserAgent* tab_insertion_agent)
     : web_state_list_(browser->GetWebStateList()),
-      tab_insertion_agent_(TabInsertionBrowserAgent::FromBrowser(browser)) {
+      tab_insertion_agent_(tab_insertion_agent) {
   DCHECK(tab_insertion_agent_);
-  browser->AddObserver(this);
-  web_state_list_->AddObserver(this);
-  for (int index = 0; index < web_state_list_->count(); ++index)
-    web_state_list_->GetWebStateAt(index)->SetDelegate(this);
+  browser_observation_.Observe(browser);
+  web_state_list_observation_.Observe(web_state_list_);
+
+  // All the BrowserAgent are attached to the Browser during the creation,
+  // the WebStateList must be empty at this point.
+  DCHECK(web_state_list_->empty())
+      << "WebStateDelegateBrowserAgent created for a Browser with a non-empty "
+         "WebStateList.";
 }
 
 WebStateDelegateBrowserAgent::~WebStateDelegateBrowserAgent() {}
@@ -81,7 +99,7 @@
     web::WebState* web_state,
     int index,
     bool activating) {
-  web_state->SetDelegate(this);
+  SetWebStateDelegate(web_state);
 }
 
 void WebStateDelegateBrowserAgent::WebStateReplacedAt(
@@ -89,26 +107,42 @@
     web::WebState* old_web_state,
     web::WebState* new_web_state,
     int index) {
-  old_web_state->SetDelegate(nullptr);
-  new_web_state->SetDelegate(this);
+  ClearWebStateDelegate(old_web_state);
+  SetWebStateDelegate(new_web_state);
 }
 
 void WebStateDelegateBrowserAgent::WebStateDetachedAt(
     WebStateList* web_state_list,
     web::WebState* web_state,
     int index) {
-  web_state->SetDelegate(nullptr);
+  ClearWebStateDelegate(web_state);
 }
 
 // BrowserObserver::
 void WebStateDelegateBrowserAgent::BrowserDestroyed(Browser* browser) {
-  DCHECK_EQ(browser->GetWebStateList(), web_state_list_);
+  DCHECK(browser_observation_.IsObservingSource(browser));
+
+  WebStateList* web_state_list = browser->GetWebStateList();
+  DCHECK(web_state_list_observation_.IsObservingSource(web_state_list));
+  DCHECK_EQ(web_state_list_, web_state_list);
+
   // Remove all web state delegates.
   for (int index = 0; index < web_state_list_->count(); ++index)
     web_state_list_->GetWebStateAt(index)->SetDelegate(nullptr);
 
-  browser->GetWebStateList()->RemoveObserver(this);
-  browser->RemoveObserver(this);
+  web_state_observations_.RemoveAllObservations();
+  web_state_list_observation_.Reset();
+  browser_observation_.Reset();
+}
+
+// WebStateObserver::
+void WebStateDelegateBrowserAgent::WebStateRealized(web::WebState* web_state) {
+  SetWebStateDelegate(web_state);
+  web_state_observations_.RemoveObservation(web_state);
+}
+
+void WebStateDelegateBrowserAgent::WebStateDestroyed(web::WebState* web_state) {
+  web_state_observations_.RemoveObservation(web_state);
 }
 
 // WebStateDelegate::
@@ -262,3 +296,23 @@
     web::WebState* source) {
   return input_view_provider_;
 }
+
+void WebStateDelegateBrowserAgent::SetWebStateDelegate(
+    web::WebState* web_state) {
+  DCHECK(web_state);
+  if (web_state->IsRealized()) {
+    web_state->SetDelegate(this);
+  } else {
+    web_state_observations_.AddObservation(web_state);
+  }
+}
+
+void WebStateDelegateBrowserAgent::ClearWebStateDelegate(
+    web::WebState* web_state) {
+  DCHECK(web_state);
+  if (web_state->IsRealized()) {
+    web_state->SetDelegate(nullptr);
+  } else {
+    web_state_observations_.RemoveObservation(web_state);
+  }
+}
diff --git a/ios/chrome/browser/web/web_state_delegate_browser_agent_unittest.mm b/ios/chrome/browser/web/web_state_delegate_browser_agent_unittest.mm
index c50fc74..2f90b4b 100644
--- a/ios/chrome/browser/web/web_state_delegate_browser_agent_unittest.mm
+++ b/ios/chrome/browser/web/web_state_delegate_browser_agent_unittest.mm
@@ -40,7 +40,8 @@
   WebStateDelegateBrowserAgentTest()
       : browser_(std::make_unique<TestBrowser>()) {
     TabInsertionBrowserAgent::CreateForBrowser(browser_.get());
-    WebStateDelegateBrowserAgent::CreateForBrowser(browser_.get());
+    WebStateDelegateBrowserAgent::CreateForBrowser(
+        browser_.get(), TabInsertionBrowserAgent::FromBrowser(browser_.get()));
   }
   ~WebStateDelegateBrowserAgentTest() override = default;
 
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 500b1208..aecca75 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-f1f225c579a6f730ec8c2ce83fa2ca1872ac85b7
\ No newline at end of file
+bfa7a0c49e4254e8ebb255713efa836efae236b1
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 9113c3dc3..1e7b0337 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-aeada587d7d0b8bf295b8eb9e78eeb73d36b9e36
\ No newline at end of file
+95307ab4f39a741129f6d37f74e05ca127d23fbe
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index 7e2db9c..04acb64 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-7ab24b952a4852bcda9d3d64a773db024d60e0b5
\ No newline at end of file
+cf00a49d8b073d88c74d836dff8b8bded71205a2
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index f90f764..fa8f82fc 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-15cff84dbebc587dc60ae39d35142f03f4344036
\ No newline at end of file
+c54ae81146277f7156414539ad5939b2376b3233
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
index c38363d..28cd3ccb 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-8deaca4b1a3f155359e6fe5f4f7b2d5b0e2c23fc
\ No newline at end of file
+b7c1203b636088282d219c4c1f6ca46e9ee6ddc1
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
index 90785e2b..11ab6f7 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-13e21c99ee7169d63f17c9f2187c317abdee8bf9
\ No newline at end of file
+c4aa9c19475853170a43802787c4097b2a44af79
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index ecf2fd1..cc46f88 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-608c85daa07459d1a45dac03c4a203b459a2fb2d
\ No newline at end of file
+e74c84b713062821a60b0c1d892843d8a0b83886
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 6be0547..de57bd4e 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-1cad47898ee3c41f80872218067f08d2cb24d6e2
\ No newline at end of file
+b578a66cb49c1c98e6ffca83344d6353b10c9334
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 73d91b90..644552a 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-c31be3f5af6d12009758f28ed02b6cdbfb14381d
\ No newline at end of file
+1f55550aac6a0d81159365fd61eb55dce448f189
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 5a3e80c..3a1e95d3d 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-7d40dc47217c8883b9110da84c9a715bcc225046
\ No newline at end of file
+650d265276b1fc43b82189c970a47142814eb4f4
\ No newline at end of file
diff --git a/ipc/BUILD.gn b/ipc/BUILD.gn
index 54a6802..9202770 100644
--- a/ipc/BUILD.gn
+++ b/ipc/BUILD.gn
@@ -52,6 +52,7 @@
       "ipc_message_macros.h",
       "ipc_message_pipe_reader.cc",
       "ipc_message_pipe_reader.h",
+      "ipc_message_protobuf_utils.h",
       "ipc_message_start.h",
       "ipc_message_templates.h",
       "ipc_message_templates_impl.h",
@@ -73,7 +74,7 @@
     ]
   }
 
-  if (is_nacl && !is_nacl_nonsfi) {
+  if (is_nacl) {
     sources += [
       "ipc_channel_nacl.cc",
       "ipc_channel_nacl.h",
@@ -95,14 +96,9 @@
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
     "//services/tracing/public/cpp",
+    "//third_party/protobuf:protobuf_lite",
   ]
 
-  if (!is_nacl_nonsfi) {
-    sources += [ "ipc_message_protobuf_utils.h" ]
-
-    public_deps += [ "//third_party/protobuf:protobuf_lite" ]
-  }
-
   deps = [ "//base" ]
 
   if (enable_ipc_fuzzer) {
@@ -261,6 +257,7 @@
       "ipc_channel_proxy_unittest.cc",
       "ipc_channel_reader_unittest.cc",
       "ipc_fuzzing_tests.cc",
+      "ipc_message_protobuf_utils_unittest.cc",
       "ipc_message_unittest.cc",
       "ipc_message_utils_unittest.cc",
       "ipc_mojo_bootstrap_unittest.cc",
@@ -302,10 +299,6 @@
         "sync_socket_unittest.cc",
       ]
     }
-
-    if (!is_nacl_nonsfi) {
-      sources += [ "ipc_message_protobuf_utils_unittest.cc" ]
-    }
   }
 
   test("ipc_perftests") {
diff --git a/ipc/ipc_message_protobuf_utils.h b/ipc/ipc_message_protobuf_utils.h
index 0168b15..f06a176 100644
--- a/ipc/ipc_message_protobuf_utils.h
+++ b/ipc/ipc_message_protobuf_utils.h
@@ -7,12 +7,6 @@
 
 #include "build/build_config.h"
 
-#if defined(OS_NACL_NONSFI)
-static_assert(false,
-              "ipc_message_protobuf_utils is not able to work with "
-              "nacl_nonsfi configuration.");
-#endif
-
 #include "base/pickle.h"
 #include "ipc/ipc_param_traits.h"
 #include "ipc/ipc_message_utils.h"
diff --git a/ipc/ipc_message_protobuf_utils_unittest.cc b/ipc/ipc_message_protobuf_utils_unittest.cc
index 61421c6e..66930c3 100644
--- a/ipc/ipc_message_protobuf_utils_unittest.cc
+++ b/ipc/ipc_message_protobuf_utils_unittest.cc
@@ -4,12 +4,6 @@
 
 #include "build/build_config.h"
 
-#if defined(OS_NACL_NONSFI)
-static_assert(false,
-              "ipc_message_protobuf_utils is not able to work with nacl_nonsfi "
-              "configuration.");
-#endif
-
 #include "ipc/ipc_message_protobuf_utils.h"
 
 #include <initializer_list>
diff --git a/mojo/core/BUILD.gn b/mojo/core/BUILD.gn
index 14a0439..d0794f6 100644
--- a/mojo/core/BUILD.gn
+++ b/mojo/core/BUILD.gn
@@ -119,7 +119,7 @@
     }
 
     if (is_posix && !is_mac) {
-      if (!is_nacl || is_nacl_nonsfi) {
+      if (!is_nacl) {
         sources += [
           "broker_posix.cc",
           "channel_posix.cc",
@@ -141,7 +141,7 @@
       sources += [ "channel_mac.cc" ]
     }
 
-    if (!is_nacl || is_nacl_nonsfi) {
+    if (!is_nacl) {
       sources += [
         "broker_host.cc",
         "broker_host.h",
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index 851b5f82..60a21b91 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -230,7 +230,7 @@
     ]
   }
 
-  if (enable_ipc_fuzzer && !is_nacl_nonsfi) {
+  if (enable_ipc_fuzzer) {
     sources += [
       "lib/message_dumper.cc",
       "message_dumper.h",
diff --git a/mojo/public/cpp/platform/BUILD.gn b/mojo/public/cpp/platform/BUILD.gn
index ba740d6..7ac7fe1 100644
--- a/mojo/public/cpp/platform/BUILD.gn
+++ b/mojo/public/cpp/platform/BUILD.gn
@@ -22,7 +22,7 @@
     "platform_handle.cc",
   ]
 
-  if (is_posix && !is_mac && (!is_nacl || is_nacl_nonsfi)) {
+  if (is_posix && !is_mac && !is_nacl) {
     public += [ "socket_utils_posix.h" ]
     sources += [ "socket_utils_posix.cc" ]
   }
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni
index ca652e3b..842160a 100644
--- a/mojo/public/tools/bindings/mojom.gni
+++ b/mojo/public/tools/bindings/mojom.gni
@@ -70,7 +70,7 @@
     enable_mojom_message_id_scrambling &&
     (is_mac || is_win ||
      (is_linux && !is_chromeos_ash && !is_chromecast && !is_chromeos_lacros) ||
-     ((enable_nacl || is_nacl || is_nacl_nonsfi) &&
+     ((enable_nacl || is_nacl) &&
       (target_os != "chromeos" && !chromeos_is_browser_only)))
 
 _mojom_tools_root = "//mojo/public/tools"
diff --git a/native_client_sdk/src/build_tools/build_artifacts.py b/native_client_sdk/src/build_tools/build_artifacts.py
index 7be4e0a..f8303d5 100755
--- a/native_client_sdk/src/build_tools/build_artifacts.py
+++ b/native_client_sdk/src/build_tools/build_artifacts.py
@@ -228,10 +228,6 @@
 
   if PLATFORM == 'linux':
     files.append(['nacl_helper_bootstrap', 'nacl_helper_bootstrap_x86_32'])
-    files.append(['nonsfi_loader_newlib_x32_nonsfi.nexe',
-                  'nonsfi_loader_x86_32'])
-    files.append(['nonsfi_loader_newlib_arm_nonsfi.nexe',
-                  'nonsfi_loader_arm'])
 
   # Add .exe extensions to all windows tools
   for pair in files:
diff --git a/native_client_sdk/src/build_tools/build_sdk.py b/native_client_sdk/src/build_tools/build_sdk.py
index 440bbcb8..035ba47 100755
--- a/native_client_sdk/src/build_tools/build_sdk.py
+++ b/native_client_sdk/src/build_tools/build_sdk.py
@@ -342,8 +342,7 @@
 
 
   if platform == 'linux':
-    tools_files_x86 += [['nonsfi_loader', 'nonsfi_loader_x86_32'],
-                        ['nacl_helper_bootstrap',
+    tools_files_x86 += [['nacl_helper_bootstrap',
                          'nacl_helper_bootstrap_x86_32']]
     tools_files_x64 += [['nacl_helper_bootstrap',
                          'nacl_helper_bootstrap_x86_64']]
@@ -356,7 +355,6 @@
       ]
       tools_files_arm += [
         ['nacl_helper_bootstrap', 'nacl_helper_bootstrap_arm'],
-        ['nonsfi_loader', 'nonsfi_loader_arm'],
         ['sel_ldr', 'sel_ldr_arm']
       ]
 
diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list
index 4022d8e..df568a5 100644
--- a/native_client_sdk/src/build_tools/sdk_files.list
+++ b/native_client_sdk/src/build_tools/sdk_files.list
@@ -483,8 +483,6 @@
 tools/nacl_llvm.mk
 tools/ncval${EXE_EXT}
 tools/ncval.py
-[linux]tools/nonsfi_loader_arm${EXE_EXT}
-[linux]tools/nonsfi_loader_x86_32${EXE_EXT}
 tools/oshelpers.py
 [linux]tools/qemu-arm
 tools/run.py
diff --git a/ppapi/BUILD.gn b/ppapi/BUILD.gn
index b37a1ef..c2dab92d 100644
--- a/ppapi/BUILD.gn
+++ b/ppapi/BUILD.gn
@@ -421,10 +421,5 @@
       data_deps +=
           [ ":ppapi_nacl_tests(//build/toolchain/nacl:glibc_${target_cpu})" ]
     }
-
-    if ((is_linux || is_chromeos) && enable_nacl_nonsfi) {
-      data_deps +=
-          [ ":ppapi_nacl_tests(//build/toolchain/nacl:newlib_pnacl_nonsfi)" ]
-    }
   }
 }
diff --git a/ppapi/native_client/nacl_test_data.gni b/ppapi/native_client/nacl_test_data.gni
index 9e3a846..d179121 100644
--- a/ppapi/native_client/nacl_test_data.gni
+++ b/ppapi/native_client/nacl_test_data.gni
@@ -9,11 +9,7 @@
 assert(enable_nacl)
 
 if (current_cpu == "pnacl") {
-  if (is_nacl_nonsfi) {
-    nacl_toolchain_variant = "nonsfi"
-  } else {
-    nacl_toolchain_variant = "pnacl"
-  }
+  nacl_toolchain_variant = "pnacl"
 } else if (is_nacl_glibc) {
   nacl_toolchain_variant = "glibc"
 } else {
@@ -60,7 +56,7 @@
     if (defined(invoker.pretranslate_pexe)) {
       pretranslate_pexe = invoker.pretranslate_pexe
     } else {
-      pretranslate_pexe = is_nacl_nonsfi
+      pretranslate_pexe = false
     }
   } else {
     pretranslate_pexe = false
@@ -70,7 +66,7 @@
   # toolchain context where is_win==false because current_os=="nacl".
   # It tests target_cpu rather than current_cpu because it's also
   # needed in the current_cpu=="pnacl" && pretranslate_pexe case.
-  if (target_os == "win" && target_cpu == "x86" && !is_nacl_nonsfi &&
+  if (target_os == "win" && target_cpu == "x86" &&
       (current_cpu == "x86" || pretranslate_pexe)) {
     # x86 Windows builds of Chrome run on both x86 Windows and x64
     # Windows.  On x64 Windows, only x64 NaCl is supported, so those
@@ -119,7 +115,7 @@
   }
   nexe_target_name = target_name + "_nexe"
   nexe_copy_target_name = target_name + "_copy_nexe"
-  if (current_cpu == "pnacl" && !is_nacl_nonsfi) {
+  if (current_cpu == "pnacl") {
     if (defined(invoker.debug_pexe) && invoker.debug_pexe) {
       pexe_copy_debug_target_name = target_name + "_copy_pexe_debug"
     }
@@ -147,11 +143,7 @@
   } else {
     target_dir = root_build_dir
     if (generate_nmf) {
-      if (is_nacl_nonsfi) {
-        nacl_toolchain_name = "pnacl_${nacl_toolchain_variant}"
-      } else {
-        nacl_toolchain_name = nacl_toolchain_variant
-      }
+      nacl_toolchain_name = nacl_toolchain_variant
       nmf_name = "${output_name}_${nacl_toolchain_name}"
     }
   }
@@ -195,53 +187,35 @@
 
         pexe = get_label_info(tests, "root_out_dir") +
                "/${suffixed_output_name}.pexe"
-        if (translate_cpu == "x86" ||
-            (is_nacl_nonsfi &&
-             (translate_cpu == "x86" || translate_cpu == "x64"))) {
+        if (translate_cpu == "x86") {
           nmf_cpu = "x32"
         } else {
           nmf_cpu = translate_cpu
         }
-        if (is_nacl_nonsfi) {
-          suffix = "pnacl_newlib_${nmf_cpu}_nonsfi"
-        } else {
-          suffix = "pnacl_newlib_${nmf_cpu}"
-        }
+        suffix = "pnacl_newlib_${nmf_cpu}"
         nexe = "${root_out_dir}/${output_name}_${suffix}.nexe"
 
         script = "${nacl_toolchain_bindir}/pydir/loader.py"
         sources = [ pexe ]
         outputs = [ nexe ]
 
-        if (is_nacl_nonsfi) {
-          if (translate_cpu == "x86" || translate_cpu == "x64") {
-            arch = "x86-32-nonsfi"
-          } else if (translate_cpu == "arm") {
-            arch = "arm-nonsfi"
-          }
-        } else {
-          # TODO(phosek): remove the following once change 1360243003 is rolled
-          # into Chrome and use translate_cpu directly.
-          if (translate_cpu == "x86") {
-            arch = "i686"
-          } else if (translate_cpu == "x64") {
-            arch = "x86-64"
-          } else if (translate_cpu == "arm") {
-            arch = "armv7"
-          } else if (translate_cpu == "mipsel") {
-            arch = "mipsel"
-          }
+        # TODO(phosek): remove the following once change 1360243003 is rolled
+        # into Chrome and use translate_cpu directly.
+        if (translate_cpu == "x86") {
+          arch = "i686"
+        } else if (translate_cpu == "x64") {
+          arch = "x86-64"
+        } else if (translate_cpu == "arm") {
+          arch = "armv7"
+        } else if (translate_cpu == "mipsel") {
+          arch = "mipsel"
         }
 
         # The pre-translated object file has to be linked with an IRT shim to
         # get a runnable nexe. This is handled by pnacl-translate, which passes
         # -l:libpnacl_irt_shim.a to native linker, and we need to ensure the
         # linker can find the correct library.
-        if (is_nacl_nonsfi) {
-          pnacl_irt_shim = "//ppapi/native_client/src/untrusted/pnacl_irt_shim:aot(//build/toolchain/nacl:newlib_pnacl_nonsfi)"
-        } else {
-          pnacl_irt_shim = "//ppapi/native_client/src/untrusted/pnacl_irt_shim:aot(//build/toolchain/nacl:clang_newlib_${translate_cpu})"
-        }
+        pnacl_irt_shim = "//ppapi/native_client/src/untrusted/pnacl_irt_shim:aot(//build/toolchain/nacl:clang_newlib_${translate_cpu})"
 
         args = [
           "pnacl-translate",
@@ -310,7 +284,7 @@
     }
   }
 
-  if (current_cpu == "pnacl" && !is_nacl_nonsfi) {
+  if (current_cpu == "pnacl") {
     if (defined(invoker.debug_pexe) && invoker.debug_pexe) {
       copy(pexe_copy_debug_target_name) {
         visibility = [ ":$final_target_name" ]
@@ -323,27 +297,16 @@
   }
 
   if (generate_nmf) {
-    if (is_nacl_nonsfi) {
-      generate_nonsfi_test_nmf(nmf_target_name) {
-        visibility = [ ":$final_target_name" ]
-        forward_variables_from(invoker, [ "nmfflags" ])
-        nmf = "${target_dir}/${nmf_name}.nmf"
-        files = get_target_outputs(":$nexe_copy_target_name")
-        executable = files[0]
-        deps = [ ":$nexe_copy_target_name" ]
+    generate_nmf(nmf_target_name) {
+      visibility = [ ":$final_target_name" ]
+      forward_variables_from(invoker, [ "nmfflags" ])
+      nmf = "${target_dir}/${nmf_name}.nmf"
+      executables = get_target_outputs(":$nexe_copy_target_name")
+      if (is_nacl_glibc) {
+        lib_prefix = "${output_name}_libs"
+        stage_dependencies = target_dir
       }
-    } else {
-      generate_nmf(nmf_target_name) {
-        visibility = [ ":$final_target_name" ]
-        forward_variables_from(invoker, [ "nmfflags" ])
-        nmf = "${target_dir}/${nmf_name}.nmf"
-        executables = get_target_outputs(":$nexe_copy_target_name")
-        if (is_nacl_glibc) {
-          lib_prefix = "${output_name}_libs"
-          stage_dependencies = target_dir
-        }
-        deps = [ ":$nexe_copy_target_name" ]
-      }
+      deps = [ ":$nexe_copy_target_name" ]
     }
   }
 
@@ -357,7 +320,7 @@
 
   group(final_target_name) {
     data_deps = [ ":$nexe_copy_target_name" ]
-    if (current_cpu == "pnacl" && !is_nacl_nonsfi) {
+    if (current_cpu == "pnacl") {
       if (defined(invoker.debug_pexe) && invoker.debug_pexe) {
         data_deps += [ ":$pexe_copy_debug_target_name" ]
       }
diff --git a/ppapi/proxy/BUILD.gn b/ppapi/proxy/BUILD.gn
index 4420050..13e2afeb 100644
--- a/ppapi/proxy/BUILD.gn
+++ b/ppapi/proxy/BUILD.gn
@@ -241,6 +241,7 @@
     "//mojo/core/embedder",
     "//ppapi/c",
     "//ppapi/shared_impl",
+    "//third_party/icu",
     "//ui/gfx/geometry",
     "//ui/gfx/ipc/geometry",
   ]
@@ -254,10 +255,6 @@
       "//ui/surface",
     ]
   }
-
-  if (!is_nacl_nonsfi) {
-    deps += [ "//third_party/icu" ]
-  }
 }
 
 source_set("common") {
diff --git a/ppapi/shared_impl/BUILD.gn b/ppapi/shared_impl/BUILD.gn
index 5d1c48b..65d2f2f 100644
--- a/ppapi/shared_impl/BUILD.gn
+++ b/ppapi/shared_impl/BUILD.gn
@@ -104,15 +104,12 @@
     "//ppapi/c:c",
     "//ppapi/thunk:headers",
     "//third_party/icu:icuuc",
+    "//url",
   ]
 
   if (!is_nacl) {
     deps += [ "//skia" ]
   }
-
-  if (!is_nacl_nonsfi) {
-    deps += [ "//url" ]
-  }
 }
 
 component("shared_impl") {
@@ -232,6 +229,7 @@
   ]
 
   deps = [
+    "//base/third_party/dynamic_annotations",
     "//build:chromeos_buildflags",
     "//device/gamepad/public/cpp:shared_with_blink",
     "//gpu/command_buffer/client",
@@ -250,10 +248,6 @@
     ]
   }
 
-  if (!is_nacl_nonsfi) {
-    deps += [ "//base/third_party/dynamic_annotations" ]
-  }
-
   if (is_mac) {
     frameworks = [ "QuartzCore.framework" ]
   }
diff --git a/ppapi/tests/create_nonsfi_test_nmf.py b/ppapi/tests/create_nonsfi_test_nmf.py
deleted file mode 100755
index a2a8f9f..0000000
--- a/ppapi/tests/create_nonsfi_test_nmf.py
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2014 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.
-
-"""Simple tool to generate NMF file by just reformatting given arguments.
-
-This tool is similar to native_client_sdk/src/tools/create_nmf.py.
-create_nmf.py handles most cases, with the exception of Non-SFI nexes.
-create_nmf.py tries to auto-detect nexe and pexe types based on their contents,
-but it does not work for Non-SFI nexes (which don't have a marker to
-distinguish them from SFI nexes).
-
-This script simply reformats the command line arguments into NMF JSON format.
-"""
-
-import argparse
-import collections
-import json
-import logging
-import os
-import sys
-
-_FILES_KEY = 'files'
-_PORTABLE_KEY = 'portable'
-_PROGRAM_KEY = 'program'
-_URL_KEY = 'url'
-
-def ParseArgs():
-  parser = argparse.ArgumentParser()
-  parser.add_argument(
-      '--program', metavar='FILE', help='Main program nexe')
-  parser.add_argument(
-      '--arch', metavar='ARCH', choices=('x86-32', 'x86-64', 'arm'),
-      help='The archtecture of main program nexe')
-  # To keep compatibility with create_nmf.py, we use -x and --extra-files
-  # as flags.
-  parser.add_argument(
-      '-x', '--extra-files', action='append', metavar='KEY:FILE', default=[],
-      help=('Add extra key:file tuple to the "files" '
-            'section of the .nmf'))
-  parser.add_argument(
-      '--output', metavar='FILE', help='Path to the output nmf file.')
-
-  return parser.parse_args()
-
-
-def BuildNmfMap(root_path, program, arch, extra_files):
-  """Build simple map representing nmf json."""
-  nonsfi_key = arch + '-nonsfi'
-  result = {
-    _PROGRAM_KEY: {
-      nonsfi_key: {
-        # The program path is relative to the root_path.
-        _URL_KEY: os.path.relpath(program, root_path)
-      },
-    }
-  }
-
-  if extra_files:
-    files = {}
-    for named_file in extra_files:
-      name, path = named_file.split(':', 1)
-      files[name] = {
-        _PORTABLE_KEY: {
-          # Note: use path as is, unlike program path.
-          _URL_KEY: path
-        }
-      }
-    if files:
-      result[_FILES_KEY] = files
-
-  return result
-
-
-def OutputNmf(nmf_map, output_path):
-  """Writes the nmf to an output file at given path in JSON format."""
-  with open(output_path, 'w') as output:
-    json.dump(nmf_map, output, indent=2)
-
-
-def main():
-  args = ParseArgs()
-  if not args.program:
-    logging.error('--program is not specified.')
-    sys.exit(1)
-  if not args.arch:
-    logging.error('--arch is not specified.')
-    sys.exit(1)
-  if not args.output:
-    logging.error('--output is not specified.')
-    sys.exit(1)
-
-  nmf_map = BuildNmfMap(os.path.dirname(args.output),
-                        args.program, args.arch, args.extra_files)
-  OutputNmf(nmf_map, args.output)
-
-
-if __name__ == '__main__':
-  main()
diff --git a/ppapi/tests/extensions/BUILD.gn b/ppapi/tests/extensions/BUILD.gn
index 3190dca..712e918 100644
--- a/ppapi/tests/extensions/BUILD.gn
+++ b/ppapi/tests/extensions/BUILD.gn
@@ -19,14 +19,9 @@
     ":ppapi_tests_extensions_popup($newlib)",
     ":ppapi_tests_extensions_socket_permissions($newlib)",
   ]
-  if ((target_cpu == "x86" || target_cpu == "x64") &&
-      (is_linux || is_chromeos) && enable_nacl_nonsfi) {
-    nonsfi = "//build/toolchain/nacl:newlib_pnacl_nonsfi"
-    data_deps += [ ":ppapi_tests_extensions_packaged_app($nonsfi)" ]
-  }
 }
 
-if (is_nacl && !is_nacl_nonsfi) {
+if (is_nacl) {
   nacl_test_data("ppapi_tests_extensions_background_keepalive") {
     sources = [ "background_keepalive/background.cc" ]
     deps = [ "//ppapi/cpp" ]
diff --git a/ppapi/tests/test_case.html b/ppapi/tests/test_case.html
index 374ada6f..2202566 100644
--- a/ppapi/tests/test_case.html
+++ b/ppapi/tests/test_case.html
@@ -279,11 +279,6 @@
     obj.setAttribute("src", "ppapi_nacl_tests_pnacl.nmf");
     obj.setAttribute("type", "application/x-nacl");
     obj.setAttribute("mode", mode);
-  } else if (mode == "nacl_pnacl_nonsfi") {
-    obj = document.createElement("EMBED");
-    obj.setAttribute("src", "ppapi_nacl_tests_pnacl_nonsfi.nmf");
-    obj.setAttribute("type", "application/x-nacl");
-    obj.setAttribute("mode", mode);
   } else if (mode == "mojo") {
     obj = document.createElement("EMBED");
     obj.setAttribute("src",
diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc
index 13aaae4..b330c43 100644
--- a/remoting/host/client_session_unittest.cc
+++ b/remoting/host/client_session_unittest.cc
@@ -50,9 +50,9 @@
 using protocol::MockVideoStub;
 using protocol::SessionConfig;
 using protocol::test::EqualsClipboardEvent;
+using protocol::test::EqualsKeyEvent;
 using protocol::test::EqualsMouseButtonEvent;
 using protocol::test::EqualsMouseMoveEvent;
-using protocol::test::EqualsKeyEvent;
 
 using testing::_;
 using testing::AtLeast;
@@ -69,12 +69,12 @@
   if (!arg.has_capabilities())
     return false;
 
-  std::vector<std::string> words_args = base::SplitString(
-      arg.capabilities(), " ", base::KEEP_WHITESPACE,
-      base::SPLIT_WANT_NONEMPTY);
-  std::vector<std::string> words_expected = base::SplitString(
-      expected_capabilities, " ", base::KEEP_WHITESPACE,
-      base::SPLIT_WANT_NONEMPTY);
+  std::vector<std::string> words_args =
+      base::SplitString(arg.capabilities(), " ", base::KEEP_WHITESPACE,
+                        base::SPLIT_WANT_NONEMPTY);
+  std::vector<std::string> words_expected =
+      base::SplitString(expected_capabilities, " ", base::KEEP_WHITESPACE,
+                        base::SPLIT_WANT_NONEMPTY);
 
   for (const auto& word : words_expected) {
     if (std::find(words_args.begin(), words_args.end(), word) ==
@@ -301,22 +301,22 @@
 
   int x_min, x_max, y_min, y_max;
   bool initialized = false;
-  for (auto& disp : displays_.displays()) {
-    int disp_x_max = disp->x + disp->width;
-    int disp_y_max = disp->y + disp->height;
+  for (const auto& disp : displays_.displays()) {
+    int disp_x_max = disp.x + disp.width;
+    int disp_y_max = disp.y + disp.height;
     if (!initialized) {
-      x_min = disp->x;
+      x_min = disp.x;
       x_max = disp_x_max;
-      y_min = disp->y;
+      y_min = disp.y;
       y_max = disp_y_max;
       initialized = true;
     } else {
-      if (disp->x < x_min)
-        x_min = disp->x;
+      if (disp.x < x_min)
+        x_min = disp.x;
       if (disp_x_max > x_max)
         x_max = disp_x_max;
-      if (disp->y < y_min)
-        y_min = disp->y;
+      if (disp.y < y_min)
+        y_min = disp.y;
       if (disp_y_max > y_max)
         y_max = disp_y_max;
     }
diff --git a/remoting/host/desktop_capturer_proxy.cc b/remoting/host/desktop_capturer_proxy.cc
index f8f5e5e..54c5f5d 100644
--- a/remoting/host/desktop_capturer_proxy.cc
+++ b/remoting/host/desktop_capturer_proxy.cc
@@ -201,12 +201,11 @@
 bool DesktopCapturerProxy::SelectSource(SourceId id_index) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  SourceId id = -1;
-  if (id_index >= 0 && id_index < desktop_display_info_.NumDisplays()) {
-    const DisplayGeometry* display =
-        desktop_display_info_.displays()[id_index].get();
-    id = display->id;
-  }
+  const DisplayGeometry* display =
+      desktop_display_info_.GetDisplayInfo(id_index);
+
+  SourceId id = (display ? display->id : webrtc::kFullDesktopScreenId);
+
   capture_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&Core::SelectSource, base::Unretained(core_.get()), id));
@@ -243,15 +242,14 @@
   LOG(INFO) << "DCP::OnDisplayInfoLoaded";
   for (const auto& display : desktop_display_info_.displays()) {
     protocol::VideoTrackLayout* track = layout->add_video_track();
-    track->set_position_x(display->x);
-    track->set_position_y(display->y);
-    track->set_width(display->width);
-    track->set_height(display->height);
-    track->set_x_dpi(display->dpi);
-    track->set_y_dpi(display->dpi);
-    LOG(INFO) << "   Display: " << display->x << "," << display->y << " "
-              << display->width << "x" << display->height << " @ "
-              << display->dpi;
+    track->set_position_x(display.x);
+    track->set_position_y(display.y);
+    track->set_width(display.width);
+    track->set_height(display.height);
+    track->set_x_dpi(display.dpi);
+    track->set_y_dpi(display.dpi);
+    LOG(INFO) << "   Display: " << display.x << "," << display.y << " "
+              << display.width << "x" << display.height << " @ " << display.dpi;
   }
   client_session_control_->OnDesktopDisplayChanged(std::move(layout));
 }
diff --git a/remoting/host/desktop_display_info.cc b/remoting/host/desktop_display_info.cc
index 26b542b..460c6c1 100644
--- a/remoting/host/desktop_display_info.cc
+++ b/remoting/host/desktop_display_info.cc
@@ -19,16 +19,16 @@
 bool DesktopDisplayInfo::operator==(const DesktopDisplayInfo& other) {
   if (other.displays_.size() == displays_.size()) {
     for (size_t display = 0; display < displays_.size(); display++) {
-      const DisplayGeometry* this_display = displays_[display].get();
-      const DisplayGeometry* other_display = other.displays_[display].get();
-      if (this_display->id != other_display->id ||
-          this_display->x != other_display->x ||
-          this_display->y != other_display->y ||
-          this_display->width != other_display->width ||
-          this_display->height != other_display->height ||
-          this_display->dpi != other_display->dpi ||
-          this_display->bpp != other_display->bpp ||
-          this_display->is_default != other_display->is_default) {
+      const DisplayGeometry& this_display = displays_[display];
+      const DisplayGeometry& other_display = other.displays_[display];
+      if (this_display.id != other_display.id ||
+          this_display.x != other_display.x ||
+          this_display.y != other_display.y ||
+          this_display.width != other_display.width ||
+          this_display.height != other_display.height ||
+          this_display.dpi != other_display.dpi ||
+          this_display.bpp != other_display.bpp ||
+          this_display.is_default != other_display.is_default) {
         return false;
       }
     }
@@ -68,7 +68,7 @@
 const DisplayGeometry* DesktopDisplayInfo::GetDisplayInfo(unsigned int id) {
   if (id < 0 || id >= displays_.size())
     return nullptr;
-  return displays_[id].get();
+  return &displays_[id];
 }
 
 // Calculate the offset from the origin of the desktop to the origin of the
@@ -117,18 +117,17 @@
     return webrtc::DesktopVector();
   }
 
-  const DisplayGeometry* disp_info = displays_[disp_index].get();
-  webrtc::DesktopVector origin(disp_info->x, disp_info->y);
+  const DisplayGeometry& disp_info = displays_[disp_index];
+  webrtc::DesktopVector origin(disp_info.x, disp_info.y);
 
   // Find topleft-most display coordinate. This is the topleft of the desktop.
   int dx = 0;
   int dy = 0;
-  for (auto& display : displays_) {
-    const DisplayGeometry* disp = display.get();
-    if (disp->x < dx)
-      dx = disp->x;
-    if (disp->y < dy)
-      dy = disp->y;
+  for (const auto& display : displays_) {
+    if (display.x < dx)
+      dx = display.x;
+    if (display.y < dy)
+      dy = display.y;
   }
   webrtc::DesktopVector topleft(dx, dy);
 
@@ -148,20 +147,21 @@
 #endif  // defined(OS_APPLE)
 }
 
-void DesktopDisplayInfo::AddDisplay(std::unique_ptr<DisplayGeometry> display) {
-  displays_.push_back(std::move(display));
+void DesktopDisplayInfo::AddDisplay(const DisplayGeometry& display) {
+  displays_.push_back(display);
 }
 
-void DesktopDisplayInfo::AddDisplayFrom(protocol::VideoTrackLayout track) {
-  std::unique_ptr<DisplayGeometry> display(new DisplayGeometry());
-  display->x = track.position_x();
-  display->y = track.position_y();
-  display->width = track.width();
-  display->height = track.height();
-  display->dpi = track.x_dpi();
-  display->bpp = 24;
-  display->is_default = false;
-  displays_.push_back(std::move(display));
+void DesktopDisplayInfo::AddDisplayFrom(
+    const protocol::VideoTrackLayout& track) {
+  DisplayGeometry display;
+  display.x = track.position_x();
+  display.y = track.position_y();
+  display.width = track.width();
+  display.height = track.height();
+  display.dpi = track.x_dpi();
+  display.bpp = 24;
+  display.is_default = false;
+  displays_.push_back(display);
 }
 
 }  // namespace remoting
diff --git a/remoting/host/desktop_display_info.h b/remoting/host/desktop_display_info.h
index 696a56d..3f5742a 100644
--- a/remoting/host/desktop_display_info.h
+++ b/remoting/host/desktop_display_info.h
@@ -42,19 +42,17 @@
   webrtc::DesktopVector CalcDisplayOffset(webrtc::ScreenId id);
 
   // Add a new display with the given info to the display list.
-  void AddDisplay(std::unique_ptr<DisplayGeometry> display);
+  void AddDisplay(const DisplayGeometry& display);
 
-  void AddDisplayFrom(protocol::VideoTrackLayout track);
+  void AddDisplayFrom(const protocol::VideoTrackLayout& track);
 
   bool operator==(const DesktopDisplayInfo& other);
   bool operator!=(const DesktopDisplayInfo& other);
 
-  const std::vector<std::unique_ptr<DisplayGeometry>>& displays() const {
-    return displays_;
-  }
+  const std::vector<DisplayGeometry>& displays() const { return displays_; }
 
  private:
-  std::vector<std::unique_ptr<DisplayGeometry>> displays_;
+  std::vector<DisplayGeometry> displays_;
 };
 
 }  // namespace remoting
diff --git a/remoting/host/desktop_display_info_loader_mac.mm b/remoting/host/desktop_display_info_loader_mac.mm
index 9402c286..8548a62f 100644
--- a/remoting/host/desktop_display_info_loader_mac.mm
+++ b/remoting/host/desktop_display_info_loader_mac.mm
@@ -34,13 +34,10 @@
   int main_display_height = 0;
 
   for (NSUInteger i = 0; i < [screens count]; ++i) {
-    auto info = std::make_unique<DisplayGeometry>();
-
     NSScreen* screen = screens[i];
     NSDictionary* device = [screen deviceDescription];
     CGDirectDisplayID id =
         static_cast<CGDirectDisplayID>([device[@"NSScreenNumber"] intValue]);
-    info->id = id;
 
     float dsf = 1.0f;
     if ([screen respondsToSelector:@selector(backingScaleFactor)])
@@ -51,24 +48,25 @@
     int y = bounds.origin.y;
     int height = bounds.size.height;
 
+    bool is_default = false;
     if (i == 0) {
       DCHECK(x == 0);
       DCHECK(y == 0);
-      info->is_default = true;
+      is_default = true;
       main_display_height = height;
-    } else {
-      info->is_default = false;
     }
 
-    info->x = x;
+    DisplayGeometry info;
+    info.id = id;
+    info.x = x;
     // Convert origin from lower left to upper left (based on main display).
-    info->y = main_display_height - y - height;
-    info->width = bounds.size.width;
-    info->height = height;
-    info->dpi = (int)(kDefaultScreenDpi * dsf);
-    info->bpp = 24;
-
-    result.AddDisplay(std::move(info));
+    info.y = main_display_height - y - height;
+    info.width = bounds.size.width;
+    info.height = height;
+    info.dpi = (int)(kDefaultScreenDpi * dsf);
+    info.bpp = 24;
+    info.is_default = is_default;
+    result.AddDisplay(info);
   }
   return result;
 }
diff --git a/remoting/host/desktop_display_info_loader_win.cc b/remoting/host/desktop_display_info_loader_win.cc
index c61882fb..4395c37 100644
--- a/remoting/host/desktop_display_info_loader_win.cc
+++ b/remoting/host/desktop_display_info_loader_win.cc
@@ -23,9 +23,6 @@
 
   BOOL enum_result = TRUE;
   for (int device_index = 0;; ++device_index) {
-    auto info = std::make_unique<DisplayGeometry>();
-    info->id = device_index;
-
     DISPLAY_DEVICE device = {};
     device.cb = sizeof(device);
     enum_result = EnumDisplayDevices(NULL, device_index, &device, 0);
@@ -38,9 +35,9 @@
     if (!(device.StateFlags & DISPLAY_DEVICE_ACTIVE))
       continue;
 
-    info->is_default = false;
+    bool is_default = false;
     if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
-      info->is_default = true;
+      is_default = true;
 
     // Get additional info about device.
     DEVMODE devmode;
@@ -48,13 +45,16 @@
     EnumDisplaySettingsEx(device.DeviceName, ENUM_CURRENT_SETTINGS, &devmode,
                           0);
 
-    info->x = devmode.dmPosition.x;
-    info->y = devmode.dmPosition.y;
-    info->width = devmode.dmPelsWidth;
-    info->height = devmode.dmPelsHeight;
-    info->dpi = devmode.dmLogPixels;
-    info->bpp = devmode.dmBitsPerPel;
-    result.AddDisplay(std::move(info));
+    DisplayGeometry info;
+    info.id = device_index;
+    info.is_default = is_default;
+    info.x = devmode.dmPosition.x;
+    info.y = devmode.dmPosition.y;
+    info.width = devmode.dmPelsWidth;
+    info.height = devmode.dmPelsHeight;
+    info.dpi = devmode.dmLogPixels;
+    info.bpp = devmode.dmBitsPerPel;
+    result.AddDisplay(info);
   }
 
   return result;
diff --git a/remoting/host/desktop_display_info_loader_x11.cc b/remoting/host/desktop_display_info_loader_x11.cc
index 4104c30..26c4fbe 100644
--- a/remoting/host/desktop_display_info_loader_x11.cc
+++ b/remoting/host/desktop_display_info_loader_x11.cc
@@ -90,27 +90,27 @@
   DesktopDisplayInfo result;
 
   for (const auto& monitor : monitors_) {
-    auto info = std::make_unique<DisplayGeometry>();
+    DisplayGeometry info;
 
     // webrtc::ScreenCapturerX11 uses the |name| Atom as the monitor ID.
-    info->id = static_cast<int32_t>(monitor.name);
-    info->is_default = monitor.primary;
-    info->x = monitor.x;
-    info->y = monitor.y;
-    info->width = monitor.width;
-    info->height = monitor.height;
-    info->dpi = kDefaultScreenDpi;
-    info->bpp = 24;
+    info.id = static_cast<int32_t>(monitor.name);
+    info.is_default = monitor.primary;
+    info.x = monitor.x;
+    info.y = monitor.y;
+    info.width = monitor.width;
+    info.height = monitor.height;
+    info.dpi = kDefaultScreenDpi;
+    info.bpp = 24;
 
     // Calculate DPI if possible, using width in millimeters.
     if (monitor.width_in_millimeters != 0) {
       double pixelsPerMillimeter =
           static_cast<double>(monitor.width) / monitor.width_in_millimeters;
       double pixelsPerInch = pixelsPerMillimeter * kMillimetersPerInch;
-      info->dpi = base::ClampRound(pixelsPerInch);
+      info.dpi = base::ClampRound(pixelsPerInch);
     }
 
-    result.AddDisplay(std::move(info));
+    result.AddDisplay(info);
   }
   return result;
 }
diff --git a/remoting/host/desktop_display_info_unittest.cc b/remoting/host/desktop_display_info_unittest.cc
index d34a2651..b01d893 100644
--- a/remoting/host/desktop_display_info_unittest.cc
+++ b/remoting/host/desktop_display_info_unittest.cc
@@ -12,16 +12,15 @@
 
 class DesktopDisplayInfoTest : public testing::Test {
  public:
-  void AddDisplay(int x, int y, int width, int height) {
-    auto* display = new DisplayGeometry();
-    display->x = x;
-    display->y = y;
-    display->width = width;
-    display->height = height;
-    display->dpi = 96;
-    display->bpp = 24;
-    display->is_default = false;
-    info_.AddDisplay(std::unique_ptr<DisplayGeometry>(display));
+  void AddDisplay(int x, int y, uint32_t width, uint32_t height) {
+    info_.AddDisplay({.id = 0,
+                      .x = x,
+                      .y = y,
+                      .width = width,
+                      .height = height,
+                      .dpi = 96,
+                      .bpp = 24,
+                      .is_default = false});
   }
 
   void VerifyDisplayOffset(const base::Location& from_here,
diff --git a/sandbox/features.gni b/sandbox/features.gni
index db30ae6..ad067ada 100644
--- a/sandbox/features.gni
+++ b/sandbox/features.gni
@@ -2,8 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/nacl/config.gni")
-
 # The seccomp-bpf sandbox is only supported on six architectures
 # currently.
 # Do not disable seccomp_bpf anywhere without talking to
@@ -13,8 +11,6 @@
                    current_cpu == "arm" || current_cpu == "arm64" ||
                    current_cpu == "mipsel" || current_cpu == "mips64el")
 
-use_seccomp_bpf = use_seccomp_bpf || is_nacl_nonsfi
-
 # SSBD (Speculative Store Bypass Disable) is a mitigation of Spectre Variant 4.
 # As Spectre Variant 4 can be mitigated by site isolation, opt-out SSBD on site
 # isolation fully applied platform.
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn
index e7c6c4c1..c6e707d4 100644
--- a/sandbox/linux/BUILD.gn
+++ b/sandbox/linux/BUILD.gn
@@ -20,14 +20,6 @@
   use_base_test_suite = is_linux || is_chromeos
 }
 
-if (is_nacl_nonsfi) {
-  config("nacl_nonsfi_warnings") {
-    # There are number of platform specific functions in
-    # seccomp-bpf syscall helpers, which are not being used.
-    cflags = [ "-Wno-unused-function" ]
-  }
-}
-
 # We have two principal targets: sandbox and sandbox_linux_unittests
 # All other targets are listed as dependencies.
 # There is one notable exception: for historical reasons, chrome_sandbox is
@@ -35,10 +27,10 @@
 
 group("sandbox") {
   public_deps = [ ":sandbox_services" ]
-  if (compile_suid_client || is_nacl_nonsfi) {
+  if (compile_suid_client) {
     public_deps += [ ":suid_sandbox_client" ]
   }
-  if (use_seccomp_bpf || is_nacl_nonsfi) {
+  if (use_seccomp_bpf) {
     public_deps += [ ":seccomp_bpf" ]
   }
   if (is_android) {
@@ -53,6 +45,8 @@
     "tests/sandbox_test_runner.h",
     "tests/sandbox_test_runner_function_pointer.cc",
     "tests/sandbox_test_runner_function_pointer.h",
+    "tests/test_utils.cc",
+    "tests/test_utils.h",
     "tests/unit_tests.cc",
     "tests/unit_tests.h",
   ]
@@ -62,14 +56,7 @@
     "//testing/gtest",
   ]
 
-  if (!is_nacl_nonsfi) {
-    sources += [
-      "tests/test_utils.cc",
-      "tests/test_utils.h",
-    ]
-  }
-
-  if (use_seccomp_bpf || is_nacl_nonsfi) {
+  if (use_seccomp_bpf) {
     sources += [
       "seccomp-bpf/bpf_tester_compatibility_delegate.h",
       "seccomp-bpf/bpf_tests.h",
@@ -265,24 +252,6 @@
       "seccomp-bpf-helpers/baseline_policy_android.h",
     ]
   }
-
-  if (is_nacl_nonsfi) {
-    cflags = [ "-fgnu-inline-asm" ]
-    sources -= [
-      "bpf_dsl/bpf_dsl_forward.h",
-      "bpf_dsl/bpf_dsl_impl.h",
-      "bpf_dsl/cons.h",
-      "bpf_dsl/errorcode.h",
-      "bpf_dsl/linux_syscall_ranges.h",
-      "bpf_dsl/seccomp_macros.h",
-      "bpf_dsl/trap_registry.h",
-      "seccomp-bpf-helpers/baseline_policy.cc",
-      "seccomp-bpf-helpers/baseline_policy.h",
-      "seccomp-bpf-helpers/syscall_sets.cc",
-      "seccomp-bpf-helpers/syscall_sets.h",
-    ]
-    configs += [ ":nacl_nonsfi_warnings" ]
-  }
 }
 
 if (is_android) {
@@ -379,7 +348,7 @@
     "//base/third_party/dynamic_annotations",
   ]
 
-  if (compile_credentials || is_nacl_nonsfi) {
+  if (compile_credentials) {
     sources += [
       "services/credentials.cc",
       "services/credentials.h",
@@ -394,40 +363,7 @@
     deps += [ ":sandbox_services_headers" ]
   }
 
-  if (is_nacl_nonsfi) {
-    cflags = [ "-fgnu-inline-asm" ]
-
-    sources -= [
-      "services/init_process_reaper.cc",
-      "services/init_process_reaper.h",
-      "services/scoped_process.cc",
-      "services/scoped_process.h",
-      "services/yama.cc",
-      "services/yama.h",
-      "syscall_broker/broker_channel.cc",
-      "syscall_broker/broker_channel.h",
-      "syscall_broker/broker_client.cc",
-      "syscall_broker/broker_client.h",
-      "syscall_broker/broker_command.cc",
-      "syscall_broker/broker_command.h",
-      "syscall_broker/broker_file_permission.cc",
-      "syscall_broker/broker_file_permission.h",
-      "syscall_broker/broker_host.cc",
-      "syscall_broker/broker_host.h",
-      "syscall_broker/broker_permission_list.cc",
-      "syscall_broker/broker_permission_list.h",
-      "syscall_broker/broker_process.cc",
-      "syscall_broker/broker_process.h",
-      "syscall_broker/broker_sandbox_config.cc",
-      "syscall_broker/broker_sandbox_config.h",
-      "syscall_broker/broker_simple_message.cc",
-      "syscall_broker/broker_simple_message.h",
-      "syscall_broker/remote_syscall_arg_handler.cc",
-      "syscall_broker/remote_syscall_arg_handler.h",
-      "syscall_broker/syscall_dispatcher.cc",
-      "syscall_broker/syscall_dispatcher.h",
-    ]
-  } else if (!is_android) {
+  if (!is_android) {
     sources += [
       "services/libc_interceptor.cc",
       "services/libc_interceptor.h",
@@ -458,7 +394,7 @@
   ]
 }
 
-if (compile_suid_client || is_nacl_nonsfi) {
+if (compile_suid_client) {
   component("suid_sandbox_client") {
     sources = [
       "suid/client/setuid_sandbox_client.cc",
@@ -475,14 +411,5 @@
       "//base",
       "//base/third_party/dynamic_annotations",
     ]
-
-    if (is_nacl_nonsfi) {
-      sources -= [
-        "suid/client/setuid_sandbox_host.cc",
-        "suid/client/setuid_sandbox_host.h",
-        "suid/common/sandbox.h",
-        "suid/common/suid_unsafe_environment_variables.h",
-      ]
-    }
   }
 }
diff --git a/sandbox/linux/bpf_dsl/seccomp_macros.h b/sandbox/linux/bpf_dsl/seccomp_macros.h
index 1a407b9..961a8cf7 100644
--- a/sandbox/linux/bpf_dsl/seccomp_macros.h
+++ b/sandbox/linux/bpf_dsl/seccomp_macros.h
@@ -10,9 +10,7 @@
 // longer need to support these old Bionic versions.
 // All x86_64 builds use a new enough bionic to have sys/user.h.
 #if !defined(__BIONIC__) || defined(__x86_64__)
-#if !defined(__native_client_nonsfi__)
 #include <sys/user.h>
-#endif
 #if defined(__mips__)
 // sys/user.h in eglibc misses size_t definition
 #include <stddef.h>
@@ -51,11 +49,10 @@
 #define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
                                  8*(nr) + 0)
 
-
-#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
-// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
-// define regs_struct directly.  This can be removed once we no longer need to
-// support these old Bionic versions and PNaCl toolchain.
+#if defined(__BIONIC__)
+// Old Bionic versions don't have sys/user.h, so we just define regs_struct
+// directly.  This can be removed once we no longer need to support these old
+// Bionic versions.
 struct regs_struct {
   long int ebx;
   long int ecx;
@@ -151,10 +148,10 @@
 #define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
                                  8*(nr) + 0)
 
-#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
-// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
-// define regs_struct directly.  This can be removed once we no longer need to
-// support these old Bionic versions and PNaCl toolchain.
+#if defined(__BIONIC__)
+// Old Bionic versions don't have sys/user.h, so we just define regs_struct
+// directly.  This can be removed once we no longer need to support these old
+// Bionic versions.
 struct regs_struct {
   unsigned long uregs[18];
 };
diff --git a/sandbox/linux/seccomp-bpf/syscall.cc b/sandbox/linux/seccomp-bpf/syscall.cc
index e47e98b..2e0e810 100644
--- a/sandbox/linux/seccomp-bpf/syscall.cc
+++ b/sandbox/linux/seccomp-bpf/syscall.cc
@@ -120,14 +120,14 @@
     ".cfi_endproc\n"
     "9:.size SyscallAsm, 9b-SyscallAsm\n"
 #elif defined(__arm__)
-    // Throughout this file, we use the same mode (ARM vs. thumb)
-    // that the C++ compiler uses. This means, when transfering control
-    // from C++ to assembly code, we do not need to switch modes (e.g.
-    // by using the "bx" instruction). It also means that our assembly
-    // code should not be invoked directly from code that lives in
-    // other compilation units, as we don't bother implementing thumb
-    // interworking. That's OK, as we don't make any of the assembly
-    // symbols public. They are all local to this file.
+      // Throughout this file, we use the same mode (ARM vs. thumb)
+      // that the C++ compiler uses. This means, when transferring control
+      // from C++ to assembly code, we do not need to switch modes (e.g.
+      // by using the "bx" instruction). It also means that our assembly
+      // code should not be invoked directly from code that lives in
+      // other compilation units, as we don't bother implementing thumb
+      // interworking. That's OK, as we don't make any of the assembly
+      // symbols public. They are all local to this file.
     ".text\n"
     ".align 2\n"
     ".type SyscallAsm, %function\n"
@@ -137,12 +137,10 @@
     ".arm\n"
 #endif
     "SyscallAsm:\n"
-#if !defined(__native_client_nonsfi__)
+
     // .fnstart and .fnend pseudo operations creates unwind table.
-    // It also creates a reference to the symbol __aeabi_unwind_cpp_pr0, which
-    // is not provided by PNaCl toolchain. Disable it.
     ".fnstart\n"
-#endif
+
     "@ args = 0, pretend = 0, frame = 8\n"
     "@ frame_needed = 1, uses_anonymous_args = 0\n"
 #if defined(__thumb__)
@@ -185,11 +183,9 @@
 #else
     "2:ldmfd sp!, {fp, pc}\n"
 #endif
-#if !defined(__native_client_nonsfi__)
-    // Do not use .fnstart and .fnend for PNaCl toolchain. See above comment,
-    // for more details.
+
     ".fnend\n"
-#endif
+
     "9:.size SyscallAsm, 9b-SyscallAsm\n"
 #elif (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS))
     ".text\n"
diff --git a/sandbox/linux/seccomp-bpf/trap.cc b/sandbox/linux/seccomp-bpf/trap.cc
index 85c57c0..cb71a9b 100644
--- a/sandbox/linux/seccomp-bpf/trap.cc
+++ b/sandbox/linux/seccomp-bpf/trap.cc
@@ -167,7 +167,7 @@
 
   // Obtain the siginfo information that is specific to SIGSYS.
   struct arch_sigsys sigsys;
-#if defined(si_call_addr) && !defined(__native_client_nonsfi__)
+#if defined(si_call_addr)
   sigsys.ip = info->si_call_addr;
   sigsys.nr = info->si_syscall;
   sigsys.arch = info->si_arch;
diff --git a/sandbox/linux/services/syscall_wrappers.cc b/sandbox/linux/services/syscall_wrappers.cc
index 3bec18a..f863cd00 100644
--- a/sandbox/linux/services/syscall_wrappers.cc
+++ b/sandbox/linux/services/syscall_wrappers.cc
@@ -157,112 +157,11 @@
                  sizeof(linux_value));
 }
 
-// When this is built with PNaCl toolchain, we should always use sys_sigaction
-// below, because sigaction() provided by the toolchain is incompatible with
-// Linux's ABI.
-#if !defined(OS_NACL_NONSFI)
 int sys_sigaction(int signum,
                   const struct sigaction* act,
                   struct sigaction* oldact) {
   return sigaction(signum, act, oldact);
 }
-#else
-#if defined(ARCH_CPU_X86_FAMILY)
-
-// On x86_64, sa_restorer is required. We specify it on x86 as well in order to
-// support kernels with VDSO disabled.
-#if !defined(SA_RESTORER)
-#define SA_RESTORER 0x04000000
-#endif
-
-// XSTR(__NR_foo) expands to a string literal containing the value value of
-// __NR_foo.
-#define STR(x) #x
-#define XSTR(x) STR(x)
-
-// rt_sigreturn is a special system call that interacts with the user land
-// stack. Thus, here prologue must not be created, which implies syscall()
-// does not work properly, too. Note that rt_sigreturn does not return.
-// TODO(rickyz): These assembly functions may still break stack unwinding on
-// nonsfi NaCl builds.
-#if defined(ARCH_CPU_X86_64)
-
-extern "C" {
-  void sys_rt_sigreturn();
-}
-
-asm(
-    ".text\n"
-    "sys_rt_sigreturn:\n"
-    "mov $" XSTR(__NR_rt_sigreturn) ", %eax\n"
-    "syscall\n");
-
-#elif defined(ARCH_CPU_X86)
-extern "C" {
-  void sys_sigreturn();
-  void sys_rt_sigreturn();
-}
-
-asm(
-    ".text\n"
-    "sys_rt_sigreturn:\n"
-    "mov $" XSTR(__NR_rt_sigreturn) ", %eax\n"
-    "int $0x80\n"
-
-    "sys_sigreturn:\n"
-    "pop %eax\n"
-    "mov $" XSTR(__NR_sigreturn) ", %eax\n"
-    "int $0x80\n");
-#else
-#error "Unsupported architecture."
-#endif
-
-#undef STR
-#undef XSTR
-
-#endif  // defined(ARCH_CPU_X86_FAMILY)
-
-int sys_sigaction(int signum,
-                  const struct sigaction* act,
-                  struct sigaction* oldact) {
-  LinuxSigAction linux_act = {};
-  if (act) {
-    linux_act.kernel_handler = act->sa_handler;
-    std::memcpy(&linux_act.sa_mask, &act->sa_mask,
-                std::min(sizeof(linux_act.sa_mask), sizeof(act->sa_mask)));
-    linux_act.sa_flags = act->sa_flags;
-
-#if defined(ARCH_CPU_X86_FAMILY)
-    if (!(linux_act.sa_flags & SA_RESTORER)) {
-      linux_act.sa_flags |= SA_RESTORER;
-#if defined(ARCH_CPU_X86_64)
-      linux_act.sa_restorer = sys_rt_sigreturn;
-#elif defined(ARCH_CPU_X86)
-      linux_act.sa_restorer =
-          linux_act.sa_flags & SA_SIGINFO ? sys_rt_sigreturn : sys_sigreturn;
-#else
-#error "Unsupported architecture."
-#endif
-    }
-#endif  // defined(ARCH_CPU_X86_FAMILY)
-  }
-
-  LinuxSigAction linux_oldact = {};
-  int result = syscall(__NR_rt_sigaction, signum, act ? &linux_act : nullptr,
-                       oldact ? &linux_oldact : nullptr,
-                       sizeof(LinuxSigSet));
-
-  if (result == 0 && oldact) {
-    oldact->sa_handler = linux_oldact.kernel_handler;
-    sigemptyset(&oldact->sa_mask);
-    std::memcpy(&oldact->sa_mask, &linux_oldact.sa_mask,
-                std::min(sizeof(linux_act.sa_mask), sizeof(act->sa_mask)));
-    oldact->sa_flags = linux_oldact.sa_flags;
-  }
-  return result;
-}
-
-#endif  // !defined(OS_NACL_NONSFI)
 
 int sys_stat(const char* path, struct kernel_stat* stat_buf) {
   int res;
diff --git a/sandbox/linux/system_headers/linux_futex.h b/sandbox/linux/system_headers/linux_futex.h
index 4e28403..91733a8d 100644
--- a/sandbox/linux/system_headers/linux_futex.h
+++ b/sandbox/linux/system_headers/linux_futex.h
@@ -5,9 +5,7 @@
 #ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
 #define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
 
-#if !defined(__native_client_nonsfi__)
 #include <linux/futex.h>
-#endif  // !defined(__native_client_nonsfi__)
 
 #if !defined(FUTEX_WAIT)
 #define FUTEX_WAIT 0
diff --git a/sandbox/linux/system_headers/linux_signal.h b/sandbox/linux/system_headers/linux_signal.h
index f5a7367..74bbb8e 100644
--- a/sandbox/linux/system_headers/linux_signal.h
+++ b/sandbox/linux/system_headers/linux_signal.h
@@ -65,27 +65,6 @@
 #error "Unsupported platform"
 #endif
 
-#if defined(__native_client_nonsfi__)
-#if !defined(__i386__) && !defined(__arm__)
-#error "Unsupported platform"
-#endif
-
-#include <signal.h>
-
-struct LinuxSigInfo {
-  int si_signo;
-  int si_errno;
-  int si_code;
-
-  // Extra data is followed by the |si_code|. The length depends on the
-  // signal number.
-  char _sifields[1];
-};
-
-#include "sandbox/linux/system_headers/linux_ucontext.h"
-
-#else  // !defined(__native_client_nonsfi__)
-
 #include <signal.h>
 
 static_assert(LINUX_SIGHUP == SIGHUP, "LINUX_SIGHUP == SIGHUP");
@@ -110,8 +89,6 @@
 
 typedef siginfo_t LinuxSigInfo;
 
-#endif  // !defined(__native_client_nonsfi__)
-
 // struct sigset_t is different size in PNaCl from the Linux's.
 #if (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS))
 #if !defined(_NSIG_WORDS)
diff --git a/services/preferences/public/cpp/dictionary_value_update.cc b/services/preferences/public/cpp/dictionary_value_update.cc
index 5d1ddc2..ec65bdf 100644
--- a/services/preferences/public/cpp/dictionary_value_update.cc
+++ b/services/preferences/public/cpp/dictionary_value_update.cc
@@ -135,7 +135,12 @@
 
 bool DictionaryValueUpdate::GetBoolean(base::StringPiece path,
                                        bool* out_value) const {
-  return value_->GetBoolean(path, out_value);
+  absl::optional<bool> value = value_->FindBoolPath(path);
+  if (!value.has_value())
+    return false;
+  if (out_value)
+    *out_value = value.value();
+  return true;
 }
 
 bool DictionaryValueUpdate::GetInteger(base::StringPiece path,
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index f5b639b..685e588 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -1721,7 +1721,7 @@
       {
         "args": [],
         "cros_board": "atlas",
-        "cros_img": "atlas-release/R97-14324.13.0",
+        "cros_img": "atlas-release/R98-14359.0.0",
         "name": "lacros_all_tast_tests_ATLAS_DEV",
         "resultdb": {
           "enable": true,
@@ -1781,7 +1781,7 @@
       {
         "args": [],
         "cros_board": "eve",
-        "cros_img": "eve-release/R97-14324.13.0",
+        "cros_img": "eve-release/R98-14359.0.0",
         "name": "lacros_all_tast_tests_EVE_DEV",
         "resultdb": {
           "enable": true,
diff --git a/testing/buildbot/internal.chromeos.fyi.json b/testing/buildbot/internal.chromeos.fyi.json
index 8099255..274e0e7 100644
--- a/testing/buildbot/internal.chromeos.fyi.json
+++ b/testing/buildbot/internal.chromeos.fyi.json
@@ -1106,7 +1106,7 @@
       {
         "args": [],
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R97-14324.13.0",
+        "cros_img": "octopus-release/R98-14359.0.0",
         "name": "lacros_fyi_tast_tests_OCTOPUS_DEV",
         "swarming": {},
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
@@ -1149,7 +1149,7 @@
       {
         "args": [],
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R97-14324.13.0",
+        "cros_img": "octopus-release/R98-14359.0.0",
         "name": "ozone_unittests_OCTOPUS_DEV",
         "swarming": {},
         "test": "ozone_unittests",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 3dc24a3..cd2c25a4 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -570,7 +570,7 @@
   'CROS_ATLAS_DEV': {
     'skylab': {
       'cros_board': 'atlas',
-      'cros_img': 'atlas-release/R97-14324.13.0',
+      'cros_img': 'atlas-release/R98-14359.0.0',
     },
     'identifier': 'ATLAS_DEV',
   },
@@ -598,7 +598,7 @@
   'CROS_EVE_DEV': {
     'skylab': {
       'cros_board': 'eve',
-      'cros_img': 'eve-release/R97-14324.13.0',
+      'cros_img': 'eve-release/R98-14359.0.0',
     },
     'identifier': 'EVE_DEV',
   },
@@ -633,7 +633,7 @@
   'CROS_OCTOPUS_DEV': {
     'skylab': {
       'cros_board': 'octopus',
-      'cros_img': 'octopus-release/R97-14324.13.0',
+      'cros_img': 'octopus-release/R98-14359.0.0',
     },
     'identifier': 'OCTOPUS_DEV',
   },
diff --git a/testing/libfuzzer/archive_corpus.py b/testing/libfuzzer/archive_corpus.py
index dddc18ff..31c0934 100755
--- a/testing/libfuzzer/archive_corpus.py
+++ b/testing/libfuzzer/archive_corpus.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
 #
 # Copyright 2016 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
diff --git a/testing/libfuzzer/dictionary_generator.py b/testing/libfuzzer/dictionary_generator.py
index b720e8e..424522a 100755
--- a/testing/libfuzzer/dictionary_generator.py
+++ b/testing/libfuzzer/dictionary_generator.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
 #
 # Copyright 2016 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
diff --git a/testing/libfuzzer/gen_fuzzer_config.py b/testing/libfuzzer/gen_fuzzer_config.py
index 7d45fcc..5cd6677 100755
--- a/testing/libfuzzer/gen_fuzzer_config.py
+++ b/testing/libfuzzer/gen_fuzzer_config.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
 #
 # Copyright (c) 2015 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
diff --git a/testing/libfuzzer/tests/check_fuzzer_config.py b/testing/libfuzzer/tests/check_fuzzer_config.py
index 6a4ea8e..521df55 100755
--- a/testing/libfuzzer/tests/check_fuzzer_config.py
+++ b/testing/libfuzzer/tests/check_fuzzer_config.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
 # 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.
diff --git a/testing/libfuzzer/tests/check_seed_corpus_archive.py b/testing/libfuzzer/tests/check_seed_corpus_archive.py
index 5bbabd4e..865b873 100755
--- a/testing/libfuzzer/tests/check_seed_corpus_archive.py
+++ b/testing/libfuzzer/tests/check_seed_corpus_archive.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
 # 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.
diff --git a/testing/libfuzzer/zip_sources.py b/testing/libfuzzer/zip_sources.py
index 946a7de..03645bb 100755
--- a/testing/libfuzzer/zip_sources.py
+++ b/testing/libfuzzer/zip_sources.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
 #
 # Copyright 2016 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 66d055ec..4e6d2a6 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2845,7 +2845,7 @@
             ]
         }
     ],
-    "DeprioritizeTimersUntilDOMContentLoaded": [
+    "DeprioritizeTimersUntilDOMContentLoadedExperiment": [
         {
             "platforms": [
                 "android",
diff --git a/third_party/blink/perf_tests/layout/hittest-nested-inline-blocks-listbased.html b/third_party/blink/perf_tests/layout/hittest-nested-inline-blocks-listbased.html
new file mode 100644
index 0000000..eea2109
--- /dev/null
+++ b/third_party/blink/perf_tests/layout/hittest-nested-inline-blocks-listbased.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<script src="../resources/runner.js"></script>
+<div id="container">
+  <div style="display:inline-block;">
+    <div style="display:inline-block;">
+      <div style="display:inline-block;">
+        <div style="display:inline-block;">
+          <div style="display:inline-block;">
+            <div style="display:inline-block;">
+              <div style="display:inline-block;">
+                <div style="display:inline-block;">
+                  <div style="display:inline-block;">
+                    <div style="display:inline-block; width:100px; height:100px;"></div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+<script>
+  function test() {
+    document.elementsFromPoint(50, 50);
+  }
+
+  PerfTestRunner.measureRunsPerSecond({
+    description: `Measures performance of hit-testing nested inline-blocks, list-based.`,
+    run: test
+  });
+</script>
+</body>
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index d59020f0..6c66f8b 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -8035,6 +8035,7 @@
       ContentWebUSB
       ContentMediaSession
       ContentMediaSessionService
+      ContentScreenReader
 
       # See components/back_forward_cache/back_forward_cache_disable.h for explanations.
       EmbedderPopupBlockerTabHelper
diff --git a/third_party/blink/renderer/bindings/core/v8/script_wrappable_v8_gc_integration_test.cc b/third_party/blink/renderer/bindings/core/v8/script_wrappable_v8_gc_integration_test.cc
index d82e4a110..baec99ee 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_wrappable_v8_gc_integration_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_wrappable_v8_gc_integration_test.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h"
 #include "third_party/blink/renderer/core/testing/death_aware_script_wrappable.h"
@@ -35,8 +35,9 @@
     auto* object = MakeGarbageCollected<DeathAwareScriptWrappable>();
     observer.Observe(object);
 
-    holder.Reset(GetIsolate(),
-                 ToV8(object, scope.GetContext()->Global(), GetIsolate()));
+    holder.Reset(GetIsolate(), ToV8Traits<DeathAwareScriptWrappable>::ToV8(
+                                   scope.GetScriptState(), object)
+                                   .ToLocalChecked());
   }
 
   RunV8MinorGC();
@@ -58,8 +59,9 @@
     observer.Observe(object);
 
     // Creates new V8 wrapper and associates it with global scope
-    holder.Reset(GetIsolate(),
-                 ToV8(object, scope.GetContext()->Global(), GetIsolate()));
+    holder.Reset(GetIsolate(), ToV8Traits<DeathAwareScriptWrappable>::ToV8(
+                                   scope.GetScriptState(), object)
+                                   .ToLocalChecked());
   }
 
   RunV8MinorGC();
@@ -82,7 +84,8 @@
     observer.Observe(object);
 
     // Creates new V8 wrapper and associates it with global scope
-    ToV8(object, scope.GetContext()->Global(), GetIsolate());
+    ToV8Traits<DeathAwareScriptWrappable>::ToV8(scope.GetScriptState(), object)
+        .ToLocalChecked();
   }
 
   RunV8MinorGC();
diff --git a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc
index da7bb66..6c46369 100644
--- a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc
+++ b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc
@@ -210,6 +210,13 @@
 
   gfx::RectF boundaries = ObjectBoundingBox();
   const bool bounds_changed = old_boundaries != boundaries;
+  if (bounds_changed) {
+    // Invalidate all resources of this client if our reference box changed.
+    SVGResourceInvalidator resource_invalidator(*this);
+    resource_invalidator.InvalidateEffects();
+    resource_invalidator.InvalidatePaints();
+  }
+
   // If our bounds changed, notify the parents.
   if (UpdateTransformAfterLayout(bounds_changed) || bounds_changed)
     SetNeedsBoundariesUpdate();
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc
index d71aa14..a5890a1 100644
--- a/third_party/blink/renderer/core/loader/base_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -184,13 +184,6 @@
   if (!policy)
     return;
 
-  if (!RuntimeEnabledFeatures::FeaturePolicyForClientHintsEnabled() &&
-      !base::FeatureList::IsEnabled(features::kAllowClientHintsToThirdParty) &&
-      !is_1p_origin) {
-    // No client hints for 3p origins.
-    return;
-  }
-
   // The next 4 hints should be enabled if we're allowing legacy hints to third
   // parties, or if PermissionsPolicy delegation says they are allowed.
   if (ShouldSendClientHint(
@@ -693,7 +686,7 @@
   if (mode == ClientHintsMode::kLegacy &&
       base::FeatureList::IsEnabled(features::kAllowClientHintsToThirdParty)) {
     origin_ok = true;
-  } else if (RuntimeEnabledFeatures::FeaturePolicyForClientHintsEnabled()) {
+  } else {
     // For subresource requests, if the parent frame has Sec-CH-UA-Reduced,
     // then send Sec-CH-UA-Reduced in the fetch request, regardless of the
     // permissions policy.
@@ -701,8 +694,6 @@
                 (policy && policy->IsFeatureEnabledForOrigin(
                                GetClientHintToPolicyFeatureMap().at(type),
                                resource_origin));
-  } else {
-    origin_ok = is_1p_origin;
   }
 
   if (!origin_ok)
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 5fcb19d..c19e306 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -360,15 +360,11 @@
       response_(params_->response.ToResourceResponse()),
       load_type_(params_->frame_load_type),
       is_client_redirect_(params_->is_client_redirect),
-      // TODO(japhet): This is needed because the browser process DCHECKs if the
-      // first entry we commit in a new frame has replacement set. It's unclear
-      // whether the DCHECK is right, investigate removing this special case.
       // TODO(dgozman): we should get rid of this boolean field, and make client
       // responsible for it's own view of "replaces current item", based on the
       // frame load type.
-      replaces_current_history_item_(
-          load_type_ == WebFrameLoadType::kReplaceCurrentItem &&
-          (!frame_->Loader().Opener() || !url_.IsEmpty())),
+      replaces_current_history_item_(load_type_ ==
+                                     WebFrameLoadType::kReplaceCurrentItem),
       data_received_(false),
       is_error_page_for_failed_navigation_(
           SchemeRegistry::ShouldTreatURLSchemeAsError(
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index a69f2ad..55ed89f 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -122,20 +122,10 @@
 
 namespace {
 
-// Client hints sent to third parties are controlled through two mechanisms,
-// based on the state of the experimental flag "FeaturePolicyForClientHints".
-//
-// If that flag is disabled (the default), then all hints are always sent for
-// first-party subresources, and the kAllowClientHintsToThirdParty feature
-// controls whether some specific hints are sent to third parties. (Only
-// device-memory, resource-width, viewport-width and DPR are sent under this
-// model). This feature is enabled by default on Android, and disabled by
-// default on all other platforms.
-//
-// When the runtime flag is enabled, all client hints except UA are controlled
-// entirely by permissions policy on all platforms. In that case, hints will
-// generally be sent for first-party resources, and not for third-party
-// resources, unless specifically enabled by policy.
+// Client hints sent to third parties are controlled entirely by permissions
+// policy on all platforms. In that case, hints will generally be sent for
+// first-party resources, and not for third-party resources, unless specifically
+// enabled by policy.
 
 // Determines FetchCacheMode for |frame|. This FetchCacheMode should be a base
 // policy to consider one of each resource belonging to the frame, and should
@@ -454,9 +444,8 @@
     return;
   }
 
-  // When the runtime flag "FeaturePolicyForClientHints" is enabled, permissions
-  // policy is used to enable hints for all subresources, based on the policy of
-  // the requesting document, and the origin of the resource.
+  // The Permissions policy is used to enable hints for all subresources, based
+  // on the policy of the requesting document, and the origin of the resource.
   const PermissionsPolicy* policy =
       document_
           ? document_->domWindow()->GetSecurityContext().GetPermissionsPolicy()
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index 4c435cc..764d5cf 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -479,27 +479,28 @@
     const KURL& url,
     WebFrameLoadType frame_load_type) {
   // Converts navigations from the initial empty document to do replacement if
-  // needed.
-  if (frame_load_type == WebFrameLoadType::kStandard ||
-      frame_load_type == WebFrameLoadType::kReplaceCurrentItem) {
-    if (frame_->Tree().Parent() && IsOnInitialEmptyDocument()) {
-      // Subframe navigations from the initial empty document should always do
-      // replacement.
-      return WebFrameLoadType::kReplaceCurrentItem;
-    }
-    if (!frame_->Tree().Parent() && !Client()->BackForwardLength()) {
-      // For main frames, currently only empty-URL navigations will be converted
-      // to do replacement. Note that this will cause the navigation to be
-      // ignored in the browser side, so no NavigationEntry will be added.
-      // TODO(https://crbug.com/1215096, https://crbug.com/524208): Make the
-      // main frame case follow the behavior of subframes (always replace when
-      // navigating from the initial empty document), and that a NavigationEntry
-      // will always be created.
-      if (Opener() && url.IsEmpty())
-        return WebFrameLoadType::kReplaceCurrentItem;
-      return WebFrameLoadType::kStandard;
-    }
+  // needed. Note that we don't convert reloads or history navigations (so only
+  // kStandard navigations can get converted to do replacement).
+  if (frame_load_type != WebFrameLoadType::kStandard)
+    return frame_load_type;
+
+  if (frame_->Tree().Parent() && IsOnInitialEmptyDocument()) {
+    // Subframe navigations from the initial empty document should always do
+    // replacement.
+    return WebFrameLoadType::kReplaceCurrentItem;
   }
+
+  if (!frame_->Tree().Parent() && !Client()->BackForwardLength()) {
+    // For main frames, currently only empty-URL navigations will be converted
+    // to do replacement. Note that this will cause the navigation to be
+    // ignored in the browser side, so no NavigationEntry will be added.
+    // TODO(https://crbug.com/1215096): Make the main frame case follow the
+    // behavior of subframes (always replace when navigating from the initial
+    // empty document).
+    if (Opener() && url.IsEmpty())
+      return WebFrameLoadType::kReplaceCurrentItem;
+  }
+
   return frame_load_type;
 }
 
diff --git a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
index 4c6da06..5ebc9ed 100644
--- a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
+++ b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/core/editing/editor.h"
 #include "third_party/blink/renderer/core/editing/markers/composition_marker.h"
 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
+#include "third_party/blink/renderer/core/editing/markers/highlight_pseudo_marker.h"
 #include "third_party/blink/renderer/core/editing/markers/text_match_marker.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/layout/api/line_layout_api_shim.h"
@@ -55,7 +56,8 @@
       text_box.Start() + text_box.GetLineLayoutItem().TextStartOffset();
 
   DCHECK(marker.GetType() == DocumentMarker::kTextMatch ||
-         marker.GetType() == DocumentMarker::kTextFragment);
+         marker.GetType() == DocumentMarker::kTextFragment ||
+         marker.GetType() == DocumentMarker::kHighlight);
   const unsigned start_offset = marker.StartOffset() > text_box_start
                                     ? marker.StartOffset() - text_box_start
                                     : 0U;
@@ -648,6 +650,7 @@
         inline_text_box_.PaintDocumentMarker(paint_info, box_origin, marker,
                                              style, font, true);
         break;
+      case DocumentMarker::kHighlight:
       case DocumentMarker::kTextFragment:
       case DocumentMarker::kTextMatch:
         if (marker_paint_phase == DocumentMarkerPaintPhase::kBackground) {
@@ -675,10 +678,6 @@
                                         styleable_marker, style, font);
         }
       } break;
-      case DocumentMarker::kHighlight:
-        inline_text_box_.PaintDocumentMarker(paint_info, box_origin, marker,
-                                             style, font, false);
-        break;
       default:
         // Marker is not painted, or painting code has not been added yet
         break;
@@ -965,11 +964,20 @@
       GetTextMatchMarkerPaintOffsets(marker, inline_text_box_);
   TextRun run = inline_text_box_.ConstructTextRun(style);
 
-  Color color = LayoutTheme::GetTheme().PlatformTextSearchHighlightColor(
-      marker.GetType() == DocumentMarker::kTextMatch
-          ? To<TextMatchMarker>(marker).IsActiveMatch()
-          : false,
-      style.UsedColorScheme());
+  Color color;
+  if (marker.GetType() == DocumentMarker::kTextMatch) {
+    color = LayoutTheme::GetTheme().PlatformTextSearchHighlightColor(
+        To<TextMatchMarker>(marker).IsActiveMatch(), style.UsedColorScheme());
+  } else {
+    DCHECK(marker.GetType() == DocumentMarker::kHighlight ||
+           marker.GetType() == DocumentMarker::kTextFragment);
+    const auto& highlight_pseudo_marker = To<HighlightPseudoMarker>(marker);
+    auto layout_item = inline_text_box_.GetLineLayoutItem();
+    color = HighlightPaintingUtils::HighlightBackgroundColor(
+        layout_item.GetDocument(), layout_item.StyleRef(),
+        layout_item.GetNode(), highlight_pseudo_marker.GetPseudoId(),
+        highlight_pseudo_marker.GetPseudoArgument());
+  }
   GraphicsContext& context = paint_info.context;
   GraphicsContextStateSaver state_saver(context);
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index 515992e..9b171c0 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -2180,16 +2180,25 @@
     const NGPhysicalBoxFragment& fragment,
     const NGInlineBackwardCursor& backward_cursor,
     const PhysicalOffset& physical_offset) {
+  bool is_in_atomic_painting_pass;
+
   // Note: Floats should only be hit tested in the |kHitTestFloat| phase, so we
   // shouldn't enter a float when |action| doesn't match. However, as floats may
   // scatter around in the entire inline formatting context, we should always
   // enter non-floating inline child boxes to search for floats in the
   // |kHitTestFloat| phase, unless the child box forms another context.
-  if (fragment.IsFloating() && hit_test.action != kHitTestFloat)
-    return false;
+  if (fragment.IsFloating()) {
+    if (hit_test.action != kHitTestFloat)
+      return false;
+    is_in_atomic_painting_pass = true;
+  } else {
+    is_in_atomic_painting_pass = hit_test.action == kHitTestForeground;
+  }
 
   if (!FragmentRequiresLegacyFallback(fragment)) {
     if (fragment.IsPaintedAtomically()) {
+      if (!is_in_atomic_painting_pass)
+        return false;
       return HitTestAllPhasesInFragment(fragment, hit_test.location,
                                         physical_offset, hit_test.result);
     }
@@ -2237,6 +2246,8 @@
     return false;
 
   if (fragment.IsPaintedAtomically()) {
+    if (!is_in_atomic_painting_pass)
+      return false;
     return HitTestAllPhasesInFragment(fragment, hit_test.location,
                                       physical_offset, hit_test.result);
   }
diff --git a/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5 b/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5
index 9ae84227..2ccda64 100644
--- a/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5
+++ b/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5
@@ -73,53 +73,43 @@
     {
       name: "ClientHintDPR",
       permissions_policy_name: "ch-dpr",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintDeviceMemory",
       permissions_policy_name: "ch-device-memory",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintDownlink",
       permissions_policy_name: "ch-downlink",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintECT",
       permissions_policy_name: "ch-ect",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintPrefersColorScheme",
       permissions_policy_name: "ch-prefers-color-scheme",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintRTT",
       permissions_policy_name: "ch-rtt",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintUA",
       permissions_policy_name: "ch-ua",
       feature_default: "EnableForAll",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintUAArch",
       permissions_policy_name: "ch-ua-arch",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintUABitness",
       permissions_policy_name: "ch-ua-bitness",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintUAPlatform",
       permissions_policy_name: "ch-ua-platform",
-      depends_on: ["FeaturePolicyForClientHints"],
       default_value_behind_flag: [
         ["UACHPlatformEnabledByDefault", "EnableForAll"],
       ],
@@ -127,33 +117,29 @@
     {
       name: "ClientHintUAModel",
       permissions_policy_name: "ch-ua-model",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintUAMobile",
       permissions_policy_name: "ch-ua-mobile",
       feature_default: "EnableForAll",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintUAFullVersion",
       permissions_policy_name: "ch-ua-full-version",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintUAFullVersionList",
       permissions_policy_name: "ch-ua-full-version-list",
-      depends_on: ["FeaturePolicyForClientHints", "UserAgentClientHintFullVersionList"],
+      depends_on: ["UserAgentClientHintFullVersionList"],
     },
     {
       name: "ClientHintUAPlatformVersion",
       permissions_policy_name: "ch-ua-platform-version",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintUAReduced",
       permissions_policy_name: "ch-ua-reduced",
-      depends_on: ["FeaturePolicyForClientHints", "UserAgentReduction"],
+      depends_on: ["UserAgentReduction"],
     },
     {
       name: "ClientHintViewportHeight",
@@ -163,12 +149,10 @@
     {
       name: "ClientHintViewportWidth",
       permissions_policy_name: "ch-viewport-width",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClientHintWidth",
       permissions_policy_name: "ch-width",
-      depends_on: ["FeaturePolicyForClientHints"],
     },
     {
       name: "ClipboardRead",
diff --git a/third_party/blink/renderer/core/script/dynamic_module_resolver.cc b/third_party/blink/renderer/core/script/dynamic_module_resolver.cc
index 2fd4223..a5e7642 100644
--- a/third_party/blink/renderer/core/script/dynamic_module_resolver.cc
+++ b/third_party/blink/renderer/core/script/dynamic_module_resolver.cc
@@ -43,15 +43,14 @@
 };
 
 // Abstract callback for modules resolution.
-class ModuleResolutionCallback : public ScriptFunction {
+class ModuleResolutionCallback : public NewScriptFunction::Callable {
  public:
-  ModuleResolutionCallback(ScriptState* script_state,
-                           ScriptPromiseResolver* promise_resolver)
-      : ScriptFunction(script_state), promise_resolver_(promise_resolver) {}
+  explicit ModuleResolutionCallback(ScriptPromiseResolver* promise_resolver)
+      : promise_resolver_(promise_resolver) {}
 
   void Trace(Visitor* visitor) const override {
     visitor->Trace(promise_resolver_);
-    ScriptFunction::Trace(visitor);
+    NewScriptFunction::Callable::Trace(visitor);
   }
 
  protected:
@@ -62,30 +61,19 @@
 // Called on successful resolution.
 class ModuleResolutionSuccessCallback final : public ModuleResolutionCallback {
  public:
-  ModuleResolutionSuccessCallback(ScriptState* script_state,
-                                  ScriptPromiseResolver* promise_resolver,
+  ModuleResolutionSuccessCallback(ScriptPromiseResolver* promise_resolver,
                                   ModuleScript* module_script)
-      : ModuleResolutionCallback(script_state, promise_resolver),
+      : ModuleResolutionCallback(promise_resolver),
         module_script_(module_script) {}
 
-  static v8::Local<v8::Function> CreateFunction(
-      ScriptState* script_state,
-      ScriptPromiseResolver* promise_resolver,
-      ModuleScript* module_script) {
-    ModuleResolutionSuccessCallback* self =
-        MakeGarbageCollected<ModuleResolutionSuccessCallback>(
-            script_state, promise_resolver, module_script);
-    return self->BindToV8Function();
-  }
-
   void Trace(Visitor* visitor) const final {
     visitor->Trace(module_script_);
     ModuleResolutionCallback::Trace(visitor);
   }
 
  private:
-  ScriptValue Call(ScriptValue value) override {
-    ScriptState::Scope scope(GetScriptState());
+  ScriptValue Call(ScriptState* script_state, ScriptValue value) override {
+    ScriptState::Scope scope(script_state);
     v8::Local<v8::Module> record = module_script_->V8Module();
     v8::Local<v8::Value> module_namespace = ModuleRecord::V8Namespace(record);
     promise_resolver_->Resolve(module_namespace);
@@ -99,22 +87,13 @@
 // Called on unsuccessful resolution.
 class ModuleResolutionFailureCallback final : public ModuleResolutionCallback {
  public:
-  ModuleResolutionFailureCallback(ScriptState* script_state,
-                                  ScriptPromiseResolver* promise_resolver)
-      : ModuleResolutionCallback(script_state, promise_resolver) {}
-
-  static v8::Local<v8::Function> CreateFunction(
-      ScriptState* script_state,
-      ScriptPromiseResolver* promise_resolver) {
-    ModuleResolutionFailureCallback* self =
-        MakeGarbageCollected<ModuleResolutionFailureCallback>(script_state,
-                                                              promise_resolver);
-    return self->BindToV8Function();
-  }
+  explicit ModuleResolutionFailureCallback(
+      ScriptPromiseResolver* promise_resolver)
+      : ModuleResolutionCallback(promise_resolver) {}
 
  private:
-  ScriptValue Call(ScriptValue exception) override {
-    ScriptState::Scope scope(GetScriptState());
+  ScriptValue Call(ScriptState* script_state, ScriptValue exception) override {
+    ScriptState::Scope scope(script_state);
     promise_resolver_->Reject(exception);
     return ScriptValue();
   }
@@ -191,12 +170,12 @@
 
       if (base::FeatureList::IsEnabled(features::kTopLevelAwait)) {
         ScriptPromise promise = result.GetPromise(script_state);
-        v8::Local<v8::Function> callback_success =
-            ModuleResolutionSuccessCallback::CreateFunction(
-                script_state, promise_resolver_, module_script);
-        v8::Local<v8::Function> callback_failure =
-            ModuleResolutionFailureCallback::CreateFunction(script_state,
-                                                            promise_resolver_);
+        auto* callback_success = MakeGarbageCollected<NewScriptFunction>(
+            script_state, MakeGarbageCollected<ModuleResolutionSuccessCallback>(
+                              promise_resolver_, module_script));
+        auto* callback_failure = MakeGarbageCollected<NewScriptFunction>(
+            script_state, MakeGarbageCollected<ModuleResolutionFailureCallback>(
+                              promise_resolver_));
         promise.Then(callback_success, callback_failure);
         return;
       }
diff --git a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
index a83762b..9de2b0c 100644
--- a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
+++ b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
@@ -123,22 +123,19 @@
 // with a single argument of type module namespace.
 // CaptureExportedStringFunction captures the exported string value
 // from the module namespace as a WTF::String, exposed via CapturedValue().
-class CaptureExportedStringFunction final : public ScriptFunction {
+class CaptureExportedStringFunction final : public NewScriptFunction::Callable {
  public:
-  CaptureExportedStringFunction(ScriptState* script_state,
-                                const String& export_name)
-      : ScriptFunction(script_state), export_name_(export_name) {}
+  explicit CaptureExportedStringFunction(const String& export_name)
+      : export_name_(export_name) {}
 
-  v8::Local<v8::Function> Bind() { return BindToV8Function(); }
   bool WasCalled() const { return was_called_; }
   const String& CapturedValue() const { return captured_value_; }
 
- private:
-  ScriptValue Call(ScriptValue value) override {
+  ScriptValue Call(ScriptState* script_state, ScriptValue value) override {
     was_called_ = true;
 
-    v8::Isolate* isolate = GetScriptState()->GetIsolate();
-    v8::Local<v8::Context> context = GetScriptState()->GetContext();
+    v8::Isolate* isolate = script_state->GetIsolate();
+    v8::Local<v8::Context> context = script_state->GetContext();
 
     v8::Local<v8::Object> module_namespace =
         value.V8Value()->ToObject(context).ToLocalChecked();
@@ -151,6 +148,7 @@
     return ScriptValue();
   }
 
+ private:
   const String export_name_;
   bool was_called_ = false;
   String captured_value_;
@@ -158,22 +156,19 @@
 
 // CaptureErrorFunction implements a javascript function which captures
 // name and error of the exception passed as its argument.
-class CaptureErrorFunction final : public ScriptFunction {
+class CaptureErrorFunction final : public NewScriptFunction::Callable {
  public:
-  explicit CaptureErrorFunction(ScriptState* script_state)
-      : ScriptFunction(script_state) {}
+  CaptureErrorFunction() = default;
 
-  v8::Local<v8::Function> Bind() { return BindToV8Function(); }
   bool WasCalled() const { return was_called_; }
   const String& Name() const { return name_; }
   const String& Message() const { return message_; }
 
- private:
-  ScriptValue Call(ScriptValue value) override {
+  ScriptValue Call(ScriptState* script_state, ScriptValue value) override {
     was_called_ = true;
 
-    v8::Isolate* isolate = GetScriptState()->GetIsolate();
-    v8::Local<v8::Context> context = GetScriptState()->GetContext();
+    v8::Isolate* isolate = script_state->GetIsolate();
+    v8::Local<v8::Context> context = script_state->GetContext();
 
     v8::Local<v8::Object> error_object =
         value.V8Value()->ToObject(context).ToLocalChecked();
@@ -189,24 +184,18 @@
     return ScriptValue();
   }
 
+ private:
   bool was_called_ = false;
   String name_;
   String message_;
 };
 
-class DynamicModuleResolverTestNotReached final : public ScriptFunction {
+class DynamicModuleResolverTestNotReached final
+    : public NewScriptFunction::Callable {
  public:
-  static v8::Local<v8::Function> CreateFunction(ScriptState* script_state) {
-    auto* not_reached =
-        MakeGarbageCollected<DynamicModuleResolverTestNotReached>(script_state);
-    return not_reached->BindToV8Function();
-  }
+  DynamicModuleResolverTestNotReached() = default;
 
-  explicit DynamicModuleResolverTestNotReached(ScriptState* script_state)
-      : ScriptFunction(script_state) {}
-
- private:
-  ScriptValue Call(ScriptValue) override {
+  ScriptValue Call(ScriptState*, ScriptValue) override {
     ADD_FAILURE();
     return ScriptValue();
   }
@@ -232,11 +221,12 @@
       MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
   ScriptPromise promise = promise_resolver->Promise();
 
-  auto* capture = MakeGarbageCollected<CaptureExportedStringFunction>(
-      scope.GetScriptState(), "foo");
-  promise.Then(capture->Bind(),
-               DynamicModuleResolverTestNotReached::CreateFunction(
-                   scope.GetScriptState()));
+  auto* capture = MakeGarbageCollected<CaptureExportedStringFunction>("foo");
+  promise.Then(
+      MakeGarbageCollected<NewScriptFunction>(scope.GetScriptState(), capture),
+      MakeGarbageCollected<NewScriptFunction>(
+          scope.GetScriptState(),
+          MakeGarbageCollected<DynamicModuleResolverTestNotReached>()));
 
   auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
   ModuleRequest module_request("./dependency.js",
@@ -299,11 +289,12 @@
       MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
   ScriptPromise promise = promise_resolver->Promise();
 
-  auto* capture =
-      MakeGarbageCollected<CaptureErrorFunction>(scope.GetScriptState());
-  promise.Then(DynamicModuleResolverTestNotReached::CreateFunction(
-                   scope.GetScriptState()),
-               capture->Bind());
+  auto* capture = MakeGarbageCollected<CaptureErrorFunction>();
+  promise.Then(
+      MakeGarbageCollected<NewScriptFunction>(
+          scope.GetScriptState(),
+          MakeGarbageCollected<DynamicModuleResolverTestNotReached>()),
+      MakeGarbageCollected<NewScriptFunction>(scope.GetScriptState(), capture));
 
   auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
   ModuleRequest module_request("invalid-specifier",
@@ -328,11 +319,12 @@
       MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
   ScriptPromise promise = promise_resolver->Promise();
 
-  auto* capture =
-      MakeGarbageCollected<CaptureErrorFunction>(scope.GetScriptState());
-  promise.Then(DynamicModuleResolverTestNotReached::CreateFunction(
-                   scope.GetScriptState()),
-               capture->Bind());
+  auto* capture = MakeGarbageCollected<CaptureErrorFunction>();
+  promise.Then(
+      MakeGarbageCollected<NewScriptFunction>(
+          scope.GetScriptState(),
+          MakeGarbageCollected<DynamicModuleResolverTestNotReached>()),
+      MakeGarbageCollected<NewScriptFunction>(scope.GetScriptState(), capture));
 
   auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
   Vector<ImportAssertion> import_assertions{
@@ -358,11 +350,12 @@
       MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
   ScriptPromise promise = promise_resolver->Promise();
 
-  auto* capture =
-      MakeGarbageCollected<CaptureErrorFunction>(scope.GetScriptState());
-  promise.Then(DynamicModuleResolverTestNotReached::CreateFunction(
-                   scope.GetScriptState()),
-               capture->Bind());
+  auto* capture = MakeGarbageCollected<CaptureErrorFunction>();
+  promise.Then(
+      MakeGarbageCollected<NewScriptFunction>(
+          scope.GetScriptState(),
+          MakeGarbageCollected<DynamicModuleResolverTestNotReached>()),
+      MakeGarbageCollected<NewScriptFunction>(scope.GetScriptState(), capture));
 
   auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
   ModuleRequest module_request("./dependency.js",
@@ -391,11 +384,12 @@
       MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
   ScriptPromise promise = promise_resolver->Promise();
 
-  auto* capture =
-      MakeGarbageCollected<CaptureErrorFunction>(scope.GetScriptState());
-  promise.Then(DynamicModuleResolverTestNotReached::CreateFunction(
-                   scope.GetScriptState()),
-               capture->Bind());
+  auto* capture = MakeGarbageCollected<CaptureErrorFunction>();
+  promise.Then(
+      MakeGarbageCollected<NewScriptFunction>(
+          scope.GetScriptState(),
+          MakeGarbageCollected<DynamicModuleResolverTestNotReached>()),
+      MakeGarbageCollected<NewScriptFunction>(scope.GetScriptState(), capture));
 
   auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
   ModuleRequest module_request("./dependency.js",
@@ -433,11 +427,12 @@
       MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
   ScriptPromise promise = promise_resolver->Promise();
 
-  auto* capture = MakeGarbageCollected<CaptureExportedStringFunction>(
-      scope.GetScriptState(), "foo");
-  promise.Then(capture->Bind(),
-               DynamicModuleResolverTestNotReached::CreateFunction(
-                   scope.GetScriptState()));
+  auto* capture = MakeGarbageCollected<CaptureExportedStringFunction>("foo");
+  promise.Then(
+      MakeGarbageCollected<NewScriptFunction>(scope.GetScriptState(), capture),
+      MakeGarbageCollected<NewScriptFunction>(
+          scope.GetScriptState(),
+          MakeGarbageCollected<DynamicModuleResolverTestNotReached>()));
 
   auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
   ModuleRequest module_request("./dependency.js",
diff --git a/third_party/blink/renderer/core/streams/readable_stream_test.cc b/third_party/blink/renderer/core/streams/readable_stream_test.cc
index aeb7f884..1442ce8a 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_test.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_test.cc
@@ -8,6 +8,7 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_function.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_iterator_result_value.h"
@@ -42,7 +43,8 @@
     ScriptState* script_state = scope.GetScriptState();
     v8::Isolate* isolate = script_state->GetIsolate();
     v8::Local<v8::Context> context = script_state->GetContext();
-    v8::Local<v8::Value> v8_stream = ToV8(stream, context->Global(), isolate);
+    v8::Local<v8::Value> v8_stream =
+        ToV8Traits<ReadableStream>::ToV8(script_state, stream).ToLocalChecked();
     v8::Local<v8::Object> global = context->Global();
     bool set_result = false;
     if (!global->Set(context, V8String(isolate, "stream"), v8_stream)
@@ -140,9 +142,9 @@
   auto* underlying_source =
       MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
   ScriptValue js_underlying_source = ScriptValue(
-      scope.GetIsolate(),
-      ToV8(underlying_source, scope.GetScriptState()->GetContext()->Global(),
-           scope.GetIsolate()));
+      scope.GetIsolate(), ToV8Traits<TestUnderlyingSource>::ToV8(
+                              scope.GetScriptState(), underlying_source)
+                              .ToLocalChecked());
 
   EXPECT_FALSE(underlying_source->IsStartCalled());
 
@@ -159,9 +161,9 @@
   auto* underlying_source =
       MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
   ScriptValue js_underlying_source = ScriptValue(
-      scope.GetIsolate(),
-      ToV8(underlying_source, scope.GetScriptState()->GetContext()->Global(),
-           scope.GetIsolate()));
+      scope.GetIsolate(), ToV8Traits<TestUnderlyingSource>::ToV8(
+                              scope.GetScriptState(), underlying_source)
+                              .ToLocalChecked());
   ScriptValue js_empty_strategy = EvalWithPrintingError(&scope, "{}");
   ASSERT_FALSE(js_empty_strategy.IsEmpty());
   ReadableStream* stream =
@@ -177,9 +179,9 @@
   auto* underlying_source =
       MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
   ScriptValue js_underlying_source = ScriptValue(
-      scope.GetIsolate(),
-      ToV8(underlying_source, scope.GetScriptState()->GetContext()->Global(),
-           scope.GetIsolate()));
+      scope.GetIsolate(), ToV8Traits<TestUnderlyingSource>::ToV8(
+                              scope.GetScriptState(), underlying_source)
+                              .ToLocalChecked());
   ScriptValue js_pathological_strategy =
       EvalWithPrintingError(&scope, "({get size() { throw Error('e'); }})");
   ASSERT_FALSE(js_pathological_strategy.IsEmpty());
@@ -200,9 +202,10 @@
 
   auto* underlying_source =
       MakeGarbageCollected<TestUnderlyingSource>(script_state);
-  ScriptValue js_underlying_source = ScriptValue(
-      isolate,
-      ToV8(underlying_source, script_state->GetContext()->Global(), isolate));
+  ScriptValue js_underlying_source =
+      ScriptValue(isolate, ToV8Traits<TestUnderlyingSource>::ToV8(
+                               scope.GetScriptState(), underlying_source)
+                               .ToLocalChecked());
   ReadableStream* stream = ReadableStream::Create(
       script_state, js_underlying_source, ASSERT_NO_EXCEPTION);
   ASSERT_TRUE(stream);
@@ -275,9 +278,10 @@
 
   auto* underlying_source =
       MakeGarbageCollected<TestUnderlyingSource>(script_state);
-  ScriptValue js_underlying_source = ScriptValue(
-      isolate,
-      ToV8(underlying_source, script_state->GetContext()->Global(), isolate));
+  ScriptValue js_underlying_source =
+      ScriptValue(isolate, ToV8Traits<TestUnderlyingSource>::ToV8(
+                               scope.GetScriptState(), underlying_source)
+                               .ToLocalChecked());
   ReadableStream* stream = ReadableStream::Create(
       script_state, js_underlying_source, ASSERT_NO_EXCEPTION);
   ASSERT_TRUE(stream);
@@ -300,9 +304,10 @@
 
   auto* underlying_source =
       MakeGarbageCollected<TestUnderlyingSource>(script_state);
-  ScriptValue js_underlying_source = ScriptValue(
-      isolate,
-      ToV8(underlying_source, script_state->GetContext()->Global(), isolate));
+  ScriptValue js_underlying_source =
+      ScriptValue(isolate, ToV8Traits<TestUnderlyingSource>::ToV8(
+                               scope.GetScriptState(), underlying_source)
+                               .ToLocalChecked());
   ReadableStream* stream = ReadableStream::Create(
       script_state, js_underlying_source, ASSERT_NO_EXCEPTION);
   ASSERT_TRUE(stream);
@@ -328,9 +333,10 @@
 
   auto* underlying_source =
       MakeGarbageCollected<TestUnderlyingSource>(script_state);
-  ScriptValue js_underlying_source = ScriptValue(
-      isolate,
-      ToV8(underlying_source, script_state->GetContext()->Global(), isolate));
+  ScriptValue js_underlying_source =
+      ScriptValue(isolate, ToV8Traits<TestUnderlyingSource>::ToV8(
+                               scope.GetScriptState(), underlying_source)
+                               .ToLocalChecked());
   ReadableStream* stream = ReadableStream::Create(
       script_state, js_underlying_source, ASSERT_NO_EXCEPTION);
   ASSERT_TRUE(stream);
diff --git a/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc b/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc
index 2fd934c1..18784d78 100644
--- a/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc
+++ b/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc
@@ -25,7 +25,7 @@
 
 #include "third_party/blink/renderer/core/testing/v8/web_core_test_support.h"
 
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -45,15 +45,16 @@
 
 v8::Local<v8::Value> CreateInternalsObject(v8::Local<v8::Context> context) {
   ScriptState* script_state = ScriptState::From(context);
-  v8::Local<v8::Object> global = script_state->GetContext()->Global();
   ExecutionContext* execution_context = ExecutionContext::From(script_state);
   if (execution_context->IsWindow()) {
-    return ToV8(MakeGarbageCollected<Internals>(execution_context), global,
-                script_state->GetIsolate());
+    return ToV8Traits<Internals>::ToV8(
+               script_state, MakeGarbageCollected<Internals>(execution_context))
+        .ToLocalChecked();
   }
   if (execution_context->IsWorkerGlobalScope()) {
-    return ToV8(MakeGarbageCollected<WorkerInternals>(), global,
-                script_state->GetIsolate());
+    return ToV8Traits<WorkerInternals>::ToV8(
+               script_state, MakeGarbageCollected<WorkerInternals>())
+        .ToLocalChecked();
   }
   return v8::Local<v8::Value>();
 }
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink_test.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink_test.cc
index 9a61f282..0bf3d68 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink_test.cc
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink_test.cc
@@ -72,9 +72,9 @@
         MakeGarbageCollected<AudioData>(std::move(media_buffer));
     if (audio_data_out)
       *audio_data_out = audio_data;
-    return ScriptValue(script_state->GetIsolate(),
-                       ToV8(audio_data, script_state->GetContext()->Global(),
-                            script_state->GetIsolate()));
+    return ScriptValue(
+        script_state->GetIsolate(),
+        ToV8Traits<AudioData>::ToV8(script_state, audio_data).ToLocalChecked());
   }
 
  protected:
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator_test.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator_test.cc
index bc0ded42..b71d7bfa 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator_test.cc
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator_test.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/public/platform/modules/mediastream/web_media_stream_track.h"
 #include "third_party/blink/public/web/web_heap.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_generator_init.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame.h"
@@ -43,9 +44,9 @@
       media::VideoFrame::CreateBlackFrame(gfx::Size(10, 5));
   VideoFrame* video_frame = MakeGarbageCollected<VideoFrame>(
       std::move(media_frame), ExecutionContext::From(script_state));
-  return ScriptValue(script_state->GetIsolate(),
-                     ToV8(video_frame, script_state->GetContext()->Global(),
-                          script_state->GetIsolate()));
+  return ScriptValue(
+      script_state->GetIsolate(),
+      ToV8Traits<VideoFrame>::ToV8(script_state, video_frame).ToLocalChecked());
 }
 
 ScriptValue CreateAudioDataChunk(ScriptState* script_state) {
@@ -55,9 +56,9 @@
           /*channel_count=*/2,
           /*sample_rate=*/44100,
           /*frame_count=*/500, base::TimeDelta()));
-  return ScriptValue(script_state->GetIsolate(),
-                     ToV8(audio_data, script_state->GetContext()->Global(),
-                          script_state->GetIsolate()));
+  return ScriptValue(
+      script_state->GetIsolate(),
+      ToV8Traits<AudioData>::ToV8(script_state, audio_data).ToLocalChecked());
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_sink_test.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_sink_test.cc
index a45e84ab..f43e6b7a 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_sink_test.cc
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_sink_test.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/public/web/web_heap.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame.h"
 #include "third_party/blink/renderer/core/streams/writable_stream.h"
@@ -66,8 +67,8 @@
     if (video_frame_out)
       *video_frame_out = video_frame;
     return ScriptValue(script_state->GetIsolate(),
-                       ToV8(video_frame, script_state->GetContext()->Global(),
-                            script_state->GetIsolate()));
+                       ToV8Traits<VideoFrame>::ToV8(script_state, video_frame)
+                           .ToLocalChecked());
   }
 
  protected:
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.cc
index ca8fa89..c7126d4f 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.cc
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.cc
@@ -5,6 +5,8 @@
 #include "third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.h"
 
 #include "base/feature_list.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "media/capture/video/video_capture_buffer_pool_util.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -87,6 +89,31 @@
     std::vector<scoped_refptr<media::VideoFrame>> /*scaled_media_frames*/,
     base::TimeTicks estimated_capture_time) {
   DCHECK(GetIOTaskRunner()->RunsTasksInCurrentSequence());
+
+  // The track's source may provide duplicate frames, eg if other sinks
+  // request a refresh frame. Drop them here as we've already provided them.
+  // Out of order frames aren't expected, but are also dropped defensively,
+  // see crbug.com(1271175).
+  if (media_frame->timestamp() != media::kNoTimestamp &&
+      media_frame->timestamp() <= last_enqueued_timestamp) {
+    if (media_frame->timestamp() < last_enqueued_timestamp) {
+      DLOG(WARNING)
+          << "Received unexpectedly out-of-order frame with timestamp: "
+          << media_frame->timestamp()
+          << ", previous timestamp: " << last_enqueued_timestamp
+          << ". Dropping it.";
+      if (!reported_out_of_order_timestamp) {
+        // Monitor the number of instances performing these drops. Can be
+        // compared with the "Media.BreakoutBox.Usage" histogram to give a
+        // baseline.
+        UMA_HISTOGRAM_BOOLEAN("Media.BreakoutBox.OutOfOrderFrameDropped", true);
+        reported_out_of_order_timestamp = true;
+      }
+    }
+    return;
+  }
+  last_enqueued_timestamp = media_frame->timestamp();
+
   // The scaled video frames are currently ignored.
   QueueFrame(std::move(media_frame));
 }
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.h b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.h
index 1bbd4f6..163082f 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.h
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.h
@@ -7,6 +7,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/sequence_checker.h"
+#include "media/base/timestamp_constants.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_sink.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h"
 #include "third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.h"
@@ -73,6 +74,10 @@
 
   const Member<MediaStreamComponent> track_;
 
+  // State for handling duplicate frames. Only accessed from the IO thread.
+  base::TimeDelta last_enqueued_timestamp = media::kNoTimestamp;
+  bool reported_out_of_order_timestamp = false;
+
   SEQUENCE_CHECKER(sequence_checker_);
 };
 
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source_test.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source_test.cc
index 2a55940..76c971e2 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source_test.cc
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source_test.cc
@@ -396,8 +396,9 @@
   };
 
   Vector<scoped_refptr<media::VideoFrame>> frames;
-  auto create_video_frame = [&]() {
+  auto create_video_frame = [&](const base::TimeDelta timestamp) {
     auto frame = media::VideoFrame::CreateBlackFrame(gfx::Size(10, 10));
+    frame->set_timestamp(timestamp);
     frames.push_back(frame);
     return frame;
   };
@@ -406,7 +407,7 @@
   EXPECT_TRUE(monitor.IsEmpty());
   // These frames are queued, pending to be read.
   for (size_t i = 0; i < max_frame_count; ++i) {
-    auto video_frame = create_video_frame();
+    auto video_frame = create_video_frame(base::Seconds(i));
     int frame_id = video_frame->unique_id();
     push_frame_sync(std::move(video_frame));
     EXPECT_EQ(monitor.NumFrames(device_id), i + 1);
@@ -414,7 +415,7 @@
   }
   {
     // Push another video frame with the limit reached.
-    auto video_frame = create_video_frame();
+    auto video_frame = create_video_frame(base::Seconds(max_frame_count));
     int frame_id = video_frame->unique_id();
     push_frame_sync(std::move(video_frame));
     EXPECT_EQ(monitor.NumFrames(device_id), max_frame_count);
@@ -441,7 +442,7 @@
   // A new frame arrives, but the limit has been reached and there is nothing
   // that can be replaced.
   {
-    auto video_frame = create_video_frame();
+    auto video_frame = create_video_frame(base::Seconds(max_frame_count + 1));
     int frame_id = video_frame->unique_id();
     push_frame_sync(std::move(video_frame));
     EXPECT_EQ(monitor.NumFrames(device_id), max_frame_count);
@@ -534,4 +535,64 @@
   EXPECT_TRUE(monitor.IsEmpty());
 }
 
+TEST_F(MediaStreamVideoTrackUnderlyingSourceTest, DropDuplicateFrames) {
+  V8TestingScope v8_scope;
+  ScriptState* script_state = v8_scope.GetScriptState();
+  auto* track = CreateTrack(v8_scope.GetExecutionContext());
+  auto* source = CreateSource(script_state, track, /*buffer_size=*/2);
+  auto* stream =
+      ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0);
+
+  // Push a frame at timestamp 1 multiple times, followed by one at timestamp 2.
+  base::TimeDelta timestamp1 = base::Seconds(1);
+  PushFrame(timestamp1);
+  PushFrame(timestamp1);
+  PushFrame(timestamp1);
+  PushFrame(base::Seconds(2));
+
+  NonThrowableExceptionState exception_state;
+  auto* reader =
+      stream->GetDefaultReaderForTesting(script_state, exception_state);
+
+  // The duplicate timestamp frames should have been discarded, leaving only
+  // those with distinct times.
+  for (wtf_size_t i = 1; i <= 2; ++i) {
+    VideoFrame* video_frame =
+        ReadObjectFromStream<VideoFrame>(v8_scope, reader);
+    EXPECT_EQ(base::Microseconds(*video_frame->timestamp()), base::Seconds(i));
+  }
+
+  source->Close();
+  track->stopTrack(v8_scope.GetExecutionContext());
+}
+
+TEST_F(MediaStreamVideoTrackUnderlyingSourceTest, DropOutOfOrderFrames) {
+  V8TestingScope v8_scope;
+  ScriptState* script_state = v8_scope.GetScriptState();
+  auto* track = CreateTrack(v8_scope.GetExecutionContext());
+  auto* source = CreateSource(script_state, track, /*buffer_size=*/2);
+  auto* stream =
+      ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0);
+
+  // Push an out of order frame between timestamps 2 and 3.
+  PushFrame(base::Seconds(2));
+  PushFrame(base::Seconds(1));
+  PushFrame(base::Seconds(3));
+
+  NonThrowableExceptionState exception_state;
+  auto* reader =
+      stream->GetDefaultReaderForTesting(script_state, exception_state);
+
+  // The out of order frame should have been discarded, leaving timestamps 2
+  // and 3.
+  for (wtf_size_t i = 2; i <= 3; ++i) {
+    VideoFrame* video_frame =
+        ReadObjectFromStream<VideoFrame>(v8_scope, reader);
+    EXPECT_EQ(base::Microseconds(*video_frame->timestamp()), base::Seconds(i));
+  }
+
+  source->Close();
+  track->stopTrack(v8_scope.GetExecutionContext());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/cache_storage/cache.cc b/third_party/blink/renderer/modules/cache_storage/cache.cc
index d4af5934..3e9cad4e 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache.cc
@@ -544,47 +544,25 @@
 // Used to handle the ScopedFetcher::Fetch promise in AddAllImpl.
 // TODO(nhiroki): Unfortunately, we have to go through V8 to wait for the fetch
 // promise. It should be better to achieve this only within C++ world.
-class Cache::FetchHandler final : public ScriptFunction {
+class Cache::FetchHandler final : public NewScriptFunction::Callable {
  public:
   // |exception_state| is passed so that the context_type, interface_name and
   // property_name can be copied and then used to construct a new ExceptionState
   // object asynchronously later.
-  static v8::Local<v8::Function> CreateForResolve(
-      ScriptState* script_state,
-      ResponseBodyLoader* response_loader,
-      BarrierCallbackForPutResponse* barrier_callback,
-      const ExceptionContext& exception_context) {
-    FetchHandler* self = MakeGarbageCollected<FetchHandler>(
-        script_state, response_loader, barrier_callback, exception_context);
-    return self->BindToV8Function();
-  }
-
-  static v8::Local<v8::Function> CreateForReject(
-      ScriptState* script_state,
-      BarrierCallbackForPutResponse* barrier_callback,
-      const ExceptionContext& exception_context) {
-    FetchHandler* self = MakeGarbageCollected<FetchHandler>(
-        script_state, /*response_loader=*/nullptr, barrier_callback,
-        exception_context);
-    return self->BindToV8Function();
-  }
-
-  FetchHandler(ScriptState* script_state,
-               ResponseBodyLoader* response_loader,
+  FetchHandler(ResponseBodyLoader* response_loader,
                BarrierCallbackForPutResponse* barrier_callback,
                const ExceptionContext& exception_context)
-      : ScriptFunction(script_state),
-        response_loader_(response_loader),
+      : response_loader_(response_loader),
         barrier_callback_(barrier_callback),
         exception_context_(exception_context) {}
 
-  ScriptValue Call(ScriptValue value) override {
+  ScriptValue Call(ScriptState* script_state, ScriptValue value) override {
     // We always resolve undefined from this promise handler since the
     // promise is never returned to script or chained to another handler.
     // If we return our real result and an exception occurs then unhandled
     // promise errors will occur.
     ScriptValue rtn =
-        ScriptPromise::CastUndefined(GetScriptState()).AsScriptValue();
+        ScriptPromise::CastUndefined(script_state).AsScriptValue();
 
     // If there is no loader, we were created as a reject handler.
     if (!response_loader_) {
@@ -592,12 +570,12 @@
       return rtn;
     }
 
-    ExceptionState exception_state(GetScriptState()->GetIsolate(),
+    ExceptionState exception_state(script_state->GetIsolate(),
                                    exception_context_);
 
     // Resolve handler, so try to process a Response.
     Response* response = NativeValueTraits<Response>::NativeValue(
-        GetScriptState()->GetIsolate(), value.V8Value(), exception_state);
+        script_state->GetIsolate(), value.V8Value(), exception_state);
     if (exception_state.HadException())
       barrier_callback_->OnError(exception_state);
     else
@@ -609,7 +587,7 @@
   void Trace(Visitor* visitor) const override {
     visitor->Trace(response_loader_);
     visitor->Trace(barrier_callback_);
-    ScriptFunction::Trace(visitor);
+    NewScriptFunction::Callable::Trace(visitor);
   }
 
  private:
@@ -1127,13 +1105,19 @@
     auto* response_loader = MakeGarbageCollected<ResponseBodyLoader>(
         script_state, barrier_callback, i, /*require_ok_response=*/true,
         trace_id);
+    auto* on_resolve = MakeGarbageCollected<NewScriptFunction>(
+        script_state,
+        MakeGarbageCollected<FetchHandler>(response_loader, barrier_callback,
+                                           exception_state.GetContext()));
+    // The |response_loader=nullptr| makes this handler a reject handler
+    // internally.
+    auto* on_reject = MakeGarbageCollected<NewScriptFunction>(
+        script_state, MakeGarbageCollected<FetchHandler>(
+                          /*response_loader=*/nullptr, barrier_callback,
+                          exception_state.GetContext()));
     scoped_fetcher_
         ->Fetch(script_state, info, RequestInit::Create(), exception_state)
-        .Then(FetchHandler::CreateForResolve(script_state, response_loader,
-                                             barrier_callback,
-                                             exception_state.GetContext()),
-              FetchHandler::CreateForReject(script_state, barrier_callback,
-                                            exception_state.GetContext()));
+        .Then(on_resolve, on_reject);
   }
 
   return promise;
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
index 6289cf64..3ac6680 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-blink.h"
 #include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_clipboard_item_options.h"
 #include "third_party/blink/renderer/core/clipboard/clipboard_mime_types.h"
@@ -47,7 +48,7 @@
 // This class deals with all the Blob promises and executes the write
 // operation after all the promises have been resolved.
 class ClipboardPromise::BlobPromiseResolverFunction final
-    : public ScriptFunction {
+    : public NewScriptFunction::Callable {
  public:
   enum class ResolveType { kFulfill, kReject };
 
@@ -55,41 +56,32 @@
                      ScriptPromise promise,
                      ClipboardPromise* clipboard_promise) {
     promise.Then(
-        CreateFunction(script_state, clipboard_promise, ResolveType::kFulfill),
-        CreateFunction(script_state, clipboard_promise, ResolveType::kReject));
+        MakeGarbageCollected<NewScriptFunction>(
+            script_state, MakeGarbageCollected<BlobPromiseResolverFunction>(
+                              clipboard_promise, ResolveType::kFulfill)),
+        MakeGarbageCollected<NewScriptFunction>(
+            script_state, MakeGarbageCollected<BlobPromiseResolverFunction>(
+                              clipboard_promise, ResolveType::kReject)));
   }
 
-  BlobPromiseResolverFunction(ScriptState* script_state,
-                              ClipboardPromise* clipboard_promise,
+  BlobPromiseResolverFunction(ClipboardPromise* clipboard_promise,
                               ResolveType type)
-      : ScriptFunction(script_state),
-        clipboard_promise_(clipboard_promise),
-        type_(type) {}
+      : clipboard_promise_(clipboard_promise), type_(type) {}
 
   void Trace(Visitor* visitor) const final {
-    ScriptFunction::Trace(visitor);
+    NewScriptFunction::Callable::Trace(visitor);
     visitor->Trace(clipboard_promise_);
   }
 
- private:
-  static v8::Local<v8::Function> CreateFunction(
-      ScriptState* script_state,
-      ClipboardPromise* clipboard_promise,
-      ResolveType type) {
-    return MakeGarbageCollected<BlobPromiseResolverFunction>(
-               script_state, clipboard_promise, type)
-        ->BindToV8Function();
-  }
-
-  ScriptValue Call(ScriptValue value) final {
-    ExceptionState exception_state(GetScriptState()->GetIsolate(),
+  ScriptValue Call(ScriptState* script_state, ScriptValue value) final {
+    ExceptionState exception_state(script_state->GetIsolate(),
                                    ExceptionState::kExecutionContext,
                                    "Clipboard", "write");
     if (type_ == ResolveType::kFulfill) {
       HeapVector<Member<Blob>>* blob_list =
           MakeGarbageCollected<HeapVector<Member<Blob>>>(
               NativeValueTraits<IDLSequence<Blob>>::NativeValue(
-                  GetScriptState()->GetIsolate(), value.V8Value(),
+                  script_state->GetIsolate(), value.V8Value(),
                   exception_state));
       if (exception_state.HadException()) {
         // Clear the exception here as it'll be fired in `RejectBlobPromise`.
@@ -115,6 +107,7 @@
     return ScriptValue();
   }
 
+ private:
   Member<ClipboardPromise> clipboard_promise_;
   ResolveType type_;
 };
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_promise.h b/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
index a11958f..28c5184 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
@@ -10,7 +10,6 @@
 #include "base/sequence_checker.h"
 #include "third_party/blink/public/mojom/permissions/permission.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc b/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
index b4f3f068..51db1f6 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
@@ -386,6 +386,11 @@
 
   if (transaction_backend())
     transaction_backend()->Commit(num_errors_handled_);
+
+  // Once IDBtransaction.commit() is called, the page should no longer be
+  // prevented from entering back/forward cache for having outstanding IDB
+  // connections. Commit ends the inflight IDB transactions.
+  feature_handle_for_scheduler_.reset();
 }
 
 void IDBTransaction::RegisterRequest(IDBRequest* request) {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
index 0504073c..9789bf06 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -2031,86 +2031,29 @@
 }
 
 String RTCPeerConnection::signalingState() const {
-  switch (signaling_state_) {
-    case webrtc::PeerConnectionInterface::SignalingState::kStable:
-      return "stable";
-    case webrtc::PeerConnectionInterface::SignalingState::kHaveLocalOffer:
-      return "have-local-offer";
-    case webrtc::PeerConnectionInterface::SignalingState::kHaveRemoteOffer:
-      return "have-remote-offer";
-    case webrtc::PeerConnectionInterface::SignalingState::kHaveLocalPrAnswer:
-      return "have-local-pranswer";
-    case webrtc::PeerConnectionInterface::SignalingState::kHaveRemotePrAnswer:
-      return "have-remote-pranswer";
-    case webrtc::PeerConnectionInterface::SignalingState::kClosed:
-      return "closed";
-  }
-
-  NOTREACHED();
-  return String();
+  return String(
+      webrtc::PeerConnectionInterface::AsString(signaling_state_).data());
 }
 
 String RTCPeerConnection::iceGatheringState() const {
-  switch (ice_gathering_state_) {
-    case webrtc::PeerConnectionInterface::kIceGatheringNew:
-      return "new";
-    case webrtc::PeerConnectionInterface::kIceGatheringGathering:
-      return "gathering";
-    case webrtc::PeerConnectionInterface::kIceGatheringComplete:
-      return "complete";
-  }
-
-  NOTREACHED();
-  return String();
+  return String(
+      webrtc::PeerConnectionInterface::AsString(ice_gathering_state_).data());
 }
 
 String RTCPeerConnection::iceConnectionState() const {
   if (closed_) {
     return "closed";
   }
-  switch (ice_connection_state_) {
-    case webrtc::PeerConnectionInterface::kIceConnectionNew:
-      return "new";
-    case webrtc::PeerConnectionInterface::kIceConnectionChecking:
-      return "checking";
-    case webrtc::PeerConnectionInterface::kIceConnectionConnected:
-      return "connected";
-    case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
-      return "completed";
-    case webrtc::PeerConnectionInterface::kIceConnectionFailed:
-      return "failed";
-    case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
-      return "disconnected";
-    case webrtc::PeerConnectionInterface::kIceConnectionClosed:
-      return "closed";
-    case webrtc::PeerConnectionInterface::kIceConnectionMax:
-      NOTREACHED();
-  }
-  NOTREACHED();
-  return String();
+  return String(
+      webrtc::PeerConnectionInterface::AsString(ice_connection_state_).data());
 }
 
 String RTCPeerConnection::connectionState() const {
   if (closed_) {
     return "closed";
   }
-  switch (peer_connection_state_) {
-    case webrtc::PeerConnectionInterface::PeerConnectionState::kNew:
-      return "new";
-    case webrtc::PeerConnectionInterface::PeerConnectionState::kConnecting:
-      return "connecting";
-    case webrtc::PeerConnectionInterface::PeerConnectionState::kConnected:
-      return "connected";
-    case webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected:
-      return "disconnected";
-    case webrtc::PeerConnectionInterface::PeerConnectionState::kFailed:
-      return "failed";
-    case webrtc::PeerConnectionInterface::PeerConnectionState::kClosed:
-      return "closed";
-  }
-
-  NOTREACHED();
-  return String();
+  return String(
+      webrtc::PeerConnectionInterface::AsString(peer_connection_state_).data());
 }
 
 absl::optional<bool> RTCPeerConnection::canTrickleIceCandidates() const {
diff --git a/third_party/blink/renderer/modules/serial/serial_port.cc b/third_party/blink/renderer/modules/serial/serial_port.cc
index fc20231..728f2cc3 100644
--- a/third_party/blink/renderer/modules/serial/serial_port.cc
+++ b/third_party/blink/renderer/modules/serial/serial_port.cc
@@ -112,25 +112,17 @@
 }
 
 // A ScriptFunction that calls ContinueClose() on the provided SerialPort.
-class ContinueCloseFunction : public ScriptFunction {
+class ContinueCloseFunction : public NewScriptFunction::Callable {
  public:
-  static v8::Local<v8::Function> Create(ScriptState* script_state,
-                                        SerialPort* port) {
-    auto* self =
-        MakeGarbageCollected<ContinueCloseFunction>(script_state, port);
-    return self->BindToV8Function();
-  }
+  explicit ContinueCloseFunction(SerialPort* port) : port_(port) {}
 
-  ContinueCloseFunction(ScriptState* script_state, SerialPort* port)
-      : ScriptFunction(script_state), port_(port) {}
-
-  ScriptValue Call(ScriptValue) override {
-    return port_->ContinueClose(GetScriptState()).AsScriptValue();
+  ScriptValue Call(ScriptState* script_state, ScriptValue) override {
+    return port_->ContinueClose(script_state).AsScriptValue();
   }
 
   void Trace(Visitor* visitor) const override {
     visitor->Trace(port_);
-    ScriptFunction::Trace(visitor);
+    NewScriptFunction::Callable::Trace(visitor);
   }
 
  private:
@@ -138,25 +130,18 @@
 };
 
 // A ScriptFunction that calls AbortClose() on the provided SerialPort.
-class AbortCloseFunction : public ScriptFunction {
+class AbortCloseFunction : public NewScriptFunction::Callable {
  public:
-  static v8::Local<v8::Function> Create(ScriptState* script_state,
-                                        SerialPort* port) {
-    auto* self = MakeGarbageCollected<AbortCloseFunction>(script_state, port);
-    return self->BindToV8Function();
-  }
+  explicit AbortCloseFunction(SerialPort* port) : port_(port) {}
 
-  AbortCloseFunction(ScriptState* script_state, SerialPort* port)
-      : ScriptFunction(script_state), port_(port) {}
-
-  ScriptValue Call(ScriptValue) override {
+  ScriptValue Call(ScriptState*, ScriptValue) override {
     port_->AbortClose();
     return ScriptValue();
   }
 
   void Trace(Visitor* visitor) const override {
     visitor->Trace(port_);
-    ScriptFunction::Trace(visitor);
+    NewScriptFunction::Callable::Trace(visitor);
   }
 
  private:
@@ -431,8 +416,11 @@
   }
 
   return ScriptPromise::All(script_state, promises)
-      .Then(ContinueCloseFunction::Create(script_state, this),
-            AbortCloseFunction::Create(script_state, this));
+      .Then(
+          MakeGarbageCollected<NewScriptFunction>(
+              script_state, MakeGarbageCollected<ContinueCloseFunction>(this)),
+          MakeGarbageCollected<NewScriptFunction>(
+              script_state, MakeGarbageCollected<AbortCloseFunction>(this)));
 }
 
 ScriptPromise SerialPort::ContinueClose(ScriptState* script_state) {
diff --git a/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc b/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
index 9e18f8a..2fa8fd68 100644
--- a/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
+++ b/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
@@ -36,39 +36,27 @@
 
 }  // anonymous namespace
 
-class WaitUntilObserver::ThenFunction final : public ScriptFunction {
+class WaitUntilObserver::ThenFunction final
+    : public NewScriptFunction::Callable {
  public:
   enum ResolveType {
     kFulfilled,
     kRejected,
   };
 
-  static v8::Local<v8::Function> CreateFunction(
-      ScriptState* script_state,
-      WaitUntilObserver* observer,
-      ResolveType type,
-      PromiseSettledCallback callback) {
-    ThenFunction* self = MakeGarbageCollected<ThenFunction>(
-        script_state, observer, type, std::move(callback));
-    return self->BindToV8Function();
-  }
-
-  ThenFunction(ScriptState* script_state,
-               WaitUntilObserver* observer,
+  ThenFunction(WaitUntilObserver* observer,
                ResolveType type,
                PromiseSettledCallback callback)
-      : ScriptFunction(script_state),
-        observer_(observer),
+      : observer_(observer),
         resolve_type_(type),
         callback_(std::move(callback)) {}
 
   void Trace(Visitor* visitor) const override {
     visitor->Trace(observer_);
-    ScriptFunction::Trace(visitor);
+    NewScriptFunction::Callable::Trace(visitor);
   }
 
- private:
-  ScriptValue Call(ScriptValue value) override {
+  ScriptValue Call(ScriptState* script_state, ScriptValue value) override {
     DCHECK(observer_);
     DCHECK(resolve_type_ == kFulfilled || resolve_type_ == kRejected);
     if (callback_)
@@ -79,7 +67,7 @@
     // substeps: Decrement the pending promises count by one."
 
     scoped_refptr<scheduler::EventLoop> event_loop =
-        ExecutionContext::From(GetScriptState())->GetAgent()->event_loop();
+        ExecutionContext::From(script_state)->GetAgent()->event_loop();
 
     // At this time point the microtask A running resolve/reject function of
     // this promise has already been queued, in order to allow microtask A to
@@ -93,7 +81,7 @@
           WTF::Bind(&WaitUntilObserver::OnPromiseRejected,
                     WrapPersistent(observer_.Get())));
       observer_ = nullptr;
-      return ScriptPromise::Reject(GetScriptState(), value).AsScriptValue();
+      return ScriptPromise::Reject(script_state, value).AsScriptValue();
     }
 
     event_loop->EnqueueMicrotask(
@@ -103,6 +91,7 @@
     return value;
   }
 
+ private:
   Member<WaitUntilObserver> observer_;
   ResolveType resolve_type_;
   PromiseSettledCallback callback_;
@@ -166,11 +155,14 @@
   // 3. `Add f to the extend lifetime promises.`
   // 4. `Increment the pending promises count by one.`
   IncrementPendingPromiseCount();
-  script_promise.Then(
-      ThenFunction::CreateFunction(script_state, this, ThenFunction::kFulfilled,
-                                   std::move(on_promise_fulfilled)),
-      ThenFunction::CreateFunction(script_state, this, ThenFunction::kRejected,
-                                   std::move(on_promise_rejected)));
+  script_promise.Then(MakeGarbageCollected<NewScriptFunction>(
+                          script_state, MakeGarbageCollected<ThenFunction>(
+                                            this, ThenFunction::kFulfilled,
+                                            std::move(on_promise_fulfilled))),
+                      MakeGarbageCollected<NewScriptFunction>(
+                          script_state, MakeGarbageCollected<ThenFunction>(
+                                            this, ThenFunction::kRejected,
+                                            std::move(on_promise_rejected))));
   return true;
 }
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
index 09beffc..7e9e2fb 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
@@ -214,7 +214,8 @@
     EXPECT_TRUE(processor);
     EXPECT_EQ(processor->Name(), "testProcessor");
     v8::Local<v8::Value> processor_value =
-        ToV8(processor, script_state->GetContext()->Global(), isolate);
+        ToV8Traits<AudioWorkletProcessor>::ToV8(script_state, processor)
+            .ToLocalChecked();
     EXPECT_TRUE(processor_value->IsObject());
 
     wait_event->Signal();
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index f2a785a..9ba2998 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -594,6 +594,15 @@
       GetDrawingBuffer()->TransferToStaticBitmapImage());
 }
 
+void WebGLRenderingContextBase::drawingBufferStorage(GLenum sizedformat,
+                                                     GLsizei width,
+                                                     GLsizei height) {
+  if (!GetDrawingBuffer())
+    return;
+
+  NOTIMPLEMENTED();
+}
+
 void WebGLRenderingContextBase::commit() {
   if (!GetDrawingBuffer() || (Host() && Host()->IsOffscreenCanvas()))
     return;
@@ -1836,6 +1845,10 @@
   return isContextLost() ? 0 : GetDrawingBuffer()->Size().height();
 }
 
+GLenum WebGLRenderingContextBase::drawingBufferFormat() const {
+  return isContextLost() ? 0 : GetDrawingBuffer()->StorageFormat();
+}
+
 void WebGLRenderingContextBase::activeTexture(GLenum texture) {
   if (isContextLost())
     return;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
index 70b0712a..1cbe02a58 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -173,6 +173,7 @@
 
   int drawingBufferWidth() const;
   int drawingBufferHeight() const;
+  GLenum drawingBufferFormat() const;
 
   void activeTexture(GLenum texture);
   void attachShader(WebGLProgram*, WebGLShader*);
@@ -642,6 +643,8 @@
 
   V8UnionHTMLCanvasElementOrOffscreenCanvas* getHTMLOrOffscreenCanvas() const;
 
+  void drawingBufferStorage(GLenum sizedformat, GLsizei width, GLsizei height);
+
   void commit();
 
   ScriptPromise makeXRCompatible(ScriptState*, ExceptionState&);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl
index 172e2045..a90022f 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl
@@ -464,6 +464,7 @@
 
     readonly attribute GLsizei drawingBufferWidth;
     readonly attribute GLsizei drawingBufferHeight;
+    [RuntimeEnabled=CanvasColorManagementV2] readonly attribute GLenum drawingBufferFormat;
 
     void activeTexture(GLenum texture);
     void attachShader(WebGLProgram program, WebGLShader shader);
@@ -712,6 +713,8 @@
 
     [NoAllocDirectCall] void viewport(GLint x, GLint y, GLsizei width, GLsizei height);
 
+    [RuntimeEnabled=CanvasColorManagementV2] void drawingBufferStorage(GLenum sizedformat, GLsizei width, GLsizei height);
+
     [RuntimeEnabled=OffscreenCanvasCommit] void commit();
 
     // WebXR Device API support
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
index 5e2b67e3..4179c3f 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
@@ -83,7 +83,6 @@
                                        unsigned start_index,
                                        unsigned num_glyphs,
                                        unsigned num_characters) {
-    CHECK_GT(num_glyphs, 0u);
     CHECK_GT(num_characters, 0u);
     return base::AdoptRef(new RunInfo(font, dir, canvas_rotation, script,
                                       start_index, num_glyphs, num_characters));
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
index ffc163b6..cd107ffff 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -1614,6 +1614,10 @@
   gl_->BindFramebuffer(target, WantExplicitResolve() ? multisample_fbo_ : fbo_);
 }
 
+GLenum DrawingBuffer::StorageFormat() const {
+  return want_alpha_channel_ ? GL_RGBA8 : GL_RGB8;
+}
+
 sk_sp<SkData> DrawingBuffer::PaintRenderingResultsToDataArray(
     SourceDrawingBuffer source_buffer) {
   ScopedStateRestorer scoped_state_restorer(this);
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
index db29344..a6696c0 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
@@ -184,6 +184,7 @@
   // GL_FRAMEBUFFER, GL_READ_FRAMEBUFFER, or GL_DRAW_FRAMEBUFFER.
   void Bind(GLenum target);
   IntSize Size() const { return size_; }
+  GLenum StorageFormat() const;
 
   // Resolves the multisample color buffer to the normal color buffer and leaves
   // the resolved color buffer bound to GL_READ_FRAMEBUFFER and
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc
index 7f162b9b..eda9ebc0 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc
@@ -218,9 +218,6 @@
 RTCVideoDecoderFactory::GetSupportedFormats() const {
   CheckAndWaitDecoderSupportStatusIfNeeded();
 
-  media::SupportedVideoDecoderConfigs supported_decoder_factory_configs =
-      decoder_factory_->GetSupportedVideoDecoderConfigsForWebRTC();
-
   // For now, ignore `kUseDecoderStreamForWebRTC`, and advertise support only
   // for hardware-accelerated formats.  For some codecs, like AV1, which don't
   // have an equivalent in rtc, we might want to include them anyway.
@@ -242,15 +239,11 @@
       format = VdcToWebRtcFormat(config);
     }
 
-    if (base::FeatureList::IsEnabled(media::kUseDecoderStreamForWebRTC) &&
-        !format.has_value()) {
-      for (auto& supported_config : supported_decoder_factory_configs) {
-        if (supported_config.Matches(config)) {
-          format = VdcToWebRtcFormat(config);
-          break;
-        }
-      }
-    }
+    // TODO(https://crbug.com/1274904): Temporarily do not add configs from
+    // `decoder_factory_`, so that supported configs are identical.
+    // See:
+    // https://chromium-review.googlesource.com/c/chromium/src/+/3305493
+    // For the exact diff.
 
     if (format)
       supported_formats.push_back(*format);
@@ -306,19 +299,12 @@
   // The codec must be supported if it's power efficient.
   codec_support.is_supported = codec_support.is_power_efficient;
 
-  // RtcDecoderStreamAdapter supports all codecs with HW support and potentially
-  // a few codecs in SW.
-  if (!codec_support.is_supported &&
-      base::FeatureList::IsEnabled(media::kUseDecoderStreamForWebRTC)) {
-    media::SupportedVideoDecoderConfigs supported_decoder_factory_configs =
-        decoder_factory_->GetSupportedVideoDecoderConfigsForWebRTC();
-    for (auto& supported_config : supported_decoder_factory_configs) {
-      if (supported_config.Matches(config)) {
-        codec_support.is_supported = true;
-        break;
-      }
-    }
-  }
+  // TODO(https://crbug.com/1274904): Temporarily do not check
+  // `decoder_factory_` for additional support, to make codec
+  // DecoderAdapter and DecoderStreamAdapter the same.
+  // See:
+  // https://chromium-review.googlesource.com/c/chromium/src/+/3305493
+  // For the exact diff.
 
   return codec_support;
 }
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc
index 469c2601..f39f7f8 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc
@@ -228,6 +228,14 @@
   if (WebRtcToMediaVideoCodec(video_codec_type) == media::VideoCodec::kUnknown)
     return nullptr;
 
+  if (!gpu_factories &&
+      !base::FeatureList::IsEnabled(media::kExposeSwDecodersToWebRTC)) {
+    // Interpret "no gpu factories" to mean "sw only", even though we don't
+    // technically know if `decoder_factory` can create hw decoders or not.  To
+    // make it unambiguous, and probably save a thread hop, fail immediately.
+    return nullptr;
+  }
+
   // Avoid the thread hop if the decoder is known not to support the config.
   // TODO(sandersd): Predict size from level.
   media::VideoDecoderConfig config(
@@ -240,6 +248,14 @@
 
   config.set_is_rtc(true);
 
+  // TODO(https://crbug.com/1274904): Fail early to match DecoderAdapter.
+  if (gpu_factories &&
+      gpu_factories->IsDecoderConfigSupported(config) ==
+          media::GpuVideoAcceleratorFactories::Supported::kFalse) {
+    base::UmaHistogramBoolean("Media.RTCVideoDecoderInitDecodeSuccess", false);
+    return nullptr;
+  }
+
   // InitializeSync doesn't really initialize anything; it just posts the work
   // to the media thread.  If init fails, then we'll fall back on the first
   // decode after we notice.
@@ -324,6 +340,10 @@
 
   base::AutoLock auto_lock(lock_);
   init_decode_complete_ = true;
+  // Interpret "no gpu factories" to mean "no hw decoders", regardless of
+  // whether or not the decoder factory can produce them.  Probably, it can't.
+  if (!gpu_factories_)
+    prefer_software_decoders_ = true;
   const webrtc::RenderResolution& resolution = settings.max_render_resolution();
   if (resolution.Valid()) {
     // This lets our initial decoder selection see something that's at least
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter_test.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter_test.cc
index 6f90465..a074853e 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter_test.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter_test.cc
@@ -191,6 +191,9 @@
     decoder_factory_ = std::make_unique<MockDecoderFactory>();
     // Create one hw decoder.
     decoder_factory_->CreatePendingDecoder(true);
+    // Unless specifically overridden by a test, the gpu claims to support any
+    // decoder config.
+    SetGpuFactorySupport(true);
   }
 
   RTCVideoDecoderStreamAdapterTest(const RTCVideoDecoderStreamAdapterTest&) =
@@ -246,7 +249,6 @@
     SetUpMockDecoder(decoder, init_cb_result);
   }
 
-  // Create a DecoderStreamAdapter in `adapter_` using the decoder factory.
   bool CreateDecoderStream() {
     adapter_ = RTCVideoDecoderStreamAdapter::Create(
         use_hw_decoders_ ? &gpu_factories_ : nullptr, decoder_factory_.get(),
@@ -301,6 +303,27 @@
 
   int32_t Release() { return adapter_->Release(); }
 
+  // Notify `gpu_factories_` if it is supposed to claim to support all decoder
+  // config or none of them.
+  void SetGpuFactorySupport(bool supported) {
+    // Use EXPECT_CALL rather than ON_CALL so it doesn't warn.
+    EXPECT_CALL(gpu_factories_, IsDecoderConfigSupported(_))
+        .Times(AtLeast(0))
+        .WillRepeatedly(Return(
+            supported
+                ? media::GpuVideoAcceleratorFactories::Supported::kTrue
+                : media::GpuVideoAcceleratorFactories::Supported::kFalse));
+  }
+
+  bool GetUseHwDecoders() const { return use_hw_decoders_; }
+
+  // Override our use of hw decoders.  Generally you should not use this -- it
+  // will be set by the test parameters.  However, we allow it for the very few
+  // tests that actually care.
+  void OverrideHwDecoders(bool use_hw_decoders) {
+    use_hw_decoders_ = use_hw_decoders;
+  }
+
   webrtc::EncodedImage GetEncodedImageWithColorSpace(uint32_t timestamp) {
     webrtc::EncodedImage input_image;
     static const uint8_t data[1] = {0};
@@ -320,7 +343,7 @@
   base::test::TaskEnvironment task_environment_;
   scoped_refptr<base::SequencedTaskRunner> media_thread_task_runner_;
 
-  const bool use_hw_decoders_;
+  bool use_hw_decoders_;
   StrictMock<media::MockGpuVideoAcceleratorFactories> gpu_factories_{
       nullptr /* SharedImageInterface* */};
   std::unique_ptr<MockDecoderFactory> decoder_factory_;
@@ -349,6 +372,17 @@
   ASSERT_FALSE(adapter);
 }
 
+TEST_P(RTCVideoDecoderStreamAdapterTest, FailInitIfNoHwNorSwDecoders) {
+  // If the adapter is configured to use neither hw nor sw decoders, then Create
+  // should fail immediately.
+  const bool allow_sw = GetParam().use_chrome_sw_decoders ==
+                        TestParams::UseChromeSwDecoders::kYes;
+  if (!allow_sw) {
+    OverrideHwDecoders(false);
+    EXPECT_FALSE(CreateDecoderStream());
+  }  // else pass trivially
+}
+
 TEST_P(RTCVideoDecoderStreamAdapterTest, FailInit_DecodeFails) {
   // If decoder initialization fails after InitDecode runs, then the first
   // Decode should fail.  If chrome sw decoders are allowed, then it should
@@ -375,6 +409,15 @@
   }
 }
 
+TEST_P(RTCVideoDecoderStreamAdapterTest, UnsupportedGpuConfigFailsImmediately) {
+  // If the gpu factories don't claim to support a config, then it shouldn't
+  // create the decoder.
+  if (GetUseHwDecoders()) {
+    SetGpuFactorySupport(false);
+    EXPECT_FALSE(CreateDecoderStream());
+  }  // else pass.
+}
+
 TEST_P(RTCVideoDecoderStreamAdapterTest, MissingFramesRequestsKeyframe) {
   EXPECT_TRUE(BasicSetup());
   EXPECT_EQ(Decode(0, true), WEBRTC_VIDEO_CODEC_ERROR);
@@ -543,7 +586,7 @@
     UseHwDecoding,
     RTCVideoDecoderStreamAdapterTest,
     ::testing::Values(TestParams{TestParams::UseHwDecoders::kNo,
-                                 TestParams::UseChromeSwDecoders::kNo},
+                                 TestParams::UseChromeSwDecoders::kYes},
                       TestParams{TestParams::UseHwDecoders::kYes,
                                  TestParams::UseChromeSwDecoders::kNo},
                       TestParams{TestParams::UseHwDecoders::kYes,
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 498a835..d6c87c86f 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1023,10 +1023,6 @@
       status: "test",
     },
     {
-      name: "FeaturePolicyForClientHints",
-      status: "stable",
-    },
-    {
       name: "FeaturePolicyReporting",
       status: "experimental"
     },
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
index e21608eb..a3c489c3 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
+++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -289,10 +289,7 @@
 crbug.com/1012289 external/wpt/css/css-pseudo/marker-unicode-bidi-default.html [ Failure ]
 crbug.com/1012289 external/wpt/css/css-pseudo/marker-unicode-bidi-normal.html [ Failure ]
 crbug.com/1147859 external/wpt/css/css-pseudo/selection-decoration-p3.html [ Failure ]
-crbug.com/1136817 external/wpt/css/css-pseudo/target-text-001.html [ Failure ]
-crbug.com/1136817 external/wpt/css/css-pseudo/target-text-002.html [ Failure ]
 crbug.com/1136817 external/wpt/css/css-pseudo/target-text-004.html [ Pass ]
-crbug.com/1136817 external/wpt/css/css-pseudo/target-text-005.html [ Failure ]
 crbug.com/1136817 external/wpt/css/css-pseudo/target-text-007.html [ Failure ]
 crbug.com/1035708 wpt_internal/css/css-pseudo/spelling-error-color-001.html [ Failure ]
 crbug.com/1035708 wpt_internal/css/css-pseudo/spelling-error-color-002.html [ Failure ]
@@ -1158,7 +1155,6 @@
 ### external/wpt/css/css-pseudo/
 crbug.com/591099 external/wpt/css/css-pseudo/active-selection-011.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-pseudo/active-selection-012.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-pseudo/highlight-paired-cascade-004.tentative.html [ Failure ]
 
 ### external/wpt/css/css-writing-modes/
 crbug.com/591099 external/wpt/css/css-writing-modes/table-column-order-002.xht [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 8cddf490..c8e4c0a4 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2796,8 +2796,9 @@
 
 crbug.com/1029514 external/wpt/html/semantics/embedded-content/the-video-element/resize-during-playback.html [ Failure Pass ]
 
-# css-pseudo-4 opacity not applied to ::first-line
+# ::first-line issues
 crbug.com/1085772 external/wpt/css/css-pseudo/first-line-opacity-001.html [ Failure ]
+crbug.com/798257 external/wpt/css/css-pseudo/first-line-line-height-002.html [ Failure ]
 
 # motion-1 issues
 crbug.com/641245 external/wpt/css/motion/offset-path-ray-002.html [ Failure ]
@@ -3010,6 +3011,12 @@
 crbug.com/626703 virtual/plz-dedicated-worker/external/wpt/service-workers/service-worker/navigation-timing-extended.https.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/webrtc/RTCDataChannel-close.html [ Skip Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/webrtc/RTCDataChannel-send-blob-order.html [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/webrtc/RTCPeerConnection-capture-video.https.html [ Skip Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https.html [ Skip Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCDataChannel-send.html [ Skip Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html [ Timeout ]
 crbug.com/626703 [ Mac10.13 ] virtual/backface-visibility-interop/external/wpt/css/css-transforms/css-skew-001.html [ Crash ]
 crbug.com/626703 [ Mac10.13 ] virtual/backface-visibility-interop/external/wpt/css/css-transforms/css-transform-3d-rotateZ-negative.html [ Crash ]
 crbug.com/626703 [ Mac10.13 ] virtual/backface-visibility-interop/external/wpt/css/css-transforms/document-styles/svg-document-styles-003.html [ Crash ]
@@ -3052,10 +3059,8 @@
 crbug.com/626703 [ Mac10.12 ] virtual/container-queries/wpt_internal/css/css-conditional/container-queries/top-layer-001.html [ Crash Failure ]
 crbug.com/626703 [ Mac10.12 ] virtual/scalefactor200/external/wpt/element-timing/cross-origin-element.sub.html [ Crash Failure ]
 crbug.com/626703 [ Mac11 ] wpt_internal/webcodecs/reconfiguring_encoder.https.any.worker.html [ Timeout ]
-crbug.com/626703 external/wpt/css/css-pseudo/first-line-line-height-002.html [ Failure ]
 crbug.com/626703 [ Mac10.15 ] external/wpt/streams/piping/abort.any.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.15 ] external/wpt/streams/piping/abort.any.sharedworker.html [ Crash Failure ]
-crbug.com/626703 virtual/css-highlight-inheritance/external/wpt/css/css-pseudo/first-line-line-height-002.html [ Failure ]
 crbug.com/626703 [ Mac11-arm64 ] virtual/consume-code-cache-off-thread/external/wpt/html/semantics/scripting-1/the-script-element/json-module/parse-error.html [ Timeout ]
 crbug.com/626703 [ Mac11-arm64 ] virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/ch-unit-011.html [ Failure ]
 crbug.com/626703 [ Win10.20h2 ] external/wpt/html/cross-origin-embedder-policy/cross-origin-isolated-permission.https.html [ Timeout ]
@@ -7346,9 +7351,6 @@
 # Flaky on mac 10.13
 crbug.com/1263709 [ Mac10.13 ] http/tests/devtools/elements/node-xpath.js [ Failure ]
 
-# Temporarily disable this test to allow DevTools CL to land: https://crrev.com/c/3306493
-crbug.com/1268754 http/tests/devtools/elements/styles-4/styles-formatting.js [ Failure Pass ]
-
 # Flaky on Mac and Windows
 crbug.com/1272199 external/wpt/websockets/stream/tentative/backpressure-receive.any.serviceworker.html?wpt_flags=h2 [ Failure Pass ]
 crbug.com/1272203 external/wpt/websockets/stream/tentative/backpressure-send.any.serviceworker.html?wpt_flags=h2 [ Failure Pass ]
@@ -7364,11 +7366,11 @@
 crbug.com/1272955 http/tests/devtools/extensions/extensions-timeline-api.js [ Failure Pass ]
 
 # Flaky as depends upon order of execution.
-crbug.com/1274917 external/wpt/content-security-policy/inheritance/history.sub.html [ Timeout Failure Pass ]
-crbug.com/1274917 external/wpt/content-security-policy/inheritance/history-iframe.sub.html [ Timeout Failure Pass ]
+crbug.com/1274917 external/wpt/content-security-policy/inheritance/history.sub.html [ Failure Pass Timeout ]
+crbug.com/1274917 external/wpt/content-security-policy/inheritance/history-iframe.sub.html [ Failure Pass Timeout ]
 
 # Test is very flaky (score of 223).
-crbug.com/1274919 http/tests/inspector-protocol/page/consecutive-navigate.js [ Timeout Pass ]
+crbug.com/1274919 http/tests/inspector-protocol/page/consecutive-navigate.js [ Pass Timeout ]
 
 # Sheriff 2021-11-23
 crbug.com/1270963 wpt_internal/fenced_frame/create-credential.https.html [ Skip ]
@@ -7388,3 +7390,5 @@
 crbug.com/1274458 external/wpt/audio-output/selectAudioOutput-permissions-policy.https.sub.html [ Failure Pass ]
 crbug.com/1239485 [ Mac ] fast/frames/iframe-plugin-load-remove-document-crash.html [ Failure Pass ]
 
+# Sheriff 2021-11-30
+crbug.com/1256763 [ Linux ] virtual/gpu-rasterization/images/color-profile-image-shape.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 00f44f6..81b58e90 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -759,12 +759,6 @@
     "args": ["--disable-features=UserAgentClientHint"]
   },
   {
-    "prefix": "legacy-client-hints-no-fp-delegation",
-    "bases": [ "external/wpt/client-hints" ],
-    "args": [ "--enable-features=AllowClientHintsToThirdParty",
-              "--disable-features=FeaturePolicyForClientHints" ]
-  },
-  {
     "prefix": "storage-access-api",
     "bases": [ "external/wpt/storage-access-api" ],
     "args": [ "--enable-features=StorageAccessAPI" ]
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 7d43d67..335802f 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
@@ -590,6 +590,13 @@
        {}
       ]
      ],
+     "negative-available-size-crash.html": [
+      "837fdaeba9ef8baeb4f2bad281bb13551d6d8ff9",
+      [
+       null,
+       {}
+      ]
+     ],
      "negative-flex-margins-crash.html": [
       "8bcc566c0f702ef6a8e581bb6790476c71f19bcb",
       [
@@ -112532,6 +112539,19 @@
         {}
        ]
       ],
+      "grid-intrinsic-maximums.html": [
+       "5b244d3c1170595a2cbd9654cfc7772458d2db55",
+       [
+        null,
+        [
+         [
+          "/css/css-grid/grid-items/grid-intrinsic-maximums-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "grid-item-containing-block-001.html": [
        "1dca0dcaa195c802f2c5ce44090b176f47e7d4b8",
        [
@@ -164387,6 +164407,45 @@
        {}
       ]
      ],
+     "text-decoration-line-grammar-error-color-001.optional.html": [
+      "6309d73a0e700a66731ea5270b10eba56e2ab708",
+      [
+       null,
+       [
+        [
+         "/css/css-text-decor/text-decoration-line-grammar-error-color-001-ref.html",
+         "!="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "text-decoration-line-grammar-error-color-002.optional.html": [
+      "1758933a50ca866efa538a0aa15ff367f26667d3",
+      [
+       null,
+       [
+        [
+         "/css/css-text-decor/text-decoration-line-grammar-error-color-002-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "text-decoration-line-grammar-error-color-dynamic-001.optional.html": [
+      "58ff6aeb5cdf06ec1deae1b91c15348778e3a877",
+      [
+       null,
+       [
+        [
+         "/css/css-text-decor/text-decoration-line-grammar-error-color-dynamic-001-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "text-decoration-line-recalc.html": [
       "a3b2f9f9a38d32bd7ee4b1d3a0ea98ebed2a92b1",
       [
@@ -164400,6 +164459,45 @@
        {}
       ]
      ],
+     "text-decoration-line-spelling-error-color-001.optional.html": [
+      "5e5475fe2dd50a76086552b98b2a457013bd6c64",
+      [
+       null,
+       [
+        [
+         "/css/css-text-decor/text-decoration-line-spelling-error-color-001-ref.html",
+         "!="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "text-decoration-line-spelling-error-color-002.optional.html": [
+      "3a87976f2923171fa5e4f2ea7b0945843c13fa7f",
+      [
+       null,
+       [
+        [
+         "/css/css-text-decor/text-decoration-line-spelling-error-color-002-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "text-decoration-line-spelling-error-color-dynamic-001.optional.html": [
+      "d712e354bb94361691be6134cffd5fb7c917891f",
+      [
+       null,
+       [
+        [
+         "/css/css-text-decor/text-decoration-line-spelling-error-color-dynamic-001-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "text-decoration-line-through-wavy-covers-whole-line-length-001.html": [
       "20837062ac1d1053cc585e7bc461b879e382366d",
       [
@@ -164453,7 +164551,7 @@
       ]
      ],
      "text-decoration-propagation-display-contents.html": [
-      "d77dfe55b19be6e9a66b2085d80a45c6e16c55ee",
+      "33d3593b668f0d81aee48441639324a0abe34756",
       [
        null,
        [
@@ -214665,6 +214763,19 @@
         {}
        ]
       ],
+      "gradient-after-reposition.html": [
+       "850b0eb91d3f8c483fb2902cb41d5ed6342006d8",
+       [
+        null,
+        [
+         [
+          "/svg/text/reftests/gradient-after-reposition-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "multiple-textpaths.svg": [
        "6df4ecc27bbddaa76709e041620dacdc5c1303bd",
        [
@@ -246771,6 +246882,10 @@
        "3e08fdfbde27d0aa36dcabd2b7ea240116538b69",
        []
       ],
+      "grid-intrinsic-maximums-ref.html": [
+       "b90f15b597d4e495c0a5dbc4f8dffe8511f10111",
+       []
+      ],
       "grid-item-margins-and-writing-modes-001-ref.html": [
        "86553ef6f4077f3c6bc348496e513d7960d7b79f",
        []
@@ -247135,10 +247250,6 @@
        "512bd0d2222370b0c0e1e9fc675213bc03179962",
        []
       ],
-      "grid-shorthand-expected.txt": [
-       "d2c4b0fd368779929161d94812987f4e675f2ea7",
-       []
-      ],
       "grid-shorthand-valid-expected.txt": [
        "f6180f77830e1581abd0fe2c2181c6dac35639b9",
        []
@@ -258058,7 +258169,7 @@
        []
       ],
       "text-decoration-propagation-display-contents-ref.html": [
-       "5eecc8c8b4e39c4b940e472e5e0f39e9262e10d9",
+       "c8381c64fdaa22cfc4c52fd63d3da6b7cc6dd4bd",
        []
       ],
       "text-decoration-shorthands-001-ref.html": [
@@ -258364,6 +258475,30 @@
        []
       ]
      },
+     "text-decoration-line-grammar-error-color-001-ref.html": [
+      "2592110a1199515b6376d21a963132bfe90400bc",
+      []
+     ],
+     "text-decoration-line-grammar-error-color-002-ref.html": [
+      "2416ba8dd6b759338df37bbd63fa4dcc0f1e1336",
+      []
+     ],
+     "text-decoration-line-grammar-error-color-dynamic-001-ref.html": [
+      "e54b6814ec15857c98086e681cdbbdcd01b6095c",
+      []
+     ],
+     "text-decoration-line-spelling-error-color-001-ref.html": [
+      "9cd5199eb85d40e1ebe9d1ca6fd1778deea2d5da",
+      []
+     ],
+     "text-decoration-line-spelling-error-color-002-ref.html": [
+      "b8bd681184366917e66ea8f43f37399a09718a4d",
+      []
+     ],
+     "text-decoration-line-spelling-error-color-dynamic-001-ref.html": [
+      "e96898a81ef34410b775d73819deb78eb1665c4f",
+      []
+     ],
      "text-decoration-serialization.tentative-expected.txt": [
       "0d83f58028ff740b492af6663ff5b135a740b9a1",
       []
@@ -272649,27 +272784,35 @@
       []
      ],
      "non-secure-context.window-expected.txt": [
-      "101160983b38cf7dac36d92ae865da8c2e1b9a0c",
+      "b973089394588a1e183dc4b8dacbdb763ddd465d",
       []
      ],
      "resources": {
       "fetcher.html": [
-       "6fc321f345142c2379cee6e5845bc73b90cad509",
+       "000a5cc25bb72b334d41ff05e7b8f22691f48f30",
        []
       ],
       "ports.sub.js": [
        "fb3f0ad5c402eefea666251fe177e74e94d36450",
        []
       ],
+      "preflight.py": [
+       "4181210b263b9e3ce377464bab63278330d97be4",
+       []
+      ],
       "socket-opener.html": [
        "48d27216bedf9aa1daf4d2a4e96f860e9315a0c3",
        []
       ],
       "support.js": [
-       "16494bf197a1101a9b9445eae9b14ddd5c2bfb83",
+       "e9e70fca517855a2ddebc91e0516f3f063627709",
        []
       ]
-     }
+     },
+     "secure-context.https.window-expected.txt": [
+      "b508d892bb2b40acdc4cd3505df53c04eab5f412",
+      []
+     ]
     },
     "range": {
      "general.window-expected.txt": [
@@ -272689,8 +272832,12 @@
        "a9570ec355c63d60fb0731bddeb79ba87b491492",
        []
       ],
+      "partial-text.py": [
+       "a0058551d52d45b3c16882014be740d75e51ddd1",
+       []
+      ],
       "range-sw.js": [
-       "3680c0c471d3d5f36c4aba4cc58dcd52c38a08df",
+       "b47823f03b4ef3749e622fbf7dd3b515a216b5be",
        []
       ],
       "stash-take.py": [
@@ -272698,12 +272845,12 @@
        []
       ],
       "utils.js": [
-       "16ed737f63e8eee26a306c70acb0589e424db35d",
+       "ad2853b33dc7474293df1423dd8af459571736b9",
        []
       ]
      },
      "sw.https.window-expected.txt": [
-      "134b0a7abd817599921d4fb430e8247a2cb40f82",
+      "a9577f01727678cd7a76bcc65e132fd6fcb230ac",
       []
      ]
     },
@@ -304329,6 +304476,10 @@
       ]
      },
      "reftests": {
+      "gradient-after-reposition-ref.html": [
+       "3fe1224b9a0120e9691688fe36048ad0e6323a84",
+       []
+      ],
       "multiple-textpaths-ref.svg": [
        "a6dcd3c5d5e5fe1a9aa74d2539c14e66c95cbece",
        []
@@ -317057,80 +317208,338 @@
       {}
      ]
     ],
-    "idbobjectstore_get.htm": [
-     "99aff78d5643874834706d9922c3a2631e3db8e7",
+    "idbobjectstore_get.any.js": [
+     "d8f3422a646b5d8f1a673e2592b9adf86fe8fecf",
      [
-      null,
-      {}
-     ]
-    ],
-    "idbobjectstore_get2.htm": [
-     "dfbfea17c22df5c796366d8f46e9b6f8b09d52d3",
-     [
-      null,
-      {}
-     ]
-    ],
-    "idbobjectstore_get3.htm": [
-     "b093e535796986159e205a10dc3ac07ebf573529",
-     [
-      null,
-      {}
-     ]
-    ],
-    "idbobjectstore_get4.htm": [
-     "4a8de9f77a8007bb227aefe22a8f1079f2cceb1a",
-     [
-      null,
-      {}
-     ]
-    ],
-    "idbobjectstore_get5.htm": [
-     "59b0ede641f69b58fe4077e2265ce35f4c968da4",
-     [
-      null,
-      {}
-     ]
-    ],
-    "idbobjectstore_get6.htm": [
-     "c996ec4946c69c603fc0cd7df509a2005e70aa8c",
-     [
-      null,
-      {}
-     ]
-    ],
-    "idbobjectstore_get7.htm": [
-     "dbbfa0d46f567bf972af1b0fdf737f6b79ac25a7",
-     [
-      null,
-      {}
-     ]
-    ],
-    "idbobjectstore_getAll.html": [
-     "c9d29d3c3a42fec6c1e01bbbdcaf186a0a4ef42d",
-     [
-      null,
-      {}
-     ]
-    ],
-    "idbobjectstore_getAllKeys.html": [
-     "896d4df32e6a5ea0803975a5342250b1d5ced8ce",
-     [
-      null,
-      {}
-     ]
-    ],
-    "idbobjectstore_getKey.html": [
-     "9e3662502de0a2ef86d3a0d61960d168f1c8ab06",
-     [
-      null,
+      "IndexedDB/idbobjectstore_get.any.html",
       {
-       "timeout": "long"
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - key is a number"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/idbobjectstore_get.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - key is a number"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "idbobjectstore_get2.any.js": [
+     "891d4f5497da59454ed16b809a318ae9ea67f7b3",
+     [
+      "IndexedDB/idbobjectstore_get2.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - key is a string"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/idbobjectstore_get2.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - key is a string"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "idbobjectstore_get3.any.js": [
+     "f70054519c72b91a7fe59031660c2a38d711ab06",
+     [
+      "IndexedDB/idbobjectstore_get3.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - key is a Date"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/idbobjectstore_get3.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - key is a Date"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "idbobjectstore_get4.any.js": [
+     "3c3cb784281efeeb4b4e89350577f843787aa048",
+     [
+      "IndexedDB/idbobjectstore_get4.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - attempt to retrieve a record that doesn't exist"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/idbobjectstore_get4.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - attempt to retrieve a record that doesn't exist"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "idbobjectstore_get5.any.js": [
+     "2cea83b7647e725cbbfe9de69c4a8bdd2ef69dfc",
+     [
+      "IndexedDB/idbobjectstore_get5.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - returns the record with the first key in the range"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/idbobjectstore_get5.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - returns the record with the first key in the range"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "idbobjectstore_get6.any.js": [
+     "9939eb6846c127f4bb4deef5bb2f964335acac79",
+     [
+      "IndexedDB/idbobjectstore_get6.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - throw TransactionInactiveError on aborted transaction"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/idbobjectstore_get6.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - throw TransactionInactiveError on aborted transaction"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "idbobjectstore_get7.any.js": [
+     "e66c1d95761e4425209e0c7275dad6aceedcf452",
+     [
+      "IndexedDB/idbobjectstore_get7.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - throw DataError when using invalid key"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/idbobjectstore_get7.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IDBObjectStore.get() - throw DataError when using invalid key"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "idbobjectstore_getAll.any.js": [
+     "f34dbcfb380f22ef7ee303fa591dfd3ec88ee67e",
+     [
+      "IndexedDB/idbobjectstore_getAll.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: Test IDBObjectStore.getAll"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/idbobjectstore_getAll.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: Test IDBObjectStore.getAll"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "idbobjectstore_getAllKeys.any.js": [
+     "80f64ca222cf77daf5a15856b56ec34d58cddae7",
+     [
+      "IndexedDB/idbobjectstore_getAllKeys.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: Test IDBObjectStore.getAllKeys"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/idbobjectstore_getAllKeys.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: Test IDBObjectStore.getAllKeys"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "idbobjectstore_getKey.any.js": [
+     "7397747f3ff816660c80028ae45a854b310e58da",
+     [
+      "IndexedDB/idbobjectstore_getKey.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: Test IDBObjectStore.getKey()"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/idbobjectstore_getKey.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: Test IDBObjectStore.getKey()"
+        ],
+        [
+         "script",
+         "support.js"
+        ]
+       ]
       }
      ]
     ],
     "idbobjectstore_index.htm": [
-     "5da58ecc3116fd66f15ce2ee4f6d5184d2285ec7",
+     "f01474af5bbfaefa61010c845dc3c2b3402370da",
      [
       null,
       {}
@@ -402553,13 +402962,17 @@
     },
     "private-network-access": {
      "non-secure-context.window.js": [
-      "6b2b6be7e09708b3d3b6d30d08f476d7bf548dbd",
+      "e81dfb616bb2a05ab66352d4e08987c6f1f275c1",
       [
        "fetch/private-network-access/non-secure-context.window.html",
        {
         "script_metadata": [
          [
           "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
           "resources/support.js"
          ],
          [
@@ -402571,13 +402984,17 @@
       ]
      ],
      "secure-context.https.window.js": [
-      "1218700786f7bf61e47389cdb22365d2cb2f642a",
+      "f5714bef8bd086c5abfda0e6d6f6cba2cdc0bbf6",
       [
        "fetch/private-network-access/secure-context.https.window.html",
        {
         "script_metadata": [
          [
           "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
           "resources/support.js"
          ],
          [
@@ -402672,7 +403089,7 @@
       ]
      ],
      "sw.https.window.js": [
-      "76f80e9416c615417ad2a9fbaa565641ff5b8a12",
+      "42e4ac6d75afdcbb2ad1e9d3e4069d9cbfd10dbd",
       [
        "fetch/range/sw.https.window.html",
        {
@@ -509096,6 +509513,16 @@
       }
      ]
     ],
+    "createcredential-minpinlength.https.html": [
+     "09b045d448f41fe824c9fc4574c9830e95279c58",
+     [
+      null,
+      {
+       "testdriver": true,
+       "timeout": "long"
+      }
+     ]
+    ],
     "createcredential-passing.https.html": [
      "30fef13bbdc9efb5659460652054d119399ce819",
      [
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get.any.js
new file mode 100644
index 0000000..d8f3422
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get.any.js
@@ -0,0 +1,28 @@
+// META: title=IDBObjectStore.get() - key is a number
+// META: script=support.js
+// @author Microsoft <https://www.microsoft.com>
+
+"use strict";
+
+let db;
+const t = async_test();
+const record = { key: 3.14159265, property: "data" };
+
+const open_rq = createdb(t);
+open_rq.onupgradeneeded = event => {
+  db = event.target.result;
+  db.createObjectStore("store", { keyPath: "key" })
+    .add(record);
+}
+
+open_rq.onsuccess = event => {
+  const rq = db.transaction("store")
+    .objectStore("store")
+    .get(record.key);
+
+  rq.onsuccess = t.step_func(event => {
+    assert_equals(event.target.result.key, record.key);
+    assert_equals(event.target.result.property, record.property);
+    t.done();
+  });
+}
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get.htm b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get.htm
deleted file mode 100644
index 99aff78d..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get.htm
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>IDBObjectStore.get() - key is a number </title>
-<link rel="author" title="Microsoft" href="http://www.microsoft.com">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support.js"></script>
-
-<script>
-    var db,
-      t = async_test(),
-      record = { key: 3.14159265, property: "data" };
-
-    var open_rq = createdb(t);
-    open_rq.onupgradeneeded = function(e) {
-        db = e.target.result;
-        db.createObjectStore("store", { keyPath: "key" })
-          .add(record);
-    }
-
-    open_rq.onsuccess = function(e) {
-        var rq = db.transaction("store")
-                   .objectStore("store")
-                   .get(record.key);
-
-        rq.onsuccess = t.step_func(function(e) {
-            assert_equals(e.target.result.key, record.key);
-            assert_equals(e.target.result.property, record.property);
-            t.done();
-        });
-    }
-
-</script>
-
-<div id="log"></div>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get2.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get2.any.js
new file mode 100644
index 0000000..891d4f54
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get2.any.js
@@ -0,0 +1,28 @@
+// META: title=IDBObjectStore.get() - key is a string
+// META: script=support.js
+// @author Microsoft <https://www.microsoft.com>
+
+"use strict";
+
+let db;
+const t = async_test();
+const record = { key: "this is a key that's a string", property: "data" };
+
+const open_rq = createdb(t);
+open_rq.onupgradeneeded = event => {
+  db = event.target.result;
+  db.createObjectStore("store", { keyPath: "key" })
+    .add(record);
+};
+
+open_rq.onsuccess = event => {
+  const rq = db.transaction("store")
+    .objectStore("store")
+    .get(record.key);
+
+  rq.onsuccess = t.step_func(event => {
+    assert_equals(event.target.result.key, record.key);
+    assert_equals(event.target.result.property, record.property);
+    t.done();
+  });
+};
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get2.htm b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get2.htm
deleted file mode 100644
index dfbfea1..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get2.htm
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>IDBObjectStore.get() - key is a string </title>
-<link rel="author" title="Microsoft" href="http://www.microsoft.com">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support.js"></script>
-
-<script>
-    var db,
-      t = async_test(),
-      record = { key: "this is a key that's a string", property: "data" };
-
-    var open_rq = createdb(t);
-    open_rq.onupgradeneeded = function(e) {
-        db = e.target.result;
-        db.createObjectStore("store", { keyPath: "key" })
-          .add(record);
-    };
-
-    open_rq.onsuccess = function(e) {
-        var rq = db.transaction("store")
-                   .objectStore("store")
-                   .get(record.key);
-
-        rq.onsuccess = t.step_func(function(e) {
-            assert_equals(e.target.result.key, record.key);
-            assert_equals(e.target.result.property, record.property);
-            t.done();
-        });
-    };
-
-</script>
-
-<div id="log"></div>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get3.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get3.any.js
new file mode 100644
index 0000000..f700545
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get3.any.js
@@ -0,0 +1,28 @@
+// META: title=IDBObjectStore.get() - key is a Date
+// META: script=support.js
+// @author Microsoft <https://www.microsoft.com>
+
+"use strict";
+
+let db;
+const t = async_test();
+const record = { key: new Date(), property: "data" };
+
+const open_rq = createdb(t);
+open_rq.onupgradeneeded = event => {
+  db = event.target.result;
+  db.createObjectStore("store", { keyPath: "key" })
+    .add(record);
+};
+
+open_rq.onsuccess = event => {
+  const rq = db.transaction("store")
+    .objectStore("store")
+    .get(record.key);
+
+  rq.onsuccess = t.step_func(event => {
+    assert_equals(event.target.result.key.valueOf(), record.key.valueOf());
+    assert_equals(event.target.result.property, record.property);
+    t.done();
+  });
+};
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get3.htm b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get3.htm
deleted file mode 100644
index b093e53..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get3.htm
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>IDBObjectStore.get() - key is a Date </title>
-<link rel="author" title="Microsoft" href="http://www.microsoft.com">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support.js"></script>
-
-<script>
-    var db,
-      t = async_test(),
-      record = { key: new Date(), property: "data" };
-
-    var open_rq = createdb(t);
-    open_rq.onupgradeneeded = function(e) {
-        db = e.target.result;
-        db.createObjectStore("store", { keyPath: "key" })
-          .add(record);
-    }
-
-    open_rq.onsuccess = function(e) {
-        var rq = db.transaction("store")
-                   .objectStore("store")
-                   .get(record.key);
-
-        rq.onsuccess = t.step_func(function(e) {
-            assert_equals(e.target.result.key.valueOf(), record.key.valueOf());
-            assert_equals(e.target.result.property, record.property);
-            t.done();
-        });
-    }
-</script>
-
-<div id="log"></div>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get4.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get4.any.js
new file mode 100644
index 0000000..3c3cb78
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get4.any.js
@@ -0,0 +1,19 @@
+// META: title=IDBObjectStore.get() - attempt to retrieve a record that doesn't exist
+// META: script=support.js
+// @author Microsoft <https://www.microsoft.com>
+
+"use strict";
+
+let db;
+const t = async_test();
+
+const open_rq = createdb(t);
+open_rq.onupgradeneeded = event => {
+  db = event.target.result;
+  const rq = db.createObjectStore("store", { keyPath: "key" })
+    .get(1);
+  rq.onsuccess = t.step_func(event => {
+    assert_equals(event.target.results, undefined);
+    t.done();
+  });
+};
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get4.htm b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get4.htm
deleted file mode 100644
index 4a8de9f..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get4.htm
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>IDBObjectStore.get() - attempt to retrieve a record that doesn't exist </title>
-<link rel="author" title="Microsoft" href="http://www.microsoft.com">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support.js"></script>
-
-<script>
-    var db,
-      t = async_test();
-
-    var open_rq = createdb(t);
-    open_rq.onupgradeneeded = function(e) {
-        db = e.target.result;
-        var rq = db.createObjectStore("store", { keyPath: "key" })
-                   .get(1);
-        rq.onsuccess = t.step_func(function(e) {
-            assert_equals(e.target.results, undefined);
-            step_timeout(function() { t.done(); }, 10);
-        });
-    };
-
-    open_rq.onsuccess = function() {};
-</script>
-
-<div id="log"></div>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get5.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get5.any.js
new file mode 100644
index 0000000..2cea83b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get5.any.js
@@ -0,0 +1,29 @@
+// META: title=IDBObjectStore.get() - returns the record with the first key in the range
+// META: script=support.js
+// @author Microsoft <https://www.microsoft.com>
+
+"use strict";
+
+let db;
+const t = async_test();
+const open_rq = createdb(t);
+
+open_rq.onupgradeneeded = event => {
+  db = event.target.result;
+  const os = db.createObjectStore("store");
+
+  for (let i = 0; i < 10; i++) {
+    os.add(`data${i}`, i);
+  }
+};
+
+open_rq.onsuccess = event => {
+  const rq = db.transaction("store")
+    .objectStore("store")
+    .get(IDBKeyRange.bound(3, 6));
+
+  rq.onsuccess = t.step_func(event => {
+    assert_equals(event.target.result, "data3", "get(3-6)");
+    t.done();
+  });
+};
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get5.htm b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get5.htm
deleted file mode 100644
index 59b0ede..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get5.htm
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<title>IDBObjectStore.get() - returns the record with the first key in the range </title>
-<link rel="author" title="Microsoft" href="http://www.microsoft.com">
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=support.js></script>
-<script>
-    var db
-    var open_rq = createdb(async_test())
-
-    open_rq.onupgradeneeded = function(e) {
-        db = e.target.result
-        var os = db.createObjectStore("store")
-
-        for(var i = 0; i < 10; i++)
-            os.add("data" + i, i)
-    }
-
-    open_rq.onsuccess = function (e) {
-        db.transaction("store")
-          .objectStore("store")
-          .get( IDBKeyRange.bound(3, 6) )
-          .onsuccess = this.step_func(function(e)
-        {
-            assert_equals(e.target.result, "data3", "get(3-6)");
-            this.done();
-        })
-    }
-</script>
-
-<div id=log></div>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get6.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get6.any.js
new file mode 100644
index 0000000..9939eb68
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get6.any.js
@@ -0,0 +1,24 @@
+// META: title=IDBObjectStore.get() - throw TransactionInactiveError on aborted transaction
+// META: script=support.js
+// @author YuichiNukiyama <https://github.com/YuichiNukiyama>
+
+"use strict";
+
+let db;
+const t = async_test();
+
+const open_rq = createdb(t);
+open_rq.onupgradeneeded = event => {
+  db = event.target.result;
+  db.createObjectStore("store", { keyPath: "key" });
+};
+
+open_rq.onsuccess = event => {
+  const store = db.transaction("store")
+    .objectStore("store");
+  store.transaction.abort();
+  assert_throws_dom("TransactionInactiveError", function () {
+    store.get(1);
+  }, "throw TransactionInactiveError on aborted transaction.");
+  t.done();
+};
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get6.htm b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get6.htm
deleted file mode 100644
index c996ec4..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get6.htm
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>IDBObjectStore.get() - throw TransactionInactiveError on aborted transaction </title>
-<link rel="author" title="YuichiNukiyama" href="https://github.com/YuichiNukiyama">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support.js"></script>
-
-<script>
-    var db,
-      t = async_test();
-
-    var open_rq = createdb(t);
-    open_rq.onupgradeneeded = function(e) {
-        db = e.target.result;
-        db.createObjectStore("store", { keyPath: "key" })
-    }
-
-    open_rq.onsuccess = function (e) {
-        var store = db.transaction("store")
-                      .objectStore("store");
-        store.transaction.abort();
-        assert_throws_dom("TransactionInactiveError", function () {
-            store.get(1);
-        }, "throw TransactionInactiveError on aborted transaction.");
-        t.done();
-    }
-</script>
-
-<div id="log"></div>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get7.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get7.any.js
new file mode 100644
index 0000000..e66c1d95
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get7.any.js
@@ -0,0 +1,23 @@
+// META: title=IDBObjectStore.get() - throw DataError when using invalid key
+// META: script=support.js
+// @author YuichiNukiyama <https://github.com/YuichiNukiyama>
+
+"use strict";
+
+let db;
+const t = async_test();
+
+const open_rq = createdb(t);
+open_rq.onupgradeneeded = event => {
+  db = event.target.result;
+  db.createObjectStore("store", { keyPath: "key" });
+}
+
+open_rq.onsuccess = () => {
+  const store = db.transaction("store")
+    .objectStore("store");
+  assert_throws_dom("DataError", () => {
+    store.get(null)
+  }, "throw DataError when using invalid key.");
+  t.done();
+}
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get7.htm b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get7.htm
deleted file mode 100644
index dbbfa0d..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_get7.htm
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>IDBObjectStore.get() - throw DataError when using invalid key </title>
-<link rel="author" title="YuichiNukiyama" href="https://github.com/YuichiNukiyama">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support.js"></script>
-
-<script>
-    var db,
-      t = async_test();
-
-    var open_rq = createdb(t);
-    open_rq.onupgradeneeded = function(e) {
-        db = e.target.result;
-        db.createObjectStore("store", { keyPath: "key" })
-    }
-
-    open_rq.onsuccess = function(e) {
-        var store = db.transaction("store")
-                      .objectStore("store")
-        assert_throws_dom("DataError", function () {
-            store.get(null)
-        }, "throw DataError when using invalid key.");
-        t.done();
-    }
-</script>
-
-<div id="log"></div>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getAll.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getAll.any.js
new file mode 100644
index 0000000..f34dbcf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getAll.any.js
@@ -0,0 +1,148 @@
+// META: title=IndexedDB: Test IDBObjectStore.getAll
+// META: script=support.js
+
+'use strict';
+
+const alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
+
+function getall_test(func, name) {
+  indexeddb_test(
+    (t, connection, tx) => {
+      let store = connection.createObjectStore('generated',
+        { autoIncrement: true, keyPath: 'id' });
+      alphabet.forEach(letter => {
+        store.put({ ch: letter });
+      });
+
+      store = connection.createObjectStore('out-of-line', null);
+      alphabet.forEach(letter => {
+        store.put(`value-${letter}`, letter);
+      });
+
+      store = connection.createObjectStore('empty', null);
+    },
+    func,
+    name
+  );
+}
+
+function createGetAllRequest(t, storeName, connection, keyRange, maxCount) {
+  const transaction = connection.transaction(storeName, 'readonly');
+  const store = transaction.objectStore(storeName);
+  const req = store.getAll(keyRange, maxCount);
+  req.onerror = t.unreached_func('getAll request should succeed');
+  return req;
+}
+
+getall_test((t, connection) => {
+  const req = createGetAllRequest(t, 'out-of-line', connection, 'c');
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, ['value-c']);
+    t.done();
+  });
+}, 'Single item get');
+
+getall_test((t, connection) => {
+  const req = createGetAllRequest(t, 'generated', connection, 3);
+  req.onsuccess = t.step_func(evt => {
+    const data = evt.target.result;
+    assert_true(Array.isArray(data));
+    assert_equals(data.length, 1);
+    assert_equals(data[0].id, 3);
+    assert_equals(data[0].ch, 'c');
+    t.done();
+  });
+}, 'Single item get (generated key)');
+
+getall_test((t, connection) => {
+  const req = createGetAllRequest(t, 'empty', connection);
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, [],
+      'getAll() on empty object store should return an empty array');
+    t.done();
+  });
+}, 'getAll on empty object store');
+
+getall_test((t, connection) => {
+  const req = createGetAllRequest(t, 'out-of-line', connection);
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, alphabet.map(c => `value-${c}`));
+    t.done();
+  });
+}, 'Get all values');
+
+getall_test((t, connection) => {
+  const req = createGetAllRequest(t, 'out-of-line', connection, undefined,
+    10);
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, 'abcdefghij'.split('').map(c => `value-${c}`));
+    t.done();
+  });
+}, 'Test maxCount');
+
+getall_test((t, connection) => {
+  const req = createGetAllRequest(t, 'out-of-line', connection,
+    IDBKeyRange.bound('g', 'm'));
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, 'ghijklm'.split('').map(c => `value-${c}`));
+    t.done();
+  });
+}, 'Get bound range');
+
+getall_test((t, connection) => {
+  const req = createGetAllRequest(t, 'out-of-line', connection,
+    IDBKeyRange.bound('g', 'm'), 3);
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, ['g', 'h', 'i'].map(c => `value-${c}`));
+    t.done();
+  });
+}, 'Get bound range with maxCount');
+
+getall_test((t, connection) => {
+  const req = createGetAllRequest(t, 'out-of-line', connection,
+    IDBKeyRange.bound('g', 'k', false, true));
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, ['g', 'h', 'i', 'j'].map(c => `value-${c}`));
+    t.done();
+  });
+}, 'Get upper excluded');
+
+getall_test((t, connection) => {
+  const req = createGetAllRequest(t, 'out-of-line', connection,
+    IDBKeyRange.bound('g', 'k', true, false));
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, ['h', 'i', 'j', 'k'].map(c => `value-${c}`));
+    t.done();
+  });
+}, 'Get lower excluded');
+
+getall_test((t, connection) => {
+  const req = createGetAllRequest(t, 'generated', connection,
+    IDBKeyRange.bound(4, 15), 3);
+  req.onsuccess = t.step_func(evt => {
+    const data = evt.target.result;
+    assert_true(Array.isArray(data));
+    assert_array_equals(data.map(e => e.ch), ['d', 'e', 'f']);
+    assert_array_equals(data.map(e => e.id), [4, 5, 6]);
+    t.done();
+  });
+}, 'Get bound range (generated) with maxCount');
+
+getall_test((t, connection) => {
+  const req = createGetAllRequest(t, 'out-of-line', connection,
+    "Doesn't exist");
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, [],
+      'getAll() using a nonexistent key should return an empty array');
+    t.done();
+  });
+  req.onerror = t.unreached_func('getAll request should succeed');
+}, 'Non existent key');
+
+getall_test((t, connection) => {
+  const req = createGetAllRequest(t, 'out-of-line', connection, undefined, 0);
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, alphabet.map(c => `value-${c}`));
+    t.done();
+  });
+}, 'zero maxCount');
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getAll.html b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getAll.html
deleted file mode 100644
index c9d29d3..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getAll.html
+++ /dev/null
@@ -1,159 +0,0 @@
-<!DOCTYPE html>
-<title>IndexedDB: Test IDBObjectStore.getAll.</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support.js"></script>
-<script>
-
-var alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
-
-function getall_test(func, name) {
-  indexeddb_test(
-    function(t, connection, tx) {
-      var store = connection.createObjectStore('generated',
-            {autoIncrement: true, keyPath: 'id'});
-      alphabet.forEach(function(letter) {
-        store.put({ch: letter});
-      });
-
-      store = connection.createObjectStore('out-of-line', null);
-      alphabet.forEach(function(letter) {
-        store.put('value-' + letter, letter);
-      });
-
-      store = connection.createObjectStore('empty', null);
-    },
-    func,
-    name
-  );
-}
-
-function createGetAllRequest(t, storeName, connection, range, maxCount) {
-    var transaction = connection.transaction(storeName, 'readonly');
-    var store = transaction.objectStore(storeName);
-    var req = store.getAll(range, maxCount);
-    req.onerror = t.unreached_func('getAll request should succeed');
-    return req;
-}
-
-getall_test(function(t, connection) {
-      var req = createGetAllRequest(t, 'out-of-line', connection, 'c');
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, ['value-c']);
-          t.done();
-      });
-    }, 'Single item get');
-
-getall_test(function(t, connection) {
-      var req = createGetAllRequest(t, 'generated', connection, 3);
-      req.onsuccess = t.step_func(function(evt) {
-          var data = evt.target.result;
-          assert_true(Array.isArray(data));
-          assert_equals(data.length, 1);
-          assert_equals(data[0].id, 3);
-          assert_equals(data[0].ch, 'c');
-          t.done();
-      });
-    }, 'Single item get (generated key)');
-
-getall_test(function(t, connection) {
-      var req = createGetAllRequest(t, 'empty', connection);
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, [],
-              'getAll() on empty object store should return an empty array');
-          t.done();
-      });
-    }, 'getAll on empty object store');
-
-getall_test(function(t, connection) {
-      var req = createGetAllRequest(t, 'out-of-line', connection);
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result,
-              alphabet.map(function(c) { return 'value-' + c; }));
-          t.done();
-      });
-    }, 'Get all values');
-
-getall_test(function(t, connection) {
-      var req = createGetAllRequest(t, 'out-of-line', connection, undefined,
-                                    10);
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result,
-              'abcdefghij'.split('').map(function(c) { return 'value-' + c; }));
-          t.done();
-      });
-    }, 'Test maxCount');
-
-getall_test(function(t, connection) {
-      var req = createGetAllRequest(t, 'out-of-line', connection,
-                                    IDBKeyRange.bound('g', 'm'));
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result,
-              'ghijklm'.split('').map(function(c) { return 'value-' + c; }));
-          t.done();
-      });
-    }, 'Get bound range');
-
-getall_test(function(t, connection) {
-      var req = createGetAllRequest(t, 'out-of-line', connection,
-                                    IDBKeyRange.bound('g', 'm'), 3);
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, ['g', 'h', 'i']
-              .map(function(c) { return 'value-' + c; }));
-          t.done();
-      });
-    }, 'Get bound range with maxCount');
-
-getall_test(function(t, connection) {
-      var req = createGetAllRequest(t, 'out-of-line', connection,
-                                    IDBKeyRange.bound('g', 'k', false, true));
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, ['g', 'h', 'i', 'j']
-              .map(function(c) { return 'value-' + c; }));
-          t.done();
-      });
-    }, 'Get upper excluded');
-
-getall_test(function(t, connection) {
-      var req = createGetAllRequest(t, 'out-of-line', connection,
-                                    IDBKeyRange.bound('g', 'k', true, false));
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, ['h', 'i', 'j', 'k']
-              .map(function(c) { return 'value-' + c; }));
-          t.done();
-      });
-    }, 'Get lower excluded');
-
-getall_test(function(t, connection) {
-      var req = createGetAllRequest(t, 'generated', connection,
-                                    IDBKeyRange.bound(4, 15), 3);
-      req.onsuccess = t.step_func(function(evt) {
-          var data = evt.target.result;
-          assert_true(Array.isArray(data));
-          assert_array_equals(data.map(function(e) { return e.ch; }), ['d', 'e', 'f']);
-          assert_array_equals(data.map(function(e) { return e.id; }), [4, 5, 6]);
-          t.done();
-      });
-    }, 'Get bound range (generated) with maxCount');
-
-getall_test(function(t, connection) {
-      var req = createGetAllRequest(t, 'out-of-line', connection,
-                                    "Doesn't exist");
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, [],
-              'getAll() using a nonexistent key should return an empty array');
-          t.done();
-      });
-      req.onerror = t.unreached_func('getAll request should succeed');
-    }, 'Non existent key');
-
-getall_test(function(t, connection) {
-      var req = createGetAllRequest(t, 'out-of-line', connection, undefined, 0);
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result,
-              alphabet.map(function(c) { return 'value-' + c; }));
-          t.done();
-      });
-    }, 'zero maxCount');
-
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getAllKeys.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getAllKeys.any.js
new file mode 100644
index 0000000..80f64ca
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getAllKeys.any.js
@@ -0,0 +1,148 @@
+// META: title=IndexedDB: Test IDBObjectStore.getAllKeys
+// META: script=support.js
+
+'use strict';
+
+const alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
+
+function getall_test(func, name) {
+  indexeddb_test(
+    (t, connection, tx) => {
+      let store = connection.createObjectStore('generated',
+        { autoIncrement: true, keyPath: 'id' });
+      alphabet.forEach(letter => {
+        store.put({ ch: letter });
+      });
+
+      store = connection.createObjectStore('out-of-line', null);
+      alphabet.forEach(letter => {
+        store.put(`value-${letter}`, letter);
+      });
+
+      store = connection.createObjectStore('empty', null);
+    },
+    func,
+    name
+  );
+}
+
+function createGetAllKeysRequest(t, storeName, connection, keyRange, maxCount) {
+  const transaction = connection.transaction(storeName, 'readonly');
+  const store = transaction.objectStore(storeName);
+  const req = store.getAllKeys(keyRange, maxCount);
+  req.onerror = t.unreached_func('getAllKeys request should succeed');
+  return req;
+}
+
+getall_test((t, connection) => {
+  const req = createGetAllKeysRequest(t, 'out-of-line', connection, 'c');
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, ['c']);
+    t.done();
+  });
+}, 'Single item get');
+
+getall_test((t, connection) => {
+  const req = createGetAllKeysRequest(t, 'generated', connection, 3);
+  req.onsuccess = t.step_func(evt => {
+    const data = evt.target.result;
+    assert_true(Array.isArray(data));
+    assert_array_equals(data, [3]);
+    t.done();
+  });
+}, 'Single item get (generated key)');
+
+getall_test((t, connection) => {
+  const req = createGetAllKeysRequest(t, 'empty', connection);
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, [],
+      'getAllKeys() on empty object store should return an empty ' +
+      'array');
+    t.done();
+  });
+}, 'getAllKeys on empty object store');
+
+getall_test((t, connection) => {
+  const req = createGetAllKeysRequest(t, 'out-of-line', connection);
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, alphabet);
+    t.done();
+  });
+}, 'Get all values');
+
+getall_test((t, connection) => {
+  const req = createGetAllKeysRequest(t, 'out-of-line', connection, undefined,
+    10);
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, 'abcdefghij'.split(''));
+    t.done();
+  });
+}, 'Test maxCount');
+
+getall_test((t, connection) => {
+  const req = createGetAllKeysRequest(t, 'out-of-line', connection,
+    IDBKeyRange.bound('g', 'm'));
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, 'ghijklm'.split(''));
+    t.done();
+  });
+}, 'Get bound range');
+
+getall_test((t, connection) => {
+  const req = createGetAllKeysRequest(t, 'out-of-line', connection,
+    IDBKeyRange.bound('g', 'm'), 3);
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, ['g', 'h', 'i']);
+    t.done();
+  });
+}, 'Get bound range with maxCount');
+
+getall_test((t, connection) => {
+  const req = createGetAllKeysRequest(t, 'out-of-line', connection,
+    IDBKeyRange.bound('g', 'k', false, true));
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, ['g', 'h', 'i', 'j']);
+    t.done();
+  });
+}, 'Get upper excluded');
+
+getall_test((t, connection) => {
+  const req = createGetAllKeysRequest(t, 'out-of-line', connection,
+    IDBKeyRange.bound('g', 'k', true, false));
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, ['h', 'i', 'j', 'k']);
+    t.done();
+  });
+}, 'Get lower excluded');
+
+getall_test((t, connection) => {
+  const req = createGetAllKeysRequest(t, 'generated', connection,
+    IDBKeyRange.bound(4, 15), 3);
+  req.onsuccess = t.step_func(evt => {
+    const data = evt.target.result;
+    assert_true(Array.isArray(data));
+    assert_array_equals(data, [4, 5, 6]);
+    t.done();
+  });
+}, 'Get bound range (generated) with maxCount');
+
+getall_test((t, connection) => {
+  const req = createGetAllKeysRequest(t, 'out-of-line', connection,
+    "Doesn't exist");
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, [],
+      'getAllKeys() using a nonexistent key should return an ' +
+      'empty array');
+    t.done();
+  });
+  req.onerror = t.unreached_func('getAllKeys request should succeed');
+}, 'Non existent key');
+
+getall_test((t, connection) => {
+  const req = createGetAllKeysRequest(t, 'out-of-line', connection, undefined,
+    0);
+  req.onsuccess = t.step_func(evt => {
+    assert_array_equals(evt.target.result, alphabet);
+    t.done();
+  });
+}, 'zero maxCount');
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getAllKeys.html b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getAllKeys.html
deleted file mode 100644
index 896d4df..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getAllKeys.html
+++ /dev/null
@@ -1,152 +0,0 @@
-<!DOCTYPE html>
-<title>IndexedDB: Test IDBObjectStore.getAllKeys.</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support.js"></script>
-<script>
-
-var alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
-
-function getall_test(func, name) {
-  indexeddb_test(
-    function(t, connection, tx) {
-      var store = connection.createObjectStore('generated',
-            {autoIncrement: true, keyPath: 'id'});
-      alphabet.forEach(function(letter) {
-        store.put({ch: letter});
-      });
-
-      store = connection.createObjectStore('out-of-line', null);
-      alphabet.forEach(function(letter) {
-        store.put('value-' + letter, letter);
-      });
-
-      store = connection.createObjectStore('empty', null);
-    },
-    func,
-    name
-  );
-}
-
-function createGetAllKeysRequest(t, storeName, connection, range, maxCount) {
-    var transaction = connection.transaction(storeName, 'readonly');
-    var store = transaction.objectStore(storeName);
-    var req = store.getAllKeys(range, maxCount);
-    req.onerror = t.unreached_func('getAllKeys request should succeed');
-    return req;
-}
-
-getall_test(function(t, connection) {
-      var req = createGetAllKeysRequest(t, 'out-of-line', connection, 'c');
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, ['c']);
-          t.done();
-      });
-    }, 'Single item get');
-
-getall_test(function(t, connection) {
-      var req = createGetAllKeysRequest(t, 'generated', connection, 3);
-      req.onsuccess = t.step_func(function(evt) {
-          var data = evt.target.result;
-          assert_true(Array.isArray(data));
-          assert_array_equals(data, [3]);
-          t.done();
-      });
-    }, 'Single item get (generated key)');
-
-getall_test(function(t, connection) {
-      var req = createGetAllKeysRequest(t, 'empty', connection);
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, [],
-              'getAllKeys() on empty object store should return an empty ' +
-                  'array');
-          t.done();
-      });
-    }, 'getAllKeys on empty object store');
-
-getall_test(function(t, connection) {
-      var req = createGetAllKeysRequest(t, 'out-of-line', connection);
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, alphabet);
-          t.done();
-      });
-    }, 'Get all values');
-
-getall_test(function(t, connection) {
-      var req = createGetAllKeysRequest(t, 'out-of-line', connection, undefined,
-                                    10);
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, 'abcdefghij'.split(''));
-          t.done();
-      });
-    }, 'Test maxCount');
-
-getall_test(function(t, connection) {
-      var req = createGetAllKeysRequest(t, 'out-of-line', connection,
-                                    IDBKeyRange.bound('g', 'm'));
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, 'ghijklm'.split(''));
-          t.done();
-      });
-    }, 'Get bound range');
-
-getall_test(function(t, connection) {
-      var req = createGetAllKeysRequest(t, 'out-of-line', connection,
-                                    IDBKeyRange.bound('g', 'm'), 3);
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, ['g', 'h', 'i']);
-          t.done();
-      });
-    }, 'Get bound range with maxCount');
-
-getall_test(function(t, connection) {
-      var req = createGetAllKeysRequest(t, 'out-of-line', connection,
-                                    IDBKeyRange.bound('g', 'k', false, true));
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, ['g', 'h', 'i', 'j']);
-          t.done();
-      });
-    }, 'Get upper excluded');
-
-getall_test(function(t, connection) {
-      var req = createGetAllKeysRequest(t, 'out-of-line', connection,
-                                    IDBKeyRange.bound('g', 'k', true, false));
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, ['h', 'i', 'j', 'k']);
-          t.done();
-      });
-    }, 'Get lower excluded');
-
-getall_test(function(t, connection) {
-      var req = createGetAllKeysRequest(t, 'generated', connection,
-                                    IDBKeyRange.bound(4, 15), 3);
-      req.onsuccess = t.step_func(function(evt) {
-          var data = evt.target.result;
-          assert_true(Array.isArray(data));
-          assert_array_equals(data, [4, 5, 6]);
-          t.done();
-      });
-    }, 'Get bound range (generated) with maxCount');
-
-getall_test(function(t, connection) {
-      var req = createGetAllKeysRequest(t, 'out-of-line', connection,
-                                    "Doesn't exist");
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, [],
-              'getAllKeys() using a nonexistent key should return an ' +
-                  'empty array');
-          t.done();
-      });
-      req.onerror = t.unreached_func('getAllKeys request should succeed');
-    }, 'Non existent key');
-
-getall_test(function(t, connection) {
-      var req = createGetAllKeysRequest(t, 'out-of-line', connection, undefined,
-          0);
-      req.onsuccess = t.step_func(function(evt) {
-          assert_array_equals(evt.target.result, alphabet);
-          t.done();
-      });
-    }, 'zero maxCount');
-
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getKey.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getKey.any.js
new file mode 100644
index 0000000..7397747
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getKey.any.js
@@ -0,0 +1,89 @@
+// META: title=IndexedDB: Test IDBObjectStore.getKey()
+// META: script=support.js
+
+'use strict';
+
+function getkey_test(func, name) {
+  indexeddb_test(
+    (t, db, tx) => {
+      const basic = db.createObjectStore('basic');
+      const key_path_store = db.createObjectStore('key path',
+        { keyPath: 'id' });
+      const key_generator_store = db.createObjectStore('key generator',
+        { autoIncrement: true });
+      const key_generator_and_path_store = db.createObjectStore(
+        'key generator and key path',
+        { autoIncrement: true, key_path: 'id' });
+
+      for (let i = 1; i <= 10; ++i) {
+        basic.put(`value: ${i}`, i);
+        key_path_store.put({ id: i });
+        key_generator_store.put(`value: ${i}`);
+        key_generator_and_path_store.put({});
+      }
+    },
+    func,
+    name
+  );
+}
+
+getkey_test((t, db) => {
+  const tx = db.transaction('basic');
+  const store = tx.objectStore('basic');
+  assert_throws_js(TypeError, () => store.getKey());
+  assert_throws_dom('DataError', () => store.getKey(null));
+  assert_throws_dom('DataError', () => store.getKey({}));
+  t.done();
+}, 'IDBObjectStore.getKey() - invalid parameters');
+
+[
+  'basic',
+  'key path',
+  'key generator',
+  'key generator and key path'
+].forEach(store_name => {
+  getkey_test((t, db) => {
+    const tx = db.transaction(store_name);
+    const store = tx.objectStore(store_name);
+    const request = store.getKey(5);
+    request.onerror = t.unreached_func('request failed');
+    request.onsuccess = t.step_func(() =>
+      assert_equals(request.result, 5));
+    tx.onabort = t.unreached_func('transaction aborted');
+    tx.oncomplete = t.step_func(() => t.done());
+  }, `IDBObjectStore.getKey() - ${store_name} - key`);
+
+  getkey_test((t, db) => {
+    const tx = db.transaction(store_name);
+    const store = tx.objectStore(store_name);
+    const request = store.getKey(IDBKeyRange.lowerBound(4.5));
+    request.onerror = t.unreached_func('request failed');
+    request.onsuccess = t.step_func(() =>
+      assert_equals(request.result, 5));
+    tx.onabort = t.unreached_func('transaction aborted');
+    tx.oncomplete = t.step_func(() => t.done());
+  }, `IDBObjectStore.getKey() - ${store_name} - range`);
+
+  getkey_test((t, db) => {
+    const tx = db.transaction(store_name);
+    const store = tx.objectStore(store_name);
+    const request = store.getKey(11);
+    request.onerror = t.unreached_func('request failed');
+    request.onsuccess = t.step_func(() =>
+      assert_equals(request.result, undefined));
+    tx.onabort = t.unreached_func('transaction aborted');
+    tx.oncomplete = t.step_func(() => t.done());
+  }, `IDBObjectStore.getKey() - ${store_name} - key - no match`);
+
+  getkey_test((t, db) => {
+    const tx = db.transaction(store_name);
+    const store = tx.objectStore(store_name);
+    const request = store.getKey(IDBKeyRange.lowerBound(11));
+    request.onerror = t.unreached_func('request failed');
+    request.onsuccess = t.step_func(() =>
+      assert_equals(request.result, undefined)
+    );
+    tx.onabort = t.unreached_func('transaction aborted');
+    tx.oncomplete = t.step_func(() => t.done());
+  }, `IDBObjectStore.getKey() - ${store_name} - range - no match`);
+});
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getKey.html b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getKey.html
deleted file mode 100644
index 9e36625..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_getKey.html
+++ /dev/null
@@ -1,99 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<title>IndexedDB: Test IDBObjectStore.getKey()</title>
-<meta name=timeout content=long>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support.js"></script>
-<script>
-
-function getkey_test(func, name) {
-    indexeddb_test(
-        function(t, db, tx) {
-            var basic = db.createObjectStore('basic');
-            var key_path_store = db.createObjectStore('key path',
-                {keyPath: 'id'});
-            var key_generator_store = db.createObjectStore('key generator',
-                {autoIncrement: true});
-            var key_generator_and_path_store = db.createObjectStore(
-                'key generator and key path',
-                {autoIncrement: true, key_path: 'id'});
-
-            for (var i = 1; i <= 10; ++i) {
-                basic.put('value: ' + i, i);
-                key_path_store.put({id: i});
-                key_generator_store.put('value: ' + i);
-                key_generator_and_path_store.put({});
-            }
-        },
-        func,
-        name
-    );
-}
-
-getkey_test(function(t, db) {
-    var tx = db.transaction('basic');
-    var store = tx.objectStore('basic');
-    assert_throws_js(TypeError, function() { store.getKey(); });
-    assert_throws_dom('DataError', function() { store.getKey(null); });
-    assert_throws_dom('DataError', function() { store.getKey({}); });
-    t.done();
-}, 'IDBObjectStore.getKey() - invalid parameters');
-
-[
-    'basic',
-    'key path',
-    'key generator',
-    'key generator and key path'
-].forEach(function(store_name) {
-
-    getkey_test(function(t, db) {
-        var tx = db.transaction(store_name);
-        var store = tx.objectStore(store_name);
-        var request = store.getKey(5);
-        request.onerror = t.unreached_func('request failed');
-        request.onsuccess = t.step_func(function() {
-            assert_equals(request.result, 5);
-        });
-        tx.onabort = t.unreached_func('transaction aborted');
-        tx.oncomplete = t.step_func(function() { t.done(); });
-    }, 'IDBObjectStore.getKey() - ' + store_name + ' - key');
-
-    getkey_test(function(t, db) {
-        var tx = db.transaction(store_name);
-        var store = tx.objectStore(store_name);
-        var request = store.getKey(IDBKeyRange.lowerBound(4.5));
-        request.onerror = t.unreached_func('request failed');
-        request.onsuccess = t.step_func(function() {
-            assert_equals(request.result, 5);
-        });
-        tx.onabort = t.unreached_func('transaction aborted');
-        tx.oncomplete = t.step_func(function() { t.done(); });
-    }, 'IDBObjectStore.getKey() - ' + store_name + ' - range');
-
-    getkey_test(function(t, db) {
-        var tx = db.transaction(store_name);
-        var store = tx.objectStore(store_name);
-        var request = store.getKey(11);
-        request.onerror = t.unreached_func('request failed');
-        request.onsuccess = t.step_func(function() {
-            assert_equals(request.result, undefined);
-        });
-        tx.onabort = t.unreached_func('transaction aborted');
-        tx.oncomplete = t.step_func(function() { t.done(); });
-    }, 'IDBObjectStore.getKey() - ' + store_name + ' - key - no match');
-
-    getkey_test(function(t, db) {
-        var tx = db.transaction(store_name);
-        var store = tx.objectStore(store_name);
-        var request = store.getKey(IDBKeyRange.lowerBound(11));
-        request.onerror = t.unreached_func('request failed');
-        request.onsuccess = t.step_func(function() {
-            assert_equals(request.result, undefined);
-        });
-        tx.onabort = t.unreached_func('transaction aborted');
-        tx.oncomplete = t.step_func(function() { t.done(); });
-    }, 'IDBObjectStore.getKey() - ' + store_name + ' - range - no match');
-});
-
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_index.htm b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_index.htm
index 5da58ec..f01474a 100644
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_index.htm
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_index.htm
@@ -29,6 +29,3 @@
 
 </script>
 
-
-<div id="log"></div>
-
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/anonymous-iframe/cookie-store.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/anonymous-iframe/cookie-store.tentative.https.window.js
new file mode 100644
index 0000000..2332cb4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/anonymous-iframe/cookie-store.tentative.https.window.js
@@ -0,0 +1,92 @@
+// META: timeout=long
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=../credentialless/resources/common.js
+// META: script=./resources/common.js
+
+// A set of tests, checking cookies defined from within an anonymous iframe
+// continue to work.
+
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+const cookie_key = token()
+
+const anonymous_iframe = newAnonymousIframe(cross_origin);
+
+// Install some helper functions in the child to observe Cookies:
+promise_setup(async () => {
+  await send(anonymous_iframe, `
+    window.getMyCookie = () => {
+      const value = "; " + document.cookie;
+      const parts = value.split("; ${cookie_key}=");
+      if (parts.length !== 2)
+        return undefined
+      return parts.pop().split(';').shift();
+    };
+
+    window.nextCookieValue = () => {
+      return new Promise(resolve => {
+        const old_cookie = getMyCookie();
+        const interval = setInterval(() => {
+          const next_cookie_value = getMyCookie();
+          if (old_cookie !== next_cookie_value) {
+            clearInterval(interval);
+            resolve(next_cookie_value)
+          }
+        })
+      });
+    };
+  `);
+}, "Setup");
+
+promise_test(async test => {
+  const this_token = token();
+  send(anonymous_iframe, `
+    document.cookie = "${cookie_key}=cookie_value_1";
+    send("${this_token}", getMyCookie());
+  `);
+
+  assert_equals(await receive(this_token), "cookie_value_1");
+}, "Set/Get cookie via JS API");
+
+promise_test(async test => {
+  const resource_token = token();
+  send(anonymous_iframe, `
+    fetch("${showRequestHeaders(cross_origin, resource_token)}");
+  `);
+
+  const request_headers = JSON.parse(await receive(resource_token));
+  const cookie_value = parseCookies(request_headers)[cookie_key];
+  assert_equals(cookie_value, "cookie_value_1");
+}, "Get Cookie via subresource requests");
+
+promise_test(async test => {
+  const resource_token = token();
+  const resource_url = cross_origin + "/common/blank.html?pipe=" +
+    `|header(Set-Cookie,${cookie_key}=cookie_value_2;Path=/common/dispatcher)`;
+  const this_token = token();
+  send(anonymous_iframe, `
+    const next_cookie_value = nextCookieValue();
+    fetch("${resource_url}");
+    send("${this_token}", await next_cookie_value);
+  `);
+
+  assert_equals(await receive(this_token), "cookie_value_2");
+}, "Set Cookie via subresource requests");
+
+promise_test(async test => {
+  const resource_token = token();
+  const resource_url = cross_origin + "/common/blank.html?pipe=" +
+    `|header(Set-Cookie,${cookie_key}=cookie_value_3;Path=/common/dispatcher)`;
+  const this_token = token();
+  send(anonymous_iframe, `
+    const next_cookie_value = nextCookieValue();
+    const iframe = document.createElement("iframe");
+    iframe.src = "${resource_url}";
+    document.body.appendChild(iframe);
+    send("${this_token}", await next_cookie_value);
+  `);
+
+  assert_equals(await receive(this_token), "cookie_value_3");
+}, "Set Cookie via navigation requests");
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coop-sandbox-cuts-opener.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coop-sandbox-cuts-opener.https.html
new file mode 100644
index 0000000..47e6d0d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coop-sandbox-cuts-opener.https.html
@@ -0,0 +1,66 @@
+<!doctype html>
+<title>
+  Sandboxed Cross-Origin-Opener-Policy popup should cut the opener if necessary
+</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<body>
+<script>
+const executor_path = "/common/dispatcher/executor.html?pipe=";
+const coop_same_origin_header =
+  '|header(Cross-Origin-Opener-Policy,same-origin)';
+const coop_unsafe_none_header =
+  '|header(Cross-Origin-Opener-Policy,unsafe-none)';
+
+function getExecutorPath(uuid, origin, coop_header) {
+  return origin.origin + executor_path + coop_header  + `&uuid=${uuid}`;
+}
+
+[
+  "allow-popups allow-scripts allow-same-origin",
+  "allow-popups allow-scripts",
+].forEach(sandboxValue => {
+  async_test(t => {
+    // Set up dispatcher communications.
+    const iframe_token = token();
+    const popup_token = token();
+    const main_frame_token_for_popup = token();
+    const main_frame_token_for_iframe = token();
+
+    // Create a sandboxed iframe.
+    const iframe = document.createElement("iframe");
+    iframe.sandbox = sandboxValue;
+    iframe.src = getExecutorPath(iframe_token, SAME_ORIGIN,
+                                 coop_unsafe_none_header);
+    document.body.append(iframe);
+    t.add_cleanup(() => iframe.remove());
+
+    // Open a COOP popup from the sandboxed iframe.
+    const popup_url = getExecutorPath(popup_token,
+    SAME_ORIGIN,
+    coop_same_origin_header);
+    send(iframe_token, `window.popup = window.open('${popup_url}')`);
+
+    // This should fail. We ping the popup, if we get an answer it loaded.
+    send(popup_token, `
+    send('${main_frame_token_for_popup}', 'Popup loaded');
+    `);
+    receive(main_frame_token_for_popup)
+    .then(t.unreached_func("A COOP popup was created from a sandboxed frame"));
+
+    // We delay probing the popup.closed property to give it time to settle.
+    t.step_timeout(() => {
+    send(iframe_token,
+    `send('${main_frame_token_for_iframe}', window.popup.closed);`);
+    }, 1500);
+    receive(main_frame_token_for_iframe)
+    .then(t.step_func_done(data => assert_equals(data, "true")));
+
+  }, `<iframe sandbox="${sandboxValue}"> ${document.title}`);
+});
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackProcessor-video.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackProcessor-video.https.html
index 7cc87c7..9295db3 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackProcessor-video.https.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackProcessor-video.https.html
@@ -46,10 +46,10 @@
   return promise;
 }, "Tests that the reader of a video MediaStreamTrackProcessor produces VideoFrame objects and is closed on track stop while running on a worker");
 
-function makeVideoFrame() {
+function makeVideoFrame(timestamp) {
   const canvas = new OffscreenCanvas(100, 100);
   const ctx = canvas.getContext('2d');
-  return new VideoFrame(canvas);
+  return new VideoFrame(canvas, {timestamp});
 }
 
 promise_test(async t => {
@@ -80,7 +80,7 @@
   // Write video frames in different tasks to "slowly" settle the pending read
   // requests.
   for (let i = 0; i<numOperations; i++) {
-     await writer.write(makeVideoFrame());
+     await writer.write(makeVideoFrame(i));
      await new Promise(r=>setTimeout(r,0));
   }
 
diff --git a/third_party/blink/web_tests/external/wpt/svg/text/reftests/gradient-after-reposition-ref.html b/third_party/blink/web_tests/external/wpt/svg/text/reftests/gradient-after-reposition-ref.html
new file mode 100644
index 0000000..3fe1224
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/text/reftests/gradient-after-reposition-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<body>
+<svg style="border: 1px solid gray;">
+  <defs>
+    <linearGradient id="testGradient">
+      <stop stop-color="#000000" offset="0%"/>
+      <stop stop-color="#000000" offset="50%"/>
+      <stop stop-color="#3dcd58" offset="50%"/>
+      <stop stop-color="#ff4a4a" offset="100%"/>
+    </linearGradient>
+  </defs>
+  <text fill="url(#testGradient)" x="50" y="50" font-weight="bold" font-size="40">
+  Test gradient</text>
+</svg>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/svg/text/reftests/gradient-after-reposition.html b/third_party/blink/web_tests/external/wpt/svg/text/reftests/gradient-after-reposition.html
new file mode 100644
index 0000000..850b0eb9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/text/reftests/gradient-after-reposition.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<link rel="match" href="gradient-after-reposition-ref.html">
+<link rel="help" href="https://crbug.com/1274630">
+<body>
+<svg style="border: 1px solid gray;">
+  <defs>
+    <linearGradient id="testGradient">
+      <stop stop-color="#000000" offset="0%"/>
+      <stop stop-color="#000000" offset="50%"/>
+      <stop stop-color="#3dcd58" offset="50%"/>
+      <stop stop-color="#ff4a4a" offset="100%"/>
+    </linearGradient>
+  </defs>
+  <text id="test" fill="url(#testGradient)" x="25" y="50" font-weight="bold" font-size="40">
+  Test gradient</text>
+</svg>
+
+<script>
+requestAnimationFrame(() => {
+  requestAnimationFrame(() => {
+    const text  = document.getElementById('test');
+    text.setAttribute('x', '50');
+    document.documentElement.classList.remove('reftest-wait');
+  });
+});
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/receiver-track-live-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/receiver-track-live-expected.txt
deleted file mode 100644
index 93d7c92..0000000
--- a/third_party/blink/web_tests/external/wpt/webrtc/receiver-track-live-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL Setup audio call promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getUserMedia' of undefined"
-FAIL Inactivate the audio transceiver promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getTransceivers' of undefined"
-FAIL Reactivate the audio transceiver promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getTransceivers' of undefined"
-FAIL Clean-up promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'close' of undefined"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-formatting-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-formatting-expected.txt
index d2b4787..7b226ef 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-formatting-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-formatting-expected.txt
@@ -10,7 +10,7 @@
           firstProperty: rgba(1, 2, 3, 0);
           color: red;   /* comment1 */
           zoom: 1;/* comment2 */ /* like: property */
-          padding: 0;
+          padding: 0
       }
 
 Running: testFormattedRemoveStart
@@ -19,7 +19,7 @@
           /* leading comment */
           color: red;   /* comment1 */
           zoom: 1;/* comment2 */ /* like: property */
-          padding: 0;
+          padding: 0
       }
 
 Running: testFormattedInsertMiddle
@@ -29,7 +29,7 @@
           color: red;   /* comment1 */
           middleProperty: middleValue /* comment */;
           zoom: 1;/* comment2 */ /* like: property */
-          padding: 0;
+          padding: 0
       }
 
 Running: testFormattedRemoveMiddle
@@ -38,7 +38,7 @@
           /* leading comment */
           color: red;   /* comment1 */
           zoom: 1;/* comment2 */ /* like: property */
-          padding: 0;
+          padding: 0
       }
 
 Running: testFormattedInsertEnd
diff --git a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-blocked-when-target-blank-expected.txt b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-blocked-when-target-blank-expected.txt
index b155f04..5f67cf1 100644
--- a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-blocked-when-target-blank-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-blocked-when-target-blank-expected.txt
@@ -14,4 +14,5 @@
 ===============================================
 
 ============== Back Forward List ==============
+curr->  
 ===============================================
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 6f2c010..c69b987 100644
--- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -2177,6 +2177,7 @@
     attribute WAIT_FAILED
     attribute ZERO
     getter canvas
+    getter drawingBufferFormat
     getter drawingBufferHeight
     getter drawingBufferWidth
     method activeTexture
@@ -2257,6 +2258,7 @@
     method drawElements
     method drawElementsInstanced
     method drawRangeElements
+    method drawingBufferStorage
     method enable
     method enableVertexAttribArray
     method endQuery
@@ -2726,6 +2728,7 @@
     attribute VIEWPORT
     attribute ZERO
     getter canvas
+    getter drawingBufferFormat
     getter drawingBufferHeight
     getter drawingBufferWidth
     method activeTexture
@@ -2776,6 +2779,7 @@
     method disableVertexAttribArray
     method drawArrays
     method drawElements
+    method drawingBufferStorage
     method enable
     method enableVertexAttribArray
     method finish
diff --git a/third_party/blink/web_tests/mhtml/resources/mhtml_generator.py b/third_party/blink/web_tests/mhtml/resources/mhtml_generator.py
index 0fd52bbe..1f45fec 100755
--- a/third_party/blink/web_tests/mhtml/resources/mhtml_generator.py
+++ b/third_party/blink/web_tests/mhtml/resources/mhtml_generator.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
 # Copyright (c) 2013, Opera Software ASA. All rights reserved.
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt b/third_party/blink/web_tests/platform/mac-mac11-arm64/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt
new file mode 100644
index 0000000..7bbaab9
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt
@@ -0,0 +1,79 @@
+This is a testharness.js-based test.
+Found 75 tests; 50 PASS, 25 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS getStats succeeds
+PASS Validating stats
+PASS RTCRtpStreamStats's ssrc
+PASS RTCRtpStreamStats's kind
+PASS RTCRtpStreamStats's transportId
+PASS RTCRtpStreamStats's codecId
+PASS RTCReceivedRtpStreamStats's packetsReceived
+PASS RTCReceivedRtpStreamStats's packetsLost
+PASS RTCReceivedRtpStreamStats's jitter
+PASS RTCReceivedRtpStreamStats's packetsDiscarded
+PASS RTCReceivedRtpStreamStats's framesDropped
+FAIL RTCInboundRtpStreamStats's receiverId assert_true: Is receiverId present expected true got false
+FAIL RTCInboundRtpStreamStats's remoteId assert_true: Is remoteId present expected true got false
+PASS RTCInboundRtpStreamStats's framesDecoded
+PASS RTCInboundRtpStreamStats's nackCount
+PASS RTCInboundRtpStreamStats's framesReceived
+PASS RTCInboundRtpStreamStats's bytesReceived
+PASS RTCInboundRtpStreamStats's totalAudioEnergy
+PASS RTCInboundRtpStreamStats's totalSamplesDuration
+FAIL RTCRemoteInboundRtpStreamStats's localId assert_true: Is localId present expected true got false
+FAIL RTCRemoteInboundRtpStreamStats's roundTripTime assert_true: Is roundTripTime present expected true got false
+PASS RTCSentRtpStreamStats's packetsSent
+PASS RTCSentRtpStreamStats's bytesSent
+FAIL RTCOutboundRtpStreamStats's senderId assert_true: Is senderId present expected true got false
+FAIL RTCOutboundRtpStreamStats's remoteId assert_true: Is remoteId present expected true got false
+PASS RTCOutboundRtpStreamStats's framesEncoded
+PASS RTCOutboundRtpStreamStats's nackCount
+PASS RTCOutboundRtpStreamStats's framesSent
+FAIL RTCRemoteOutboundRtpStreamStats's localId assert_true: Is localId present expected true got false
+FAIL RTCRemoteOutboundRtpStreamStats's remoteTimestamp assert_true: Is remoteTimestamp present expected true got false
+PASS RTCPeerConnectionStats's dataChannelsOpened
+PASS RTCPeerConnectionStats's dataChannelsClosed
+PASS RTCDataChannelStats's label
+PASS RTCDataChannelStats's protocol
+PASS RTCDataChannelStats's dataChannelIdentifier
+PASS RTCDataChannelStats's state
+PASS RTCDataChannelStats's messagesSent
+PASS RTCDataChannelStats's bytesSent
+PASS RTCDataChannelStats's messagesReceived
+PASS RTCDataChannelStats's bytesReceived
+PASS RTCMediaSourceStats's trackIdentifier
+PASS RTCMediaSourceStats's kind
+PASS RTCAudioSourceStats's totalAudioEnergy
+PASS RTCAudioSourceStats's totalSamplesDuration
+PASS RTCVideoSourceStats's width
+PASS RTCVideoSourceStats's height
+PASS RTCVideoSourceStats's framesPerSecond
+FAIL RTCMediaHandlerStats's trackIdentifier assert_true: Is trackIdentifier present expected true got false
+PASS RTCCodecStats's payloadType
+PASS RTCCodecStats's mimeType
+PASS RTCCodecStats's clockRate
+PASS RTCCodecStats's channels
+PASS RTCCodecStats's sdpFmtpLine
+PASS RTCTransportStats's bytesSent
+PASS RTCTransportStats's bytesReceived
+FAIL RTCTransportStats's selectedCandidatePairId assert_true: Is selectedCandidatePairId present expected true got false
+PASS RTCTransportStats's localCertificateId
+FAIL RTCTransportStats's remoteCertificateId assert_true: Is remoteCertificateId present expected true got false
+FAIL RTCIceCandidatePairStats's transportId assert_true: Is transportId present expected true got false
+FAIL RTCIceCandidatePairStats's localCandidateId assert_true: Is localCandidateId present expected true got false
+FAIL RTCIceCandidatePairStats's remoteCandidateId assert_true: Is remoteCandidateId present expected true got false
+FAIL RTCIceCandidatePairStats's state assert_true: Is state present expected true got false
+FAIL RTCIceCandidatePairStats's nominated assert_true: Is nominated present expected true got false
+FAIL RTCIceCandidatePairStats's bytesSent assert_true: Is bytesSent present expected true got false
+FAIL RTCIceCandidatePairStats's bytesReceived assert_true: Is bytesReceived present expected true got false
+FAIL RTCIceCandidatePairStats's totalRoundTripTime assert_true: Is totalRoundTripTime present expected true got false
+FAIL RTCIceCandidatePairStats's currentRoundTripTime assert_true: Is currentRoundTripTime present expected true got false
+FAIL RTCIceCandidateStats's address assert_true: Is address present expected true got false
+FAIL RTCIceCandidateStats's port assert_true: Is port present expected true got false
+FAIL RTCIceCandidateStats's protocol assert_true: Is protocol present expected true got false
+FAIL RTCIceCandidateStats's candidateType assert_true: Is candidateType present expected true got false
+FAIL RTCIceCandidateStats's url assert_true: Is url present expected true got false
+PASS RTCCertificateStats's fingerprint
+PASS RTCCertificateStats's fingerprintAlgorithm
+PASS RTCCertificateStats's base64Certificate
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/README.md b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/README.md
deleted file mode 100644
index 81f92461..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/README.md
+++ /dev/null
@@ -1 +0,0 @@
-This virtual test suite is for testing the legacy Client Hints behavior when Permissions Policy delegation is disabled, and see that when the flag is on, legacy hints are sent to third party origins.
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-answers.sub.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-answers.sub.https-expected.txt
deleted file mode 100644
index 0ffad099..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-answers.sub.https-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-PASS Accept-CH header test
-FAIL Cross-Origin Accept-CH header test assert_false: device-memory-deprecated-received expected false got true
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-change.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-change.https-expected.txt
deleted file mode 100644
index 5e10daf9..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-change.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Accept-CH changes based on header assert_equals: expected "PASS" but got "FAIL"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-feature-policy-navigation.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-feature-policy-navigation.https-expected.txt
deleted file mode 100644
index 7dbe5ed0..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-feature-policy-navigation.https-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL Client hints loaded on cross-origin iframe request with feature policy. promise_test: Unhandled rejection with value: "FAIL Sec-CH-Device-Memory True None"
-FAIL Client hints loaded on same-origin iframe request with feature policy. promise_test: Unhandled rejection with value: "FAIL Sec-CH-DPR False 1"
-PASS Iframe trying to set Accept-CH-Lifetime.
-FAIL Client hints loaded on cross-origin iframe request with feature policy after attempting to set independently. promise_test: Unhandled rejection with value: "FAIL Sec-CH-Device-Memory True None"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-feature-policy.sub.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-feature-policy.sub.https-expected.txt
deleted file mode 100644
index 1b87d6a..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-feature-policy.sub.https-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL Accept-CH header test assert_false: dpr-received expected false got true
-FAIL Cross-Origin Accept-CH header test assert_true: device-memory-received expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-no-feature-policy-navigation.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-no-feature-policy-navigation.https-expected.txt
deleted file mode 100644
index d236abd..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-no-feature-policy-navigation.https-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL Client hints not loaded on cross-origin iframe request with no feature policy. promise_test: Unhandled rejection with value: "FAIL Sec-CH-UA True None"
-PASS Client hints loaded on same-origin iframe request with no feature policy.
-FAIL Client hints loaded on cross-origin iframe request with allow list. promise_test: Unhandled rejection with value: "FAIL Sec-CH-Device-Memory True None"
-PASS Client hints loaded on same-origin iframe request with allow list.
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-iframe-redirect-with-fp-delegation.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-iframe-redirect-with-fp-delegation.https-expected.txt
deleted file mode 100644
index c62fcc8..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-iframe-redirect-with-fp-delegation.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Iframe redirect with Feature Policy delegation got client hints according to expectations. assert_equals: message from opened frame expected "PASS" but got "DEVICE-MEMORY"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-navigation.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-navigation.https-expected.txt
deleted file mode 100644
index fbe2763..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-navigation.https-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-PASS cross origin navigation precondition: Test that the browser does not have client hints preferences cached
-PASS cross origin navigation set Accept-CH
-FAIL cross origin navigation got client hints according to expectations. assert_equals: message from opened page expected "PASS" but got "FAIL"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect-with-fp-delegation.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect-with-fp-delegation.https-expected.txt
deleted file mode 100644
index cea54bbdd..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect-with-fp-delegation.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL cross-origin subresource redirect with Feature Policy delegation got client hints according to expectations. assert_true: expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect.https-expected.txt
deleted file mode 100644
index 1a32d8c..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL cross-origin subresource redirect got client hints according to expectations. assert_true: expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-with-feature-policy.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-with-feature-policy.https-expected.txt
deleted file mode 100644
index 20e68e7..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-with-feature-policy.https-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-PASS cross origin subresources authorized by FP gets it own resources precondition: Test that the browser does not have client hints preferences cached
-PASS cross origin subresources authorized by FP gets it own resources set Accept-CH
-FAIL cross origin subresources authorized by FP gets it own resources got client hints according to expectations. assert_equals: message from opened page expected "PASS" but got "FAIL"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-syncxhr-redirect.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-syncxhr-redirect.https-expected.txt
deleted file mode 100644
index bc27661..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/cross-origin-syncxhr-redirect.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL cross-origin sync XHR redirect got client hints according to expectations. assert_true: expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/same-origin-navigation-no-accept-ch.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/same-origin-navigation-no-accept-ch.https-expected.txt
deleted file mode 100644
index ec33cf60..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/same-origin-navigation-no-accept-ch.https-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-PASS empty-ch on navigation precondition: Test that the browser does not have client hints preferences cached
-PASS empty-ch on navigation set Accept-CH to non-empty first
-PASS empty-ch on navigation set Accept-CH w/o header second
-FAIL empty-ch on navigation got client hints according to expectations. assert_equals: message from opened page expected "PASS" but got "FAIL"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/same-origin-navigation-redirect.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/same-origin-navigation-redirect.https-expected.txt
deleted file mode 100644
index c03e8108..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/same-origin-navigation-redirect.https-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-PASS redirect on navigation precondition: Test that the browser does not have client hints preferences cached
-FAIL redirect on navigation got client hints according to expectations. assert_equals: message from opened page expected "PASS" but got "DEVICE-MEMORY"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/same-origin-navigation.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/same-origin-navigation.https-expected.txt
deleted file mode 100644
index 5e95cf2..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/accept-ch-stickiness/same-origin-navigation.https-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-PASS same origin navigation precondition: Test that the browser does not have client hints preferences cached
-PASS same origin navigation set Accept-CH
-FAIL same origin navigation got client hints according to expectations. assert_equals: message from opened page expected "PASS" but got "FAIL"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/critical-ch/navigation.https.window-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/critical-ch/navigation.https.window-expected.txt
deleted file mode 100644
index d3a1661..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/critical-ch/navigation.https.window-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Critical-CH navigation assert_equals: expected "PASS" but got "FAIL"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/critical-ch/request-count.https.window-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/critical-ch/request-count.https.window-expected.txt
deleted file mode 100644
index c3653261..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/critical-ch/request-count.https.window-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Critical-CH navigation restart assert_equals: expected "2" but got "1"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/intercept-request.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/intercept-request.https-expected.txt
deleted file mode 100644
index ab3eff0..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/intercept-request.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Service workers succsefully receives hints from request assert_equals: expected "PASS" but got "FAIL"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/navigation-preload-critical.https.window-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/navigation-preload-critical.https.window-expected.txt
deleted file mode 100644
index ec92e422..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/navigation-preload-critical.https.window-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Service worker successfully passes hints through to new fetch assert_equals: expected "PASS" but got "FAIL"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/navigation-preload.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/navigation-preload.https-expected.txt
deleted file mode 100644
index ec92e422..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/navigation-preload.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Service worker successfully passes hints through to new fetch assert_equals: expected "PASS" but got "FAIL"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/passthrough-request-critical.https.window-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/passthrough-request-critical.https.window-expected.txt
deleted file mode 100644
index ec92e422..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/passthrough-request-critical.https.window-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Service worker successfully passes hints through to new fetch assert_equals: expected "PASS" but got "FAIL"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/passthrough-request.https-expected.txt b/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/passthrough-request.https-expected.txt
deleted file mode 100644
index ec92e422..0000000
--- a/third_party/blink/web_tests/virtual/legacy-client-hints-no-fp-delegation/external/wpt/client-hints/service-workers/passthrough-request.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Service worker successfully passes hints through to new fetch assert_equals: expected "PASS" but got "FAIL"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 081b44d..8feba2bf 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -2415,6 +2415,7 @@
 [Worker]     attribute WAIT_FAILED
 [Worker]     attribute ZERO
 [Worker]     getter canvas
+[Worker]     getter drawingBufferFormat
 [Worker]     getter drawingBufferHeight
 [Worker]     getter drawingBufferWidth
 [Worker]     method activeTexture
@@ -2495,6 +2496,7 @@
 [Worker]     method drawElements
 [Worker]     method drawElementsInstanced
 [Worker]     method drawRangeElements
+[Worker]     method drawingBufferStorage
 [Worker]     method enable
 [Worker]     method enableVertexAttribArray
 [Worker]     method endQuery
@@ -2964,6 +2966,7 @@
 [Worker]     attribute VIEWPORT
 [Worker]     attribute ZERO
 [Worker]     getter canvas
+[Worker]     getter drawingBufferFormat
 [Worker]     getter drawingBufferHeight
 [Worker]     getter drawingBufferWidth
 [Worker]     method activeTexture
@@ -3014,6 +3017,7 @@
 [Worker]     method disableVertexAttribArray
 [Worker]     method drawArrays
 [Worker]     method drawElements
+[Worker]     method drawingBufferStorage
 [Worker]     method enable
 [Worker]     method enableVertexAttribArray
 [Worker]     method finish
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index e4f872e..b798293 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -9842,6 +9842,7 @@
     attribute WAIT_FAILED
     attribute ZERO
     getter canvas
+    getter drawingBufferFormat
     getter drawingBufferHeight
     getter drawingBufferWidth
     method activeTexture
@@ -9922,6 +9923,7 @@
     method drawElements
     method drawElementsInstanced
     method drawRangeElements
+    method drawingBufferStorage
     method enable
     method enableVertexAttribArray
     method endQuery
@@ -10395,6 +10397,7 @@
     attribute VIEWPORT
     attribute ZERO
     getter canvas
+    getter drawingBufferFormat
     getter drawingBufferHeight
     getter drawingBufferWidth
     method activeTexture
@@ -10445,6 +10448,7 @@
     method disableVertexAttribArray
     method drawArrays
     method drawElements
+    method drawingBufferStorage
     method enable
     method enableVertexAttribArray
     method finish
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
index cf6c596..2e328ac 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -2056,6 +2056,7 @@
 [Worker]     attribute WAIT_FAILED
 [Worker]     attribute ZERO
 [Worker]     getter canvas
+[Worker]     getter drawingBufferFormat
 [Worker]     getter drawingBufferHeight
 [Worker]     getter drawingBufferWidth
 [Worker]     method activeTexture
@@ -2136,6 +2137,7 @@
 [Worker]     method drawElements
 [Worker]     method drawElementsInstanced
 [Worker]     method drawRangeElements
+[Worker]     method drawingBufferStorage
 [Worker]     method enable
 [Worker]     method enableVertexAttribArray
 [Worker]     method endQuery
@@ -2605,6 +2607,7 @@
 [Worker]     attribute VIEWPORT
 [Worker]     attribute ZERO
 [Worker]     getter canvas
+[Worker]     getter drawingBufferFormat
 [Worker]     getter drawingBufferHeight
 [Worker]     getter drawingBufferWidth
 [Worker]     method activeTexture
@@ -2655,6 +2658,7 @@
 [Worker]     method disableVertexAttribArray
 [Worker]     method drawArrays
 [Worker]     method drawElements
+[Worker]     method drawingBufferStorage
 [Worker]     method enable
 [Worker]     method enableVertexAttribArray
 [Worker]     method finish
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/background-sync.https.html b/third_party/blink/web_tests/wpt_internal/fenced_frame/background-sync.https.html
new file mode 100644
index 0000000..9762c10
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/background-sync.https.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<title>Test fenced frame does not allow to register background sync</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+
+<script>
+const background_sync_register_key = KEYS['background-sync'];
+
+function base_path() {
+  return location.pathname.replace(/\/[^\/]*$/, '/');
+}
+
+async function test(url, message) {
+  attachFencedFrame(url)
+
+  // Get the result for the top-level fenced frame.
+  const fenced_frame_result =
+      await nextValueFromServer(background_sync_register_key);
+  assert_equals(fenced_frame_result, 'failed', message);
+}
+
+promise_test(async (t) => {
+  const fencedFrameUrl = 'resources/background-sync-inner.https.html';
+  test(
+      fencedFrameUrl,
+      'background sync registration is disallowed inside a same-origin fenced frame');
+
+  const CROSS_ORIGIN_DESTINATION =
+      get_host_info()['HTTPS_REMOTE_ORIGIN'] + base_path() + fencedFrameUrl;
+  test(
+      CROSS_ORIGIN_DESTINATION,
+      'background sync registration is disallowed inside a cross-origin fenced frame');
+}, 'navigator.serviceWorker.register');
+</script>
+
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/background-sync-inner.https.html b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/background-sync-inner.https.html
new file mode 100644
index 0000000..7b19061
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/background-sync-inner.https.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="utils.js"></script>
+<title>Fenced frame content to report the result of background sync's register</title>
+
+<body>
+<script>
+(async function() {
+  const background_sync_register_key = KEYS['background-sync'];
+  const fencedframe_scope = 'background-sync-inner.https.html';
+  var scope = new URL('scope/' + fencedframe_scope,
+                      new URL(fencedframe_scope, window.location)).toString();
+  var options = {};
+  options.scope = scope;
+
+  navigator.serviceWorker.register("empty-worker.js", options);
+  const registration = await navigator.serviceWorker.ready;
+
+  // This test verifies that one-shot syncs can not be registered from an fenced frame.
+  registration.sync.register('fencedframe-oneshot').then(() => {
+    writeValueToServer(background_sync_register_key, "unexpectedly registered");
+  })
+  .catch((e) => {
+    writeValueToServer(background_sync_register_key, "failed");
+  })
+  .finally(() => {
+    registration.unregister();
+  });
+})();
+</script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/background-sync-inner.https.html.headers b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/background-sync-inner.https.html.headers
new file mode 100644
index 0000000..6247f6d
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/background-sync-inner.https.html.headers
@@ -0,0 +1 @@
+Supports-Loading-Mode: fenced-frame
\ No newline at end of file
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/empty-worker.js b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/empty-worker.js
new file mode 100644
index 0000000..49ceb264
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/empty-worker.js
@@ -0,0 +1 @@
+// Do nothing.
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/utils.js b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/utils.js
index 41db151..516677b3 100644
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/utils.js
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/utils.js
@@ -67,6 +67,7 @@
   "permission.geolocation"                      : "00000000-0000-0000-0000-000000000020",
 
   "presentation.receiver"                       : "00000000-0000-0000-0000-000000000021",
+  "background-sync"                             : "00000000-0000-0000-0000-000000000022",
   // Add keys above this list, incrementing the key UUID in hexadecimal
 }
 
diff --git a/tools/android/wpr/chrome_proxy_wpr_record.py b/tools/android/wpr/chrome_proxy_wpr_record.py
index fbebecb..4b337cd 100755
--- a/tools/android/wpr/chrome_proxy_wpr_record.py
+++ b/tools/android/wpr/chrome_proxy_wpr_record.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # 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.
diff --git a/tools/android/wpr/chrome_proxy_wpr_replay.py b/tools/android/wpr/chrome_proxy_wpr_replay.py
index 738fcac..0de5533 100755
--- a/tools/android/wpr/chrome_proxy_wpr_replay.py
+++ b/tools/android/wpr/chrome_proxy_wpr_replay.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # 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.
diff --git a/tools/binary_size/generate_official_build_report.py b/tools/binary_size/generate_official_build_report.py
index 1759328b..b254e5ce5 100755
--- a/tools/binary_size/generate_official_build_report.py
+++ b/tools/binary_size/generate_official_build_report.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # 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.
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py
index b24bd2e..8c02568 100644
--- a/tools/binary_size/libsupersize/archive.py
+++ b/tools/binary_size/libsupersize/archive.py
@@ -23,7 +23,6 @@
 import tempfile
 import time
 import zipfile
-import zlib
 
 import apkanalyzer
 import ar
@@ -39,6 +38,7 @@
 import ninja_parser
 import nm
 import obj_analyzer
+import pakfile
 import parallel
 import path_util
 import readelf
@@ -46,11 +46,6 @@
 import zip_util
 
 
-sys.path.insert(1, os.path.join(path_util.TOOLS_SRC_ROOT, 'tools', 'grit'))
-from grit.format import data_pack
-
-_UNCOMPRESSED_COMPRESSION_RATIO_THRESHOLD = 0.9
-
 # Holds computation state that is live only when an output directory exists.
 _OutputDirectoryContext = collections.namedtuple('_OutputDirectoryContext', [
     'elf_object_paths',  # Only when elf_path is also provided.
@@ -132,6 +127,14 @@
 
 
 @dataclasses.dataclass
+class PakSpec:
+  # One of pak_paths or apk_pak_paths must be non-None.
+  pak_paths: list = None
+  apk_pak_paths: list = None
+  pak_info_path: str = None
+
+
+@dataclasses.dataclass
 class ApkSpec:
   apk_path: str  # Never None.
   minimal_apks_path: str = None
@@ -309,7 +312,7 @@
       + 'FindSourceForTextAddress() likely has a bug.')
 
 
-def _NormalizeObjectPaths(raw_symbols):
+def _NormalizePaths(raw_symbols):
   """Fills in the |source_path| attribute and normalizes |object_path|."""
   logging.info('Normalizing source and object paths')
   for symbol in raw_symbols:
@@ -975,60 +978,6 @@
           raw_symbols, object_paths_by_name)
 
 
-def _ComputePakFileSymbols(file_name, contents, res_info, symbols_by_id):
-  # Reversed so that aliases are clobbered by the entries they are aliases of.
-  id_map = {id(v): k for k, v in reversed(contents.resources.items())}
-  alias_map = {
-      k: id_map[id(v)]
-      for k, v in contents.resources.items() if id_map[id(v)] != k
-  }
-  name = posixpath.basename(file_name)
-  # Hyphens used for language regions. E.g.: en-GB.pak, sr-Latn.pak, ...
-  # Longest translated .pak file without hyphen: fil.pak
-  if '-' in name or len(name) <= 7:
-    section_name = models.SECTION_PAK_TRANSLATIONS
-  else:
-    # E.g.: resources.pak, chrome_100_percent.pak.
-    section_name = models.SECTION_PAK_NONTRANSLATED
-  overhead = 12 + 6  # Header size plus extra offset
-  # Key just needs to be unique from other IDs and pak overhead symbols.
-  symbols_by_id[-len(symbols_by_id) - 1] = models.Symbol(
-      section_name, overhead, full_name='Overhead: {}'.format(file_name))
-  for resource_id in sorted(contents.resources):
-    aliased_resource_id = alias_map.get(resource_id)
-    if aliased_resource_id is not None:
-      # 4 extra bytes of metadata (2 16-bit ints)
-      size = 4
-      resource_id = aliased_resource_id
-    else:
-      resource_data = contents.resources[resource_id]
-      # 6 extra bytes of metadata (1 32-bit int, 1 16-bit int)
-      size = len(resource_data) + 6
-      name, source_path = res_info[resource_id]
-      if resource_id not in symbols_by_id:
-        full_name = '{}: {}'.format(source_path, name)
-        new_symbol = models.Symbol(
-            section_name, 0, address=resource_id, full_name=full_name)
-        if (section_name == models.SECTION_PAK_NONTRANSLATED and
-            _IsPakContentUncompressed(resource_data)):
-          new_symbol.flags |= models.FLAG_UNCOMPRESSED
-        symbols_by_id[resource_id] = new_symbol
-
-    symbols_by_id[resource_id].size += size
-  return section_name
-
-
-def _IsPakContentUncompressed(content):
-  raw_size = len(content)
-  # Assume anything less than 100 bytes cannot be compressed.
-  if raw_size < 100:
-    return False
-
-  compressed_size = len(zlib.compress(content, 1))
-  compression_ratio = compressed_size / float(raw_size)
-  return compression_ratio < _UNCOMPRESSED_COMPRESSION_RATIO_THRESHOLD
-
-
 class _ResourceSourceMapper:
   def __init__(self, size_info_prefix, knobs):
     self._knobs = knobs
@@ -1066,40 +1015,6 @@
     return None
 
 
-def _ParsePakInfoFile(pak_info_path):
-  with open(pak_info_path, 'r') as info_file:
-    res_info = {}
-    for line in info_file.readlines():
-      name, res_id, path = line.split(',')
-      res_info[int(res_id)] = (name, path.strip())
-  return res_info
-
-
-def _ParsePakSymbols(symbols_by_id, object_paths_by_pak_id):
-  raw_symbols = []
-  for resource_id, symbol in symbols_by_id.items():
-    raw_symbols.append(symbol)
-    paths = object_paths_by_pak_id.get(resource_id)
-    if not paths:
-      continue
-    symbol.object_path = paths[0]
-    if len(paths) == 1:
-      continue
-    aliases = symbol.aliases or [symbol]
-    symbol.aliases = aliases
-    for path in paths[1:]:
-      new_sym = models.Symbol(
-          symbol.section_name, symbol.size, address=symbol.address,
-          full_name=symbol.full_name, object_path=path, aliases=aliases)
-      aliases.append(new_sym)
-      raw_symbols.append(new_sym)
-
-  # Pre-sort to make final sort faster.
-  # Note: _SECTION_SORT_ORDER[] for pak symbols matches section_name ordering.
-  raw_symbols.sort(key=lambda s: (s.section_name, s.address, s.object_path))
-  return raw_symbols
-
-
 class _ResourcePathDeobfuscator:
 
   def __init__(self, pathmap_path):
@@ -1200,56 +1115,6 @@
   return dex_size, apk_symbols
 
 
-def _CreatePakObjectMap(object_paths_by_name):
-  # IDS_ macro usages result in templated function calls that contain the
-  # resource ID in them. These names are collected along with all other symbols
-  # by running "nm" on them. We just need to extract the values from them.
-  object_paths_by_pak_id = {}
-  PREFIX = 'void ui::AllowlistedResource<'
-  id_start_idx = len(PREFIX)
-  id_end_idx = -len('>()')
-  for name in object_paths_by_name:
-    if name.startswith(PREFIX):
-      pak_id = int(name[id_start_idx:id_end_idx])
-      object_paths_by_pak_id[pak_id] = object_paths_by_name[name]
-  return object_paths_by_pak_id
-
-
-def _FindPakSymbolsFromApk(section_ranges, apk_path, size_info_prefix):
-  with zipfile.ZipFile(apk_path) as z:
-    pak_zip_infos = (f for f in z.infolist() if f.filename.endswith('.pak'))
-    pak_info_path = size_info_prefix + '.pak.info'
-    res_info = _ParsePakInfoFile(pak_info_path)
-    symbols_by_id = {}
-    for zip_info in pak_zip_infos:
-      contents = data_pack.ReadDataPackFromString(z.read(zip_info))
-      if zip_info.compress_type != zipfile.ZIP_STORED:
-        logging.warning(
-            'Expected .pak files to be STORED, but this one is compressed: %s',
-            zip_info.filename)
-      section_name = _ComputePakFileSymbols(zip_info.filename, contents,
-                                            res_info, symbols_by_id)
-      _ExtendSectionRange(section_ranges, section_name, zip_info.compress_size)
-
-  return symbols_by_id
-
-
-def _FindPakSymbolsFromFiles(section_ranges, pak_files, pak_info_path,
-                             output_directory):
-  """Uses files from args to find and add pak symbols."""
-  res_info = _ParsePakInfoFile(pak_info_path)
-  symbols_by_id = {}
-  for pak_file_path in pak_files:
-    with open(pak_file_path, 'rb') as f:
-      contents = data_pack.ReadDataPackFromString(f.read())
-    section_name = _ComputePakFileSymbols(
-        os.path.relpath(pak_file_path, output_directory), contents, res_info,
-        symbols_by_id)
-    _ExtendSectionRange(section_ranges, section_name,
-                        os.path.getsize(pak_file_path))
-  return symbols_by_id
-
-
 def _CalculateElfOverhead(section_ranges, elf_path):
   if elf_path:
     section_sizes_total_without_bss = sum(
@@ -1355,12 +1220,12 @@
                               container_name,
                               metadata,
                               apk_spec,
+                              pak_spec,
                               native_spec,
                               source_directory,
                               output_directory=None,
                               resources_pathmap_path=None,
-                              pak_files=None,
-                              pak_info_file=None):
+                              pak_id_map=None):
   """Creates a Container (with sections sizes) and symbols for a SizeInfo.
 
   Args:
@@ -1368,15 +1233,15 @@
     container_name: Name for the created Container. May be '' if only one
         Container exists.
     metadata: Metadata dict from CreateMetadata().
-    apk_spec: Instance of ApkSpec.
-    native_spec: Instance of NativeSpec.
+    apk_spec: Instance of ApkSpec, or None.
+    pak_spec: Instance of PakSpec, or None.
+    native_spec: Instance of NativeSpec, or None.
     output_directory: Build output directory. If None, source_paths and symbol
         alias information will not be recorded.
     source_directory: Path to source root.
     resources_pathmap_path: Path to the pathmap file that maps original
         resource paths to shortened resource paths.
-    pak_files: List of paths to .pak files.
-    pak_info_file: Path to a .pak.info file.
+    pak_id_map: Instance of PakIdMap, or None.
 
   Returns:
     A tuple of (container, raw_symbols).
@@ -1442,6 +1307,13 @@
       section_ranges, raw_symbols, object_paths_by_name = _ParseElfInfo(
           native_spec, outdir_context=outdir_context)
 
+      if pak_id_map and native_spec.map_path:
+        # For trichrome, pak files are in different apks than native library,
+        # so need to pass along pak_id_map separately and ensure
+        # TrichromeLibrary appears first in .ssargs file.
+        logging.debug('Extracting pak IDs from symbol names')
+        pak_id_map.Update(object_paths_by_name, ninja_source_mapper)
+
   if apk_elf_result:
     logging.debug('Extracting section sizes from .so within .apk')
     apk_build_id, section_ranges, elf_overhead_size = apk_elf_result.get()
@@ -1464,15 +1336,9 @@
     raw_symbols, other_elf_symbols = _AddUnattributedSectionSymbols(
         raw_symbols, section_ranges)
 
-  pak_symbols_by_id = None
   other_symbols = []
   if apk_spec and apk_spec.size_info_prefix:
     # Can modify |section_ranges|.
-    pak_symbols_by_id = _FindPakSymbolsFromApk(section_ranges,
-                                               apk_spec.apk_path,
-                                               apk_spec.size_info_prefix)
-
-    # Can modify |section_ranges|.
     dex_size, other_symbols = _ParseApkOtherSymbols(
         apk_spec=apk_spec,
         native_spec=native_spec,
@@ -1513,10 +1379,23 @@
                 full_name='** .dex (unattributed - includes string literals)'))
       raw_symbols.extend(dex_symbols)
 
-  elif pak_files and pak_info_file:
-    # Can modify |section_ranges|.
-    pak_symbols_by_id = _FindPakSymbolsFromFiles(
-        section_ranges, pak_files, pak_info_file, output_directory)
+  if pak_spec:
+    logging.debug('Creating Pak symbols')
+    if pak_spec.apk_pak_paths:
+      assert apk_spec.size_info_prefix
+      # Can modify |section_ranges|.
+      raw_symbols += pakfile.CreatePakSymbolsFromApk(section_ranges,
+                                                     apk_spec.apk_path,
+                                                     pak_spec.apk_pak_paths,
+                                                     apk_spec.size_info_prefix,
+                                                     pak_id_map)
+    else:
+      # Can modify |section_ranges|.
+      raw_symbols += pakfile.CreatePakSymbolsFromFiles(section_ranges,
+                                                       pak_spec.pak_paths,
+                                                       pak_spec.pak_info_path,
+                                                       output_directory,
+                                                       pak_id_map)
 
   if native_spec:
     other_symbols.extend(other_elf_symbols)
@@ -1528,15 +1407,6 @@
                           elf_overhead_size)
       other_symbols.append(elf_overhead_symbol)
 
-  if pak_symbols_by_id:
-    logging.debug('Extracting pak IDs from symbol names, and creating symbols')
-    object_paths_by_pak_id = {}
-    if object_paths_by_name:
-      object_paths_by_pak_id = _CreatePakObjectMap(object_paths_by_name)
-    pak_raw_symbols = _ParsePakSymbols(
-        pak_symbols_by_id, object_paths_by_pak_id)
-    raw_symbols.extend(pak_raw_symbols)
-
   # Always have .other come last.
   other_symbols.sort(key=lambda s: (s.IsOverhead(), s.full_name.startswith(
       '**'), s.address, s.full_name))
@@ -1546,7 +1416,7 @@
     _AddSourcePathsUsingObjectPaths(ninja_source_mapper, raw_symbols)
   elif dwarf_source_mapper:
     _AddSourcePathsUsingAddress(dwarf_source_mapper, raw_symbols)
-  _NormalizeObjectPaths(raw_symbols)
+  _NormalizePaths(raw_symbols)
 
   dir_metadata.PopulateComponents(raw_symbols, source_directory)
   logging.info('Converting excessive aliases into shared-path symbols')
@@ -1672,6 +1542,7 @@
                      '--elf-file, no size metadata will be recorded.')
   group.add_argument('--pak-file',
                      action='append',
+                     default=[],
                      dest='pak_files',
                      help='Paths to pak files.')
   if is_top_args:
@@ -1730,7 +1601,8 @@
   group = parser.add_argument_group(title='Analysis Options for Pak Files')
   group.add_argument('--pak-info-file',
                      help='This file should contain all ids found in the pak '
-                     'files that have been passed in.')
+                     'files that have been passed in. If not specified, '
+                     '${pak_file}.info is assumed.')
 
   group = parser.add_argument_group(title='Analysis Options (shared)')
   group.add_argument('--source-directory',
@@ -2003,8 +1875,8 @@
 
   apk_spec = None
   if apk_prefix:
-    apk_spec = ApkSpec(minimal_apks_path=sub_args.minimal_apks_file,
-                       apk_path=apk_path,
+    apk_spec = ApkSpec(apk_path=apk_path,
+                       minimal_apks_path=sub_args.minimal_apks_file,
                        mapping_path=mapping_path,
                        split_name=split_name)
     if top_args.output_directory:
@@ -2014,6 +1886,18 @@
     apk_spec.analyze_dex = not (sub_args.native_only or sub_args.no_java
                                 or top_args.native_only or top_args.no_java)
 
+  pak_spec = None
+  apk_pak_paths = None
+  if apk_spec:
+    with zipfile.ZipFile(apk_spec.apk_path) as z:
+      apk_pak_paths = [
+          f.filename for f in z.infolist() if f.filename.endswith('.pak')
+      ]
+  if apk_pak_paths or sub_args.pak_files:
+    pak_spec = PakSpec(pak_paths=sub_args.pak_files,
+                       pak_info_path=sub_args.pak_info_file,
+                       apk_pak_paths=apk_pak_paths)
+
   if analyze_native:
     tool_prefix_finder = path_util.ToolPrefixFinder(
         value=top_args.tool_prefix,
@@ -2050,7 +1934,7 @@
     native_specs = []
 
   logging.info('Container Params: %r', sub_args.__dict__)
-  return (sub_args, apk_spec, native_specs, container_name,
+  return (sub_args, apk_spec, pak_spec, native_specs, container_name,
           resources_pathmap_path)
 
 
@@ -2147,9 +2031,10 @@
   seen_container_names = set()
   container_list = []
   raw_symbols_list = []
+  pak_id_map = pakfile.PakIdMap()
 
   # Iterate over each container.
-  for (sub_args, apk_spec, native_specs, container_name,
+  for (sub_args, apk_spec, pak_spec, native_specs, container_name,
        resources_pathmap_path) in _IterSubArgs(top_args, on_config_error):
     if not native_specs:
       native_specs = [None]
@@ -2169,12 +2054,12 @@
           container_name=container_name,
           metadata=metadata,
           apk_spec=apk_spec,
+          pak_spec=pak_spec,
           native_spec=native_spec,
           source_directory=sub_args.source_directory,
           output_directory=sub_args.output_directory,
           resources_pathmap_path=resources_pathmap_path,
-          pak_files=sub_args.pak_files,
-          pak_info_file=sub_args.pak_info_file)
+          pak_id_map=pak_id_map)
 
       container_list.append(container)
       raw_symbols_list.append(raw_symbols)
diff --git a/tools/binary_size/libsupersize/integration_test.py b/tools/binary_size/libsupersize/integration_test.py
index 592d105..dd37220 100755
--- a/tools/binary_size/libsupersize/integration_test.py
+++ b/tools/binary_size/libsupersize/integration_test.py
@@ -23,6 +23,7 @@
 import diff
 import file_format
 import models
+import pakfile
 import test_util
 
 
@@ -38,8 +39,11 @@
 _TEST_PAK_INFO_PATH = os.path.join(
     _TEST_OUTPUT_DIR, 'size-info/test.apk.pak.info')
 _TEST_ELF_FILE_BEGIN = os.path.join(_TEST_OUTPUT_DIR, 'elf.begin')
-_TEST_APK_LOCALE_PAK_PATH = os.path.join(_TEST_APK_ROOT_DIR, 'assets/en-US.pak')
-_TEST_APK_PAK_PATH = os.path.join(_TEST_APK_ROOT_DIR, 'assets/resources.pak')
+_TEST_APK_LOCALE_PAK_SUBPATH = 'assets/en-US.pak'
+_TEST_APK_PAK_SUBPATH = 'assets/resources.pak'
+_TEST_APK_LOCALE_PAK_PATH = os.path.join(_TEST_APK_ROOT_DIR,
+                                         _TEST_APK_LOCALE_PAK_SUBPATH)
+_TEST_APK_PAK_PATH = os.path.join(_TEST_APK_ROOT_DIR, _TEST_APK_PAK_SUBPATH)
 _TEST_ON_DEMAND_MANIFEST_PATH = os.path.join(_TEST_DATA_DIR,
                                              'AndroidManifest_OnDemand.xml')
 _TEST_ALWAYS_INSTALLED_MANIFEST_PATH = os.path.join(
@@ -202,6 +206,17 @@
       output_directory = _TEST_OUTPUT_DIR if use_output_directory else None
 
       def iter_specs():
+        pak_spec = None
+        if use_pak or use_apk or use_minimal_apks:
+          pak_spec = archive.PakSpec()
+          if use_pak:
+            pak_spec.pak_paths = [_TEST_APK_LOCALE_PAK_PATH, _TEST_APK_PAK_PATH]
+            pak_spec.pak_info_path = _TEST_PAK_INFO_PATH
+          else:
+            pak_spec.apk_pak_paths = [
+                _TEST_APK_LOCALE_PAK_SUBPATH, _TEST_APK_PAK_SUBPATH
+            ]
+
         native_spec = archive.NativeSpec(tool_prefix=_TEST_TOOL_PREFIX)
 
         # TODO(crbug.com/1193507): Remove when we implement string literal
@@ -232,16 +247,11 @@
                   '.minimal.apks', '.aab')
             apk_spec.size_info_prefix = os.path.join(
                 output_directory, 'size-info', os.path.basename(orig_path))
-        pak_files = None
-        pak_info_file = None
-        if use_pak:
-          pak_files = [_TEST_APK_LOCALE_PAK_PATH, _TEST_APK_PAK_PATH]
-          pak_info_file = _TEST_PAK_INFO_PATH
 
         container_name = ''
         if use_minimal_apks:
           container_name = 'Bundle.minimal.apks/base.apk'
-        yield container_name, apk_spec, native_spec, pak_files, pak_info_file
+        yield container_name, apk_spec, pak_spec, native_spec
 
         if use_minimal_apks:
           for split_name, apk_path in [
@@ -254,10 +264,11 @@
                 split_name=split_name,
                 size_info_prefix=apk_spec.size_info_prefix)
             native_spec = None
+            pak_spec = None
             container_name = 'Bundle.minimal.apks/%s.apk' % split_name
             if split_name == 'on_demand':
               container_name += '?'
-            yield container_name, apk_spec, native_spec, None, None
+            yield container_name, apk_spec, pak_spec, native_spec
 
       container_list = []
       raw_symbols_list = []
@@ -269,8 +280,8 @@
       knobs.max_same_name_alias_count = 3
 
       with _AddMocksToPath():
-        for (container_name, apk_spec, native_spec, pak_files,
-             pak_info_file) in iter_specs():
+        pak_id_map = pakfile.PakIdMap()
+        for container_name, apk_spec, pak_spec, native_spec in iter_specs():
           metadata = archive.CreateMetadata(build_config=build_config,
                                             apk_spec=apk_spec,
                                             native_spec=native_spec,
@@ -281,11 +292,11 @@
               container_name=container_name,
               metadata=metadata,
               apk_spec=apk_spec,
+              pak_spec=pak_spec,
               native_spec=native_spec,
               source_directory=_TEST_SOURCE_DIR,
               output_directory=output_directory,
-              pak_files=pak_files,
-              pak_info_file=pak_info_file)
+              pak_id_map=pak_id_map)
           container_list.append(container)
           raw_symbols_list.append(raw_symbols)
 
diff --git a/tools/binary_size/libsupersize/pakfile.py b/tools/binary_size/libsupersize/pakfile.py
new file mode 100644
index 0000000..44e79fe
--- /dev/null
+++ b/tools/binary_size/libsupersize/pakfile.py
@@ -0,0 +1,183 @@
+# 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.
+"""Size analysis of .pak files."""
+
+import collections
+import logging
+import os
+import posixpath
+import sys
+import zipfile
+import zlib
+
+import models
+import path_util
+
+sys.path.insert(1, os.path.join(path_util.TOOLS_SRC_ROOT, 'tools', 'grit'))
+from grit.format import data_pack
+
+_UNCOMPRESSED_COMPRESSION_RATIO_THRESHOLD = 0.9
+
+
+class PakIdMap:
+  def __init__(self):
+    self._dict = collections.defaultdict(set)
+
+  def Update(self, object_paths_by_name, ninja_source_mapper):
+    # IDS_ macro usages result in templated function calls that contain the
+    # resource ID in them. These names are collected along with all other
+    # symbols by running "nm" on them. We just need to extract the values.
+    PREFIX = 'void ui::AllowlistedResource<'
+    id_start_idx = len(PREFIX)
+    id_end_idx = -len('>()')
+    for name in object_paths_by_name:
+      if name.startswith(PREFIX):
+        pak_id = int(name[id_start_idx:id_end_idx])
+        object_paths = object_paths_by_name[name]
+        self._dict[pak_id].update(
+            (o, ninja_source_mapper.FindSourceForPath(o)) for o in object_paths)
+
+  def Lookup(self, pak_id):
+    ret = self._dict.get(pak_id)
+    if ret:
+      ret = sorted(ret)
+    return ret
+
+
+def _IsPakContentUncompressed(content):
+  raw_size = len(content)
+  # Assume anything less than 100 bytes cannot be compressed.
+  if raw_size < 100:
+    return False
+
+  compressed_size = len(zlib.compress(content, 1))
+  compression_ratio = compressed_size / float(raw_size)
+  return compression_ratio < _UNCOMPRESSED_COMPRESSION_RATIO_THRESHOLD
+
+
+def _ParsePakInfoFile(pak_info_path):
+  with open(pak_info_path, 'r') as info_file:
+    res_info = {}
+    for line in info_file.readlines():
+      name, res_id, path = line.split(',')
+      res_info[int(res_id)] = (name, path.strip())
+  return res_info
+
+
+def _CreateSymbolsFromFile(file_name, contents, res_info, symbols_by_id):
+  # Reversed so that aliases are clobbered by the entries they are aliases of.
+  id_map = {id(v): k for k, v in reversed(contents.resources.items())}
+  alias_map = {
+      k: id_map[id(v)]
+      for k, v in contents.resources.items() if id_map[id(v)] != k
+  }
+  name = posixpath.basename(file_name)
+  # Hyphens used for language regions. E.g.: en-GB.pak, sr-Latn.pak, ...
+  # Longest translated .pak file without hyphen: fil.pak
+  if '-' in name or len(name) <= 7:
+    section_name = models.SECTION_PAK_TRANSLATIONS
+  else:
+    # E.g.: resources.pak, chrome_100_percent.pak.
+    section_name = models.SECTION_PAK_NONTRANSLATED
+  overhead = 12 + 6  # Header size plus extra offset
+  # Key just needs to be unique from other IDs and pak overhead symbols.
+  symbols_by_id[-len(symbols_by_id) - 1] = models.Symbol(
+      section_name, overhead, full_name='Overhead: {}'.format(file_name))
+  for pak_id in sorted(contents.resources):
+    aliased_pak_id = alias_map.get(pak_id)
+    if aliased_pak_id is not None:
+      # 4 extra bytes of metadata (2 16-bit ints)
+      size = 4
+      pak_id = aliased_pak_id
+    else:
+      resource_data = contents.resources[pak_id]
+      # 6 extra bytes of metadata (1 32-bit int, 1 16-bit int)
+      size = len(resource_data) + 6
+      name, source_path = res_info[pak_id]
+      if pak_id not in symbols_by_id:
+        full_name = '{}: {}'.format(source_path, name)
+        new_symbol = models.Symbol(section_name,
+                                   0,
+                                   address=pak_id,
+                                   full_name=full_name)
+        if (section_name == models.SECTION_PAK_NONTRANSLATED
+            and _IsPakContentUncompressed(resource_data)):
+          new_symbol.flags |= models.FLAG_UNCOMPRESSED
+        symbols_by_id[pak_id] = new_symbol
+
+    symbols_by_id[pak_id].size += size
+  return section_name
+
+
+def _FinalizeSymbols(symbols_by_id, pak_id_map):
+  """Converts dict -> list, adds paths, and adds aliases."""
+  raw_symbols = []
+  for pak_id, symbol in symbols_by_id.items():
+    raw_symbols.append(symbol)
+    path_tuples = pak_id_map.Lookup(pak_id)
+    if not path_tuples:
+      continue
+    symbol.object_path, symbol.source_path = path_tuples[0]
+    if len(path_tuples) == 1:
+      continue
+    aliases = symbol.aliases or [symbol]
+    symbol.aliases = aliases
+    for object_path, source_path in path_tuples[1:]:
+      new_sym = models.Symbol(symbol.section_name,
+                              symbol.size,
+                              address=symbol.address,
+                              full_name=symbol.full_name,
+                              object_path=object_path,
+                              source_path=source_path,
+                              aliases=aliases)
+      aliases.append(new_sym)
+      raw_symbols.append(new_sym)
+
+  # Pre-sort to make final sort faster.
+  # Note: _SECTION_SORT_ORDER[] for pak symbols matches section_name ordering.
+  raw_symbols.sort(key=lambda s: (s.section_name, s.address, s.object_path))
+  return raw_symbols
+
+
+def _ExtendSectionRange(section_range_by_name, section_name, delta_size):
+  prev_address, prev_size = section_range_by_name.get(section_name, (0, 0))
+  section_range_by_name[section_name] = (prev_address, prev_size + delta_size)
+
+
+def CreatePakSymbolsFromApk(section_ranges, apk_path, apk_pak_paths,
+                            size_info_prefix, pak_id_map):
+  """Uses files in apk to find and add pak symbols."""
+  with zipfile.ZipFile(apk_path) as z:
+    pak_zip_infos = [z.getinfo(p) for p in apk_pak_paths]
+    pak_info_path = size_info_prefix + '.pak.info'
+    res_info = _ParsePakInfoFile(pak_info_path)
+    symbols_by_id = {}
+    for zip_info in pak_zip_infos:
+      contents = data_pack.ReadDataPackFromString(z.read(zip_info))
+      if zip_info.compress_type != zipfile.ZIP_STORED:
+        logging.warning(
+            'Expected .pak files to be STORED, but this one is compressed: %s',
+            zip_info.filename)
+      section_name = _CreateSymbolsFromFile(zip_info.filename, contents,
+                                            res_info, symbols_by_id)
+      _ExtendSectionRange(section_ranges, section_name, zip_info.compress_size)
+  return _FinalizeSymbols(symbols_by_id, pak_id_map)
+
+
+def CreatePakSymbolsFromFiles(section_ranges, pak_paths, pak_info_path,
+                              output_directory, pak_id_map):
+  """Uses files from --pak-file args to find and add pak symbols."""
+  if pak_info_path:
+    res_info = _ParsePakInfoFile(pak_info_path)
+  symbols_by_id = {}
+  for pak_path in pak_paths:
+    if not pak_info_path:
+      res_info = _ParsePakInfoFile(pak_path + '.info')
+    with open(pak_path, 'rb') as f:
+      contents = data_pack.ReadDataPackFromString(f.read())
+    section_name = _CreateSymbolsFromFile(
+        os.path.relpath(pak_path, output_directory), contents, res_info,
+        symbols_by_id)
+    _ExtendSectionRange(section_ranges, section_name, os.path.getsize(pak_path))
+  return _FinalizeSymbols(symbols_by_id, pak_id_map)
diff --git a/tools/code_coverage/test_suite.txt b/tools/code_coverage/test_suite.txt
index 7ad2a4d..0126753 100644
--- a/tools/code_coverage/test_suite.txt
+++ b/tools/code_coverage/test_suite.txt
@@ -52,7 +52,6 @@
 message_center_unittests
 midi_unittests
 mojo_unittests
-nacl_helper_nonsfi_unittests
 nacl_loader_unittests
 native_theme_unittests
 net_unittests
diff --git a/tools/determinism/deterministic_build_ignorelist.pyl b/tools/determinism/deterministic_build_ignorelist.pyl
index de4fd15..514c144 100644
--- a/tools/determinism/deterministic_build_ignorelist.pyl
+++ b/tools/determinism/deterministic_build_ignorelist.pyl
@@ -28,10 +28,7 @@
     'nacl_test_data/glibc/pm_exit_status_test_libs/lib64/libppapi_cpp_lib.so',
     'nacl_test_data/glibc/simple_libs/lib64/libppapi_cpp_lib.so',
     'nacl_test_data/glibc/sysconf_nprocessors_onln_test_libs/lib64/libppapi_cpp_lib.so',
-    'nacl_test_data/nonsfi/irt_exception_test_pnacl_newlib_x32_nonsfi.nexe',
-    'nacl_test_data/nonsfi/irt_manifest_file_pnacl_newlib_x32_nonsfi.nexe',
     'ppapi_nacl_tests_pnacl_newlib_x64.nexe',
-    'test_data/ppapi/tests/extensions/packaged_app/nonsfi/ppapi_tests_extensions_packaged_app_pnacl_newlib_x32_nonsfi.nexe',
 
     # https://crbug.com/1040247
     'nacl_irt_x86_64.nexe',
@@ -56,7 +53,6 @@
     'nacl_test_data/newlib/sysconf_nprocessors_onln_test_newlib_x86_64.nexe',
     'nacl_test_data/pnacl/pnacl_debug_url_newlib_pnacl.pexe.debug',
     'nacl_test_data/pnacl/pnacl_errors_newlib_pnacl.pexe',
-    'ppapi_nacl_tests_pnacl_newlib_x32_nonsfi.nexe',
     'ppapi_nacl_tests_newlib_x86_64.nexe',
     'test_data/ppapi/tests/extensions/background_keepalive/newlib/ppapi_tests_extensions_background_keepalive_newlib_x86_64.nexe',
     'test_data/ppapi/tests/extensions/load_unload/newlib/ppapi_tests_extensions_load_unload_newlib_x86_64.nexe',
@@ -72,11 +68,6 @@
   ],
 
   'linux_component': [
-    # https://crbug.com/954056
-    'nacl_test_data/nonsfi/irt_exception_test_pnacl_newlib_x32_nonsfi.nexe',
-    'nacl_test_data/nonsfi/irt_manifest_file_pnacl_newlib_x32_nonsfi.nexe',
-    'test_data/ppapi/tests/extensions/packaged_app/nonsfi/ppapi_tests_extensions_packaged_app_pnacl_newlib_x32_nonsfi.nexe',
-
     # https://crbug.com/1008035
     'nacl_test_data/extension_vcache_test/glibc/extension_validation_cache_libs/lib64/libppapi_cpp_lib.so',
     'nacl_test_data/glibc/pm_exit_status_test_libs/lib64/libppapi_cpp_lib.so',
@@ -105,7 +96,6 @@
     'nacl_test_data/newlib/sysconf_nprocessors_onln_test_newlib_x86_64.nexe',
     'nacl_test_data/pnacl/pnacl_debug_url_newlib_pnacl.pexe.debug',
     'nacl_test_data/pnacl/pnacl_errors_newlib_pnacl.pexe',
-    'ppapi_nacl_tests_pnacl_newlib_x32_nonsfi.nexe',
     'ppapi_nacl_tests_newlib_x86_64.nexe',
     'test_data/ppapi/tests/extensions/background_keepalive/newlib/ppapi_tests_extensions_background_keepalive_newlib_x86_64.nexe',
     'test_data/ppapi/tests/extensions/load_unload/newlib/ppapi_tests_extensions_load_unload_newlib_x86_64.nexe',
diff --git a/tools/ipc_fuzzer/BUILD.gn b/tools/ipc_fuzzer/BUILD.gn
index 7f177dd..c9f0124 100644
--- a/tools/ipc_fuzzer/BUILD.gn
+++ b/tools/ipc_fuzzer/BUILD.gn
@@ -6,9 +6,7 @@
 import("//tools/ipc_fuzzer/ipc_fuzzer.gni")
 
 config("ipc_fuzzer_config") {
-  if (!is_nacl_nonsfi) {
-    defines = [ "ENABLE_IPC_FUZZER" ]
-  }
+  defines = [ "ENABLE_IPC_FUZZER" ]
 }
 
 config("ipc_fuzzer_tool_config") {
diff --git a/tools/memory/partition_allocator/compute_external_fragmentation.py b/tools/memory/partition_allocator/compute_external_fragmentation.py
index 1fea847..ac7f94c 100755
--- a/tools/memory/partition_allocator/compute_external_fragmentation.py
+++ b/tools/memory/partition_allocator/compute_external_fragmentation.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # 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.
diff --git a/tools/memory/partition_allocator/compute_internal_fragmentation.py b/tools/memory/partition_allocator/compute_internal_fragmentation.py
index 8ca3dd7..79860349dd 100755
--- a/tools/memory/partition_allocator/compute_internal_fragmentation.py
+++ b/tools/memory/partition_allocator/compute_internal_fragmentation.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # 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.
diff --git a/tools/memory/partition_allocator/objects_per_size.py b/tools/memory/partition_allocator/objects_per_size.py
index 68822fe9..d7e4467e 100755
--- a/tools/memory/partition_allocator/objects_per_size.py
+++ b/tools/memory/partition_allocator/objects_per_size.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # 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.
diff --git a/tools/memory/partition_allocator/profile_allocations.py b/tools/memory/partition_allocator/profile_allocations.py
index 9b58691f..8cc2424e 100755
--- a/tools/memory/partition_allocator/profile_allocations.py
+++ b/tools/memory/partition_allocator/profile_allocations.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # 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.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index b0438db..98b7209 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -7555,6 +7555,7 @@
   <int value="131082" label="kContent-kMediaSession"/>
   <int value="131083" label="kContent-kMediaSessionService"/>
   <int value="131084" label="kContent-kMediaPlay"/>
+  <int value="131085" label="kContent-kScreenReader"/>
   <int value="196608" label="kEmbedder-kUnknown"/>
   <int value="196609" label="kEmbedder-kPopupBlockerTabHelper"/>
   <int value="196610" label="kEmbedder-kSafeBrowsingTriggeredPopupBlocker"/>
@@ -17462,6 +17463,12 @@
   <int value="1" label="Sync credentials were removed"/>
 </enum>
 
+<enum name="CredentialManagerError">
+  <int value="0" label="No context"/>
+  <int value="1" label="Provided account is empty"/>
+  <int value="2" label="API error"/>
+</enum>
+
 <enum name="CredentialManagerGetResult">
   <int value="0" label="Promise rejected"/>
   <int value="1" label="Empty credential, auto sign-in disallowed"/>
@@ -69547,6 +69554,8 @@
   <int value="30" label="kMixedContent"/>
   <int value="31" label="kTriggerBackgrounded"/>
   <int value="32" label="kEmbedderTriggeredAndRedirected"/>
+  <int value="33" label="kEmbedderTriggeredAndSameOriginRedirected"/>
+  <int value="34" label="kEmbedderTriggeredAndCrossOriginRedirected"/>
 </enum>
 
 <enum name="PrerenderHoverEvent">
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index 3cd07270..b153158 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -4783,6 +4783,16 @@
   </summary>
 </histogram>
 
+<histogram name="SingleWebsitePreferences.NavigatedFromToReset"
+    enum="SettingsNavigationSources" expires_after="M104">
+  <owner>peconn@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Logs which way had the user navigated into settings screens when they press
+    &quot;Clear and Reset&quot; button in settings of a single website.
+  </summary>
+</histogram>
+
 </histograms>
 
 </histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index d4407e1..e7ec9a1 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -766,7 +766,7 @@
 </histogram>
 
 <histogram name="Apps.AppList.OmniboxProvider.QueryTime" units="ms"
-    expires_after="2022-03-27">
+    expires_after="2022-05-29">
   <owner>jennyz@chromium.org</owner>
   <owner>newcomer@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/compositing/histograms.xml b/tools/metrics/histograms/metadata/compositing/histograms.xml
index 89d2e97..e0ee6f2 100644
--- a/tools/metrics/histograms/metadata/compositing/histograms.xml
+++ b/tools/metrics/histograms/metadata/compositing/histograms.xml
@@ -308,7 +308,7 @@
 </histogram>
 
 <histogram name="Compositing.Display.DrawToSwapUs" units="microseconds"
-    expires_after="2022-03-27">
+    expires_after="2022-05-29">
   <owner>backer@chromium.org</owner>
   <owner>rjkroege@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/cryptohome/histograms.xml b/tools/metrics/histograms/metadata/cryptohome/histograms.xml
index eb747d2..bfaafdff 100644
--- a/tools/metrics/histograms/metadata/cryptohome/histograms.xml
+++ b/tools/metrics/histograms/metadata/cryptohome/histograms.xml
@@ -53,7 +53,7 @@
 </histogram>
 
 <histogram name="Cryptohome.DeletedUserProfiles" units="profiles"
-    expires_after="2022-02-05">
+    expires_after="2022-05-29">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
index 5081335..4404d861 100644
--- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
+++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
@@ -346,6 +346,142 @@
   </summary>
 </histogram>
 
+<histogram name="TrustedWebActivity.ClearDataDialogOnClearAppDataAccepted"
+    enum="Boolean" expires_after="M104">
+  <owner>peconn@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Emits true if the user went to site settings from the dialog that is shown
+    after a Trusted Web Activity client app has had its data cleared.
+  </summary>
+</histogram>
+
+<histogram name="TrustedWebActivity.ClearDataDialogOnUninstallAccepted"
+    enum="Boolean" expires_after="M104">
+  <owner>peconn@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Emits true if the user went to site settings from the dialog that is shown
+    after a Trusted Web Activity client app has been uninstalled.
+  </summary>
+</histogram>
+
+<histogram name="TrustedWebActivity.DelegatedNotificationSmallIconFallback"
+    enum="TrustedWebActivityDelegatedNotificationSmallIconFallback"
+    expires_after="M104">
+  <owner>peconn@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Logs which kind of fallback for notification small icon was used for Trusted
+    Web Activity notification delegation.
+  </summary>
+</histogram>
+
+<histogram name="TrustedWebActivity.LocationDelegationEnrolled" enum="Boolean"
+    expires_after="2022-04-10">
+  <owner>eirage@chromium.org</owner>
+  <owner>peconn@chromium.org</owner>
+  <summary>
+    When a site running in Truested Web Activity is accessing geolocation,
+    records whether the last tracked focused Trusted Web Activity client app
+    enrolled location delegation.
+  </summary>
+</histogram>
+
+<histogram name="TrustedWebActivity.LocationPermissionChanged"
+    enum="TrustedWebActivityPermissionChanged" expires_after="2021-12-31">
+  <owner>eirage@chromium.org</owner>
+  <owner>peconn@chromium.org</owner>
+  <summary>
+    When a Trusted Web Activity client app's location permission is changed,
+    record the previous state and new stase.
+  </summary>
+</histogram>
+
+<histogram name="TrustedWebActivity.LocationPermissionRequestIsGranted"
+    enum="Boolean" expires_after="2021-12-31">
+  <owner>eirage@chromium.org</owner>
+  <owner>peconn@chromium.org</owner>
+  <summary>
+    Records the boolean result (granted or not) from requesting a Trusted Web
+    Activity client app's location permission.
+  </summary>
+</histogram>
+
+<histogram name="TrustedWebActivity.LocationUpdateErrorCode"
+    enum="TrustedWebActivityLocationErrorCode" expires_after="2021-12-31">
+  <owner>eirage@chromium.org</owner>
+  <owner>peconn@chromium.org</owner>
+  <summary>
+    Records an error code when we get a new location update or location error
+    from the Trusted Web Activity client app. Record
+    &quot;LocationUpdateError.NONE&quot; (value = 0) if there is no error and
+    the geoposition is valid.
+  </summary>
+</histogram>
+
+<histogram name="TrustedWebActivity.QualityEnforcementViolation"
+    enum="TrustedWebActivityQualityEnforcementViolationType"
+    expires_after="2021-12-31">
+  <owner>eirage@chromium.org</owner>
+  <owner>peconn@chromium.org</owner>
+  <summary>
+    When Trusted Web Activity launches or navigates to a site that violate the
+    quality criteria, records the violation type.
+  </summary>
+</histogram>
+
+<histogram name="TrustedWebActivity.QualityEnforcementViolation.Crashed"
+    enum="TrustedWebActivityQualityEnforcementViolationType"
+    expires_after="2021-12-31">
+  <owner>eirage@chromium.org</owner>
+  <owner>peconn@chromium.org</owner>
+  <summary>
+    When Trusted Web Activity launches or navigates to a site that violate the
+    quality criteria, and the CCT will be closed, records the violation type.
+
+    This is similar to TrustedWebActivity.QualityEnforcementViolation but only
+    records when the violation will close the CCT.
+  </summary>
+</histogram>
+
+<histogram name="TrustedWebActivity.ShareTargetRequest"
+    enum="WebShareTargetMethod" expires_after="M104">
+  <owner>peconn@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>Recorded when data is shared via a Trusted Web Activity.</summary>
+</histogram>
+
+<histogram name="TrustedWebActivity.SplashScreenShown" enum="Boolean"
+    expires_after="2022-04-24">
+  <owner>peconn@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Records whether or not a splash screen has been shown when launching a
+    Trusted Web Activity.
+  </summary>
+</histogram>
+
+<histogram name="TrustedWebActivity.TimeInVerifiedOrigin.V2" units="ms"
+    expires_after="M104">
+  <owner>peconn@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Time spent in a verified origin until navigating to an unverified one or
+    pausing the Trusted Web Activity.
+  </summary>
+</histogram>
+
+<histogram name="TrustedWebActivity.TimeOutOfVerifiedOrigin.V2" units="ms"
+    expires_after="M104">
+  <owner>peconn@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Time spent out of verified origins until navigating back to a verified one
+    or pausing the Trusted Web Activity.
+  </summary>
+</histogram>
+
 </histograms>
 
 </histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml
index 2d36f0b..9937ecf 100644
--- a/tools/metrics/histograms/metadata/extensions/histograms.xml
+++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -3478,9 +3478,9 @@
 </histogram>
 
 <histogram name="Extensions.ResetPermissionsIncrease" enum="Boolean"
-    expires_after="2021-12-01">
+    expires_after="2022-12-01">
   <owner>rdevlin.cronin@chromium.org</owner>
-  <owner>treib@chromium.org</owner>
+  <owner>extensions-core@chromium.org</owner>
   <summary>
     Whether the DISABLE_PERMISSIONS_INCREASE disable reason was removed from an
     extension while checking for a permissions increase. Recorded during startup
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index a63a853..d48e84f9 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -1531,6 +1531,17 @@
   </summary>
 </histogram>
 
+<histogram name="Media.BreakoutBox.OutOfOrderFrameDropped" enum="Boolean"
+    expires_after="2022-11-29">
+  <owner>toprice@chromium.org</owner>
+  <owner>benjaminwagner@chromium.org</owner>
+  <summary>
+    Number of BreakoutBox instances which have encountered an out of order video
+    frame and dropped it. Reported once per MediaStreamTrackProcessor instance,
+    on the first out of order frame.
+  </summary>
+</histogram>
+
 <histogram name="Media.BreakoutBox.Usage" enum="BreakoutBoxUsage"
     expires_after="2022-05-21">
   <owner>guidou@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
index c8000225..1d9d8d5 100644
--- a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
+++ b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
@@ -1377,7 +1377,7 @@
 
 <histogram
     name="NewTabPage.Promo.EnhancedProtectionPromo.ImpressionUntilDismissal"
-    units="units" expires_after="2022-03-27">
+    units="units" expires_after="2022-05-29">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-safebrowsing-core@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml
index 1aae17d2..71509ca 100644
--- a/tools/metrics/histograms/metadata/omnibox/histograms.xml
+++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -181,7 +181,7 @@
 </histogram>
 
 <histogram name="Omnibox.ClipboardSuggestionShownNumTimes" units="units"
-    expires_after="2022-03-27">
+    expires_after="2022-05-29">
   <owner>gangwu@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 77d680f..6935857 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -3736,7 +3736,7 @@
 </histogram>
 
 <histogram name="ContextMenu.LensSupportStatus" enum="LensSupportStatus"
-    expires_after="2022-03-27">
+    expires_after="2022-05-29">
   <owner>benwgold@google.com</owner>
   <owner>lens-chrome@google.com</owner>
   <summary>
@@ -7576,7 +7576,7 @@
 
 <histogram
     name="Graphics.Smoothness.PerSession.MaxPercentDroppedFrames_1sWindow"
-    units="%" expires_after="2022-03-27">
+    units="%" expires_after="2022-05-29">
   <owner>sadrul@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
@@ -11019,7 +11019,7 @@
 </histogram>
 
 <histogram name="PaintHolding.CommitTrigger2" enum="PaintHoldingCommitTrigger2"
-    expires_after="2022-03-27">
+    expires_after="2022-05-29">
   <owner>schenney@chromium.org</owner>
   <owner>paint-dev@chromium.org</owner>
   <summary>
@@ -13802,7 +13802,7 @@
 </histogram>
 
 <histogram name="SB2.RemoteCall.Result" enum="SB2RemoteCallResult"
-    expires_after="2022-03-27">
+    expires_after="2022-05-29">
   <owner>vakh@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -14682,16 +14682,6 @@
   <summary>Reports the result of the Signed Exchange validity ping.</summary>
 </histogram>
 
-<histogram name="SingleWebsitePreferences.NavigatedFromToReset"
-    enum="SettingsNavigationSources" expires_after="M104">
-  <owner>peconn@chromium.org</owner>
-  <owner>peter@chromium.org</owner>
-  <summary>
-    Logs which way had the user navigated into settings screens when they press
-    &quot;Clear and Reset&quot; button in settings of a single website.
-  </summary>
-</histogram>
-
 <histogram name="SiteIsolatedCodeCache.JS.Behaviour"
     enum="SiteIsolatedCodeCacheJSBehaviour" expires_after="2022-05-22">
   <owner>mythria@chromium.org</owner>
@@ -17178,142 +17168,6 @@
   </summary>
 </histogram>
 
-<histogram name="TrustedWebActivity.ClearDataDialogOnClearAppDataAccepted"
-    enum="Boolean" expires_after="M104">
-  <owner>peconn@chromium.org</owner>
-  <owner>peter@chromium.org</owner>
-  <summary>
-    Emits true if the user went to site settings from the dialog that is shown
-    after a Trusted Web Activity client app has had its data cleared.
-  </summary>
-</histogram>
-
-<histogram name="TrustedWebActivity.ClearDataDialogOnUninstallAccepted"
-    enum="Boolean" expires_after="M104">
-  <owner>peconn@chromium.org</owner>
-  <owner>peter@chromium.org</owner>
-  <summary>
-    Emits true if the user went to site settings from the dialog that is shown
-    after a Trusted Web Activity client app has been uninstalled.
-  </summary>
-</histogram>
-
-<histogram name="TrustedWebActivity.DelegatedNotificationSmallIconFallback"
-    enum="TrustedWebActivityDelegatedNotificationSmallIconFallback"
-    expires_after="M104">
-  <owner>peconn@chromium.org</owner>
-  <owner>peter@chromium.org</owner>
-  <summary>
-    Logs which kind of fallback for notification small icon was used for Trusted
-    Web Activity notification delegation.
-  </summary>
-</histogram>
-
-<histogram name="TrustedWebActivity.LocationDelegationEnrolled" enum="Boolean"
-    expires_after="2022-04-10">
-  <owner>eirage@chromium.org</owner>
-  <owner>peconn@chromium.org</owner>
-  <summary>
-    When a site running in Truested Web Activity is accessing geolocation,
-    records whether the last tracked focused Trusted Web Activity client app
-    enrolled location delegation.
-  </summary>
-</histogram>
-
-<histogram name="TrustedWebActivity.LocationPermissionChanged"
-    enum="TrustedWebActivityPermissionChanged" expires_after="2021-12-31">
-  <owner>eirage@chromium.org</owner>
-  <owner>peconn@chromium.org</owner>
-  <summary>
-    When a Trusted Web Activity client app's location permission is changed,
-    record the previous state and new stase.
-  </summary>
-</histogram>
-
-<histogram name="TrustedWebActivity.LocationPermissionRequestIsGranted"
-    enum="Boolean" expires_after="2021-12-31">
-  <owner>eirage@chromium.org</owner>
-  <owner>peconn@chromium.org</owner>
-  <summary>
-    Records the boolean result (granted or not) from requesting a Trusted Web
-    Activity client app's location permission.
-  </summary>
-</histogram>
-
-<histogram name="TrustedWebActivity.LocationUpdateErrorCode"
-    enum="TrustedWebActivityLocationErrorCode" expires_after="2021-12-31">
-  <owner>eirage@chromium.org</owner>
-  <owner>peconn@chromium.org</owner>
-  <summary>
-    Records an error code when we get a new location update or location error
-    from the Trusted Web Activity client app. Record
-    &quot;LocationUpdateError.NONE&quot; (value = 0) if there is no error and
-    the geoposition is valid.
-  </summary>
-</histogram>
-
-<histogram name="TrustedWebActivity.QualityEnforcementViolation"
-    enum="TrustedWebActivityQualityEnforcementViolationType"
-    expires_after="2021-12-31">
-  <owner>eirage@chromium.org</owner>
-  <owner>peconn@chromium.org</owner>
-  <summary>
-    When Trusted Web Activity launches or navigates to a site that violate the
-    quality criteria, records the violation type.
-  </summary>
-</histogram>
-
-<histogram name="TrustedWebActivity.QualityEnforcementViolation.Crashed"
-    enum="TrustedWebActivityQualityEnforcementViolationType"
-    expires_after="2021-12-31">
-  <owner>eirage@chromium.org</owner>
-  <owner>peconn@chromium.org</owner>
-  <summary>
-    When Trusted Web Activity launches or navigates to a site that violate the
-    quality criteria, and the CCT will be closed, records the violation type.
-
-    This is similar to TrustedWebActivity.QualityEnforcementViolation but only
-    records when the violation will close the CCT.
-  </summary>
-</histogram>
-
-<histogram name="TrustedWebActivity.ShareTargetRequest"
-    enum="WebShareTargetMethod" expires_after="M104">
-  <owner>peconn@chromium.org</owner>
-  <owner>peter@chromium.org</owner>
-  <summary>Recorded when data is shared via a Trusted Web Activity.</summary>
-</histogram>
-
-<histogram name="TrustedWebActivity.SplashScreenShown" enum="Boolean"
-    expires_after="2022-04-24">
-  <owner>peconn@chromium.org</owner>
-  <owner>peter@chromium.org</owner>
-  <summary>
-    Records whether or not a splash screen has been shown when launching a
-    Trusted Web Activity.
-  </summary>
-</histogram>
-
-<histogram name="TrustedWebActivity.TimeInVerifiedOrigin.V2" units="ms"
-    expires_after="M104">
-  <owner>peconn@chromium.org</owner>
-  <owner>peter@chromium.org</owner>
-  <summary>
-    Time spent in a verified origin until navigating to an unverified one or
-    pausing the Trusted Web Activity.
-  </summary>
-</histogram>
-
-<histogram name="TrustedWebActivity.TimeOutOfVerifiedOrigin.V2" units="ms"
-    expires_after="M104">
-  <owner>peconn@chromium.org</owner>
-  <owner>peter@chromium.org</owner>
-  <summary>
-    Time spent out of verified origins until navigating back to a verified one
-    or pausing the Trusted Web Activity.
-  </summary>
-</histogram>
-
 <histogram name="UI.DeviceScale" units="%" expires_after="2022-05-01">
   <owner>bsep@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index 7bac135..d69d571 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -27,6 +27,11 @@
   <variant name="PasswordFieldOnFocus" summary="on focus event"/>
 </variants>
 
+<variants name="ProfileType">
+  <variant name="Account"/>
+  <variant name="LocalProfile"/>
+</variants>
+
 <histogram name="KeyboardAccessory.AccessoryActionImpression"
     enum="AccessoryAction" expires_after="2022-04-17">
   <owner>fhorschig@chromium.org</owner>
@@ -1201,6 +1206,62 @@
   </token>
 </histogram>
 
+<histogram
+    name="PasswordManager.CredentialManager.{ProfileType}.GetIntent.Error"
+    enum="CredentialManagerError" expires_after="M102">
+  <owner>ioanap@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
+  <summary>
+    Records the error encountered while attempting to fetch the Credential
+    Manager launch intent from Google Play Services for the {ProfileType}. This
+    is recorded either before making the actual request (if the preconditions
+    are not met) or after the asynchronous call comes back with an error.
+  </summary>
+  <token key="ProfileType" variants="ProfileType"/>
+</histogram>
+
+<histogram
+    name="PasswordManager.CredentialManager.{ProfileType}.GetIntent.Latency"
+    units="ms" expires_after="M102">
+  <owner>ioanap@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
+  <summary>
+    Records the time(ms) elapsed between asking Google Play Services for the
+    intent used to open the Credential Manager for the {ProfileType} and
+    receiving it. It includes synchronous calls made to get the
+    CredentialManagerClient. Recorded when the asynchronous call comes back and
+    only on success.
+  </summary>
+  <token key="ProfileType" variants="ProfileType"/>
+</histogram>
+
+<histogram
+    name="PasswordManager.CredentialManager.{ProfileType}.GetIntent.Success"
+    enum="BooleanSuccess" expires_after="M102">
+  <owner>ioanap@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
+  <summary>
+    Records whether fetching the Credential Manager launch intent from Google
+    Play Services for the {ProfileType} was successful or not. Recorded when the
+    asynchronous call comes back.
+  </summary>
+  <token key="ProfileType" variants="ProfileType"/>
+</histogram>
+
+<histogram
+    name="PasswordManager.CredentialManager.{ProfileType}.Launch.Success"
+    enum="BooleanSuccess" expires_after="M102">
+  <owner>ioanap@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
+  <summary>
+    Records whether the provided intent to launch the Credential Manager for the
+    {ProfileType} could be used successfully. This is recorded right after
+    calling send() on the intent which happens when the async call to get the
+    intent from Google Play Services returns.
+  </summary>
+  <token key="ProfileType" variants="ProfileType"/>
+</histogram>
+
 <histogram name="PasswordManager.CredentialsCountFromAccountStoreAfterUnlock"
     units="credentials" expires_after="2022-05-31">
   <owner>fhorschig@chromium.org</owner>
@@ -2186,16 +2247,6 @@
   </summary>
 </histogram>
 
-<histogram name="PasswordManager.PasswordStoreAndroidBackend.APIError"
-    enum="PasswordStoreAndroidBackendAPIError" expires_after="2022-06-30">
-  <owner>fhorschig@chromium.org</owner>
-  <owner>vasilii@chromium.org</owner>
-  <summary>
-    The error codes returned by the GMS Core ChromeSync 1P API. Recorded when
-    the asynchronous job has returned.
-  </summary>
-</histogram>
-
 <histogram name="PasswordManager.PasswordStoreAndroidBackend.APIErros"
     enum="PasswordStoreAndroidBackendAPIError" expires_after="2022-06-30">
   <obsolete>
@@ -2210,17 +2261,6 @@
   </summary>
 </histogram>
 
-<histogram name="PasswordManager.PasswordStoreAndroidBackend.ErrorCode"
-    enum="PasswordStoreAndroidBackendError" expires_after="2022-06-30">
-  <owner>fhorschig@chromium.org</owner>
-  <owner>vasilii@chromium.org</owner>
-  <summary>
-    This metric reports the error observed when retrieving/adding/updating or
-    removing logins from the PasswordStore Android backend. Recorded when the
-    asynchronous job has returned.
-  </summary>
-</histogram>
-
 <histogram
     name="PasswordManager.PasswordStoreAndroidBackend.{Function}.Latency"
     units="ms" expires_after="2022-06-30">
@@ -2260,6 +2300,43 @@
   </token>
 </histogram>
 
+<histogram
+    name="PasswordManager.PasswordStoreAndroidBackend{Function}.APIError"
+    enum="PasswordStoreAndroidBackendAPIError" expires_after="2022-06-30">
+  <owner>fhorschig@chromium.org</owner>
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    The error codes returned by the GMS Core ChromeSync 1P API{Function}.
+    Recorded when the asynchronous job has returned.
+  </summary>
+  <token key="Function">
+    <variant name=""/>
+    <variant name=".AddLoginAsync" summary="for AddLoginAsync"/>
+    <variant name=".GetAllLoginsAsync" summary="for GetAllLoginsAsync"/>
+    <variant name=".RemoveLoginAsync" summary="for RemoveLoginAsync"/>
+    <variant name=".UpdateLoginAsync" summary="for UpdateLoginAsync"/>
+  </token>
+</histogram>
+
+<histogram
+    name="PasswordManager.PasswordStoreAndroidBackend{Function}.ErrorCode"
+    enum="PasswordStoreAndroidBackendError" expires_after="2022-06-30">
+  <owner>fhorschig@chromium.org</owner>
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    This metric reports the error observed when {Function} the PasswordStore
+    Android backend. Recorded when the asynchronous job has returned.
+  </summary>
+  <token key="Function">
+    <variant name=""
+        summary="retrieving/adding/updating or removing logins from"/>
+    <variant name=".AddLoginAsync" summary="adding a login to"/>
+    <variant name=".GetAllLoginsAsync" summary="retrieving all logins from"/>
+    <variant name=".RemoveLoginAsync" summary="removing a login from"/>
+    <variant name=".UpdateLoginAsync" summary="updating a login in"/>
+  </token>
+</histogram>
+
 <histogram name="PasswordManager.PasswordStoreDeletionsHaveSynced"
     enum="BooleanSuccess" expires_after="M92">
   <obsolete>
@@ -2505,7 +2582,7 @@
 </histogram>
 
 <histogram name="PasswordManager.ReusedPasswordType" enum="ReusedPasswordType"
-    expires_after="2022-03-27">
+    expires_after="2022-05-29">
   <owner>vakh@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/platform/histograms.xml b/tools/metrics/histograms/metadata/platform/histograms.xml
index bde3c24..d327706 100644
--- a/tools/metrics/histograms/metadata/platform/histograms.xml
+++ b/tools/metrics/histograms/metadata/platform/histograms.xml
@@ -732,6 +732,18 @@
   </summary>
 </histogram>
 
+<histogram name="Platform.MiniDiag.Launch" units="launches"
+    expires_after="2022-05-18">
+  <owner>roccochen@chromium.org</owner>
+  <owner>chromeos-minidiag-eng@google.com</owner>
+  <summary>
+    Total number of launches of the MiniDiag (pre-boot diagnostic tool) since
+    the last upload. This metrics is recorded right after booting into ChromeOS.
+    This metrics leverages a coreboot command, elogtool, to retrieve the event
+    log and count launch events.
+  </summary>
+</histogram>
+
 <histogram name="Platform.MountEncrypted.EncryptionKeyStatus"
     enum="MountEncryptedEncryptionKeyStatus" expires_after="2022-04-24">
   <owner>apronin@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/power/histograms.xml b/tools/metrics/histograms/metadata/power/histograms.xml
index 0dba421..a7a9903fe 100644
--- a/tools/metrics/histograms/metadata/power/histograms.xml
+++ b/tools/metrics/histograms/metadata/power/histograms.xml
@@ -1383,7 +1383,7 @@
 </histogram>
 
 <histogram name="PowerML.NonModelDim.Result" enum="PowerMLFinalResult"
-    expires_after="2022-03-27">
+    expires_after="2022-05-29">
   <owner>napper@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/profile/histograms.xml b/tools/metrics/histograms/metadata/profile/histograms.xml
index 1999c255..a2c9a0e 100644
--- a/tools/metrics/histograms/metadata/profile/histograms.xml
+++ b/tools/metrics/histograms/metadata/profile/histograms.xml
@@ -423,7 +423,7 @@
 </histogram>
 
 <histogram name="Profile.NumberOfActiveProfiles" units="profiles"
-    expires_after="2022-03-27">
+    expires_after="2022-05-29">
   <owner>droger@chromium.org</owner>
   <owner>feuunk@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/sb_client/histograms.xml b/tools/metrics/histograms/metadata/sb_client/histograms.xml
index fa41c8d..960cb91 100644
--- a/tools/metrics/histograms/metadata/sb_client/histograms.xml
+++ b/tools/metrics/histograms/metadata/sb_client/histograms.xml
@@ -893,7 +893,7 @@
 </histogram>
 
 <histogram name="SBClientPhishing.RequestWithToken" enum="BooleanSent"
-    expires_after="2022-03-30">
+    expires_after="2022-05-29">
   <owner>bhatiarohit@google.com</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/software/histograms.xml b/tools/metrics/histograms/metadata/software/histograms.xml
index ab981f4..bb2e4830 100644
--- a/tools/metrics/histograms/metadata/software/histograms.xml
+++ b/tools/metrics/histograms/metadata/software/histograms.xml
@@ -301,7 +301,7 @@
 </histogram>
 
 <histogram name="SoftwareReporter.MemoryUsed" units="KB"
-    expires_after="2022-03-27">
+    expires_after="2022-05-29">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -426,7 +426,7 @@
 </histogram>
 
 <histogram name="SoftwareReporter.RunningTimeAccordingToChrome" units="ms"
-    expires_after="2022-03-27">
+    expires_after="2022-05-29">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/uma/histograms.xml b/tools/metrics/histograms/metadata/uma/histograms.xml
index fd06bf5..1db5258 100644
--- a/tools/metrics/histograms/metadata/uma/histograms.xml
+++ b/tools/metrics/histograms/metadata/uma/histograms.xml
@@ -653,7 +653,7 @@
 </histogram>
 
 <histogram name="UMA.PrimaryUserType" enum="UserType"
-    expires_after="2022-03-27">
+    expires_after="2022-05-29">
   <owner>michaelpg@chromium.org</owner>
   <owner>yilkal@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
diff --git a/tools/metrics/histograms/metadata/v8/histograms.xml b/tools/metrics/histograms/metadata/v8/histograms.xml
index b43233d7..c3d1766 100644
--- a/tools/metrics/histograms/metadata/v8/histograms.xml
+++ b/tools/metrics/histograms/metadata/v8/histograms.xml
@@ -1522,6 +1522,18 @@
   </summary>
 </histogram>
 
+<histogram name="V8.WasmCacheCount" units="count" expires_after="2022-06-30">
+  <owner>ahaas@chromium.org</owner>
+  <owner>ecmziegler@chromium.org</owner>
+  <summary>
+    Number of times a WebAssembly module being added to the browser cache. With
+    dynamic tiering, caching is triggered repeatedly whenever the amount of
+    generated optimized code reaches a threshold. Recorded every time a new
+    version of the WebAssembly module is being added to the cache, and also when
+    the module is compiled initially.
+  </summary>
+</histogram>
+
 <histogram name="V8.WasmCatchCount" units="count" expires_after="2022-09-01">
   <owner>thibaudm@chromium.org</owner>
   <owner>ecmziegler@chromium.org</owner>
@@ -1531,6 +1543,18 @@
   </summary>
 </histogram>
 
+<histogram name="V8.WasmCompileAfterDeserializeMilliSeconds" units="ms"
+    expires_after="2022-06-30">
+  <owner>ahaas@chromium.org</owner>
+  <owner>ecmziegler@chromium.org</owner>
+  <summary>
+    After deserialization, all functions that were not in the serialized module
+    are compiled with the baseline compiler. This metric measures the time spent
+    by the baseline compiler on compiling missing functions. Recorded after the
+    baseline compilation of the missing functions finishes.
+  </summary>
+</histogram>
+
 <histogram name="V8.WasmCompileFunctionMicroSeconds" units="microseconds"
     expires_after="2022-04-10">
   <owner>ecmziegler@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/web_apk/histograms.xml b/tools/metrics/histograms/metadata/web_apk/histograms.xml
index 0ac930b..5037f3f 100644
--- a/tools/metrics/histograms/metadata/web_apk/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_apk/histograms.xml
@@ -143,7 +143,7 @@
 </histogram>
 
 <histogram name="WebApk.Install.RequestTokenDurationV2" units="ms"
-    expires_after="2022-03-27">
+    expires_after="2022-05-29">
   <owner>hartmanng@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
   <owner>
diff --git a/tools/origin_trials/PRESUBMIT.py b/tools/origin_trials/PRESUBMIT.py
index e97ba316..df539cf1 100644
--- a/tools/origin_trials/PRESUBMIT.py
+++ b/tools/origin_trials/PRESUBMIT.py
@@ -2,27 +2,28 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-USE_PYTHON3 = True
+USE_PYTHON3 = False
 
 
 def _CommonChecks(input_api, output_api):
   results = []
 
   # Run Pylint over the files in the directory.
-  pylint_checks = input_api.canned_checks.GetPylint(input_api,
-                                                    output_api,
-                                                    version='2.7')
+  # TODO(crbug.com/1262279): Enable these warnings after migrating to Python3.
+  disabled_warnings = ('super-with-arguments', )
+  pylint_checks = input_api.canned_checks.GetPylint(
+      input_api, output_api, disabled_warnings=disabled_warnings, version='2.7')
   results.extend(input_api.RunTests(pylint_checks))
 
   # Run the generate_token unittests.
+  #TODO(https://crbug.com/1274995): Run the tests on Python3.
   results.extend(
       input_api.canned_checks.RunUnitTestsInDirectory(
           input_api,
           output_api,
           '.', [r'^.+_unittest\.py$'],
           run_on_python2=not USE_PYTHON3,
-          run_on_python3=USE_PYTHON3,
-          skip_shebang_check=True))
+          run_on_python3=USE_PYTHON3))
 
   return results
 
diff --git a/tools/origin_trials/check_token.py b/tools/origin_trials/check_token.py
index 7d0f17d..fa7da43 100755
--- a/tools/origin_trials/check_token.py
+++ b/tools/origin_trials/check_token.py
@@ -63,7 +63,7 @@
 
 class OverrideKeyFileAction(argparse.Action):
   def __init__(self, option_strings, dest, **kwargs):
-    super().__init__(option_strings, dest, **kwargs)
+    super(OverrideKeyFileAction, self).__init__(option_strings, dest, **kwargs)
 
   def __call__(self, parser, namespace, values, option_string=None):
     setattr(namespace, "use_chrome_key", None)
diff --git a/tools/origin_trials/generate_token.py b/tools/origin_trials/generate_token.py
index 687bbd2f..bf5005f0 100755
--- a/tools/origin_trials/generate_token.py
+++ b/tools/origin_trials/generate_token.py
@@ -21,13 +21,15 @@
 
 import argparse
 import base64
-from datetime import datetime
 import json
-import re
 import os
+import re
 import struct
 import sys
 import time
+from datetime import datetime
+
+from six import raise_from
 
 try:
   from urllib.parse import urlparse
@@ -39,7 +41,6 @@
 sys.path.insert(0, os.path.join(script_dir, 'third_party', 'ed25519'))
 import ed25519
 
-
 # Matches a valid DNS name label (alphanumeric plus hyphens, except at the ends,
 # no longer than 63 ASCII characters)
 DNS_LABEL_REGEX = re.compile(r"^(?!-)[a-z\d-]{1,63}(?<!-)$", re.IGNORECASE)
@@ -105,8 +106,8 @@
   try:
     port = origin.port
   except ValueError as e:
-    raise argparse.ArgumentTypeError("%s is not a hostname or a URL" %
-                                     arg) from e
+    raise_from(
+        argparse.ArgumentTypeError("%s is not a hostname or a URL" % arg), e)
   if not port:
     port = {"https": 443, "http": 80}[origin.scheme]
   # Strip any extra components and return the origin URL:
@@ -142,7 +143,8 @@
   return base64.b64encode(version + signature +
                           struct.pack(">I",len(data)) + data)
 
-def main():
+
+def ParseArgs():
   default_key_file_absolute = os.path.join(script_dir, DEFAULT_KEY_FILE)
 
   parser = argparse.ArgumentParser(
@@ -208,7 +210,11 @@
                                  "00:00:00 UTC) when the token should expire",
                             type=int)
 
-  args = parser.parse_args()
+  return parser.parse_args()
+
+
+def GenerateTokenAndSignature():
+  args = ParseArgs()
   expiry = ExpiryFromArgs(args)
 
   key_file = open(os.path.expanduser(args.key_file), mode="rb")
@@ -255,6 +261,17 @@
     print("(The original error was: %s)" % exc)
     sys.exit(1)
 
+  token_data = GenerateTokenData(args.version[0], args.origin,
+                                 args.is_subdomain, args.is_third_party,
+                                 args.usage_restriction, args.trial_name,
+                                 expiry)
+  data_to_sign = GenerateDataToSign(args.version[1], token_data)
+  signature = Sign(private_key, data_to_sign)
+  return args, token_data, signature
+
+
+def main():
+  args, token_data, signature = GenerateTokenAndSignature()
 
   # Output the token details
   print("Token details:")
diff --git a/tools/origin_trials/generate_token_unittest.py b/tools/origin_trials/generate_token_unittest.py
index 06a2cc91..20852ea 100755
--- a/tools/origin_trials/generate_token_unittest.py
+++ b/tools/origin_trials/generate_token_unittest.py
@@ -8,6 +8,8 @@
 import argparse
 import generate_token
 import unittest
+# TODO(https://crbug.com/1274995): Use unittest.mock after migrating to Python3.
+from mock import patch as mock_patch
 
 
 class GenerateTokenTest(unittest.TestCase):
@@ -64,5 +66,11 @@
                         generate_token.OriginFromArg,
                         invalid_hostname)
 
+  def test_end_to_end(self):
+    with mock_patch('sys.argv',
+                    ['generate-token.py', 'example.com', 'example']):
+      generate_token.GenerateTokenAndSignature()
+
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc
index ec9f8b9..319cbee 100644
--- a/ui/accessibility/ax_node_data.cc
+++ b/ui/accessibility/ax_node_data.cc
@@ -1802,6 +1802,11 @@
     }
   }
 
+  for (const std::pair<std::string, std::string>& string_pair :
+       html_attributes) {
+    result += " " + string_pair.first + "=" + string_pair.second;
+  }
+
   if (actions)
     result += " actions=" + ActionsBitfieldToString(actions);
 
diff --git a/ui/android/java/src/org/chromium/ui/widget/TextViewWithTightWrapTest.java b/ui/android/java/src/org/chromium/ui/widget/TextViewWithTightWrapTest.java
index 6767dfc..4263f86 100644
--- a/ui/android/java/src/org/chromium/ui/widget/TextViewWithTightWrapTest.java
+++ b/ui/android/java/src/org/chromium/ui/widget/TextViewWithTightWrapTest.java
@@ -29,11 +29,18 @@
 */
 @RunWith(BaseJUnit4ClassRunner.class)
 public class TextViewWithTightWrapTest extends DummyUiActivityTestCase {
+    private static final int RENDER_TEST_REVISION = 1;
+    private static final String RENDER_TEST_REVISION_DESCRIPTION = "Fix the background color.";
+
     private TextViewWithTightWrap mTextView;
     private View mView;
 
     @Rule
-    public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus().build();
+    public RenderTestRule mRenderTestRule =
+            RenderTestRule.Builder.withPublicCorpus()
+                    .setRevision(RENDER_TEST_REVISION)
+                    .setDescription(RENDER_TEST_REVISION_DESCRIPTION)
+                    .build();
 
     @Before
     public void setup() {
@@ -44,7 +51,7 @@
                 new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
         mTextView = mView.findViewById(R.id.message);
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mView.setBackgroundColor(R.color.filled_button_bg);
+            mView.setBackgroundColor(activity.getColor(R.color.filled_button_bg));
             mTextView.setText("First line\nVery very very very long second line");
             getActivity().setContentView(mView, params);
         });
diff --git a/ui/base/linux/linux_ui_delegate.cc b/ui/base/linux/linux_ui_delegate.cc
index 965faa1..77fc3fd 100644
--- a/ui/base/linux/linux_ui_delegate.cc
+++ b/ui/base/linux/linux_ui_delegate.cc
@@ -36,4 +36,12 @@
   return false;
 }
 
+void LinuxUiDelegate::SetTransientWindowForParent(
+    gfx::AcceleratedWidget parent,
+    gfx::AcceleratedWidget transient) {
+  // This function should not be called when using a platform that doesn't
+  // implement it.
+  NOTREACHED();
+}
+
 }  // namespace ui
diff --git a/ui/base/linux/linux_ui_delegate.h b/ui/base/linux/linux_ui_delegate.h
index f95c054..d057a6a2 100644
--- a/ui/base/linux/linux_ui_delegate.h
+++ b/ui/base/linux/linux_ui_delegate.h
@@ -10,6 +10,7 @@
 
 #include "base/callback_forward.h"
 #include "base/component_export.h"
+#include "ui/gfx/native_widget_types.h"
 
 namespace ui {
 
@@ -32,6 +33,10 @@
       uint32_t parent_widget,
       base::OnceCallback<void(const std::string&)> callback);
 
+  // Only implemented on X11.
+  virtual void SetTransientWindowForParent(gfx::AcceleratedWidget parent,
+                                           gfx::AcceleratedWidget transient);
+
  private:
   static LinuxUiDelegate* instance_;
 };
diff --git a/ui/gtk/BUILD.gn b/ui/gtk/BUILD.gn
index a5b8ab7..db29cdc 100644
--- a/ui/gtk/BUILD.gn
+++ b/ui/gtk/BUILD.gn
@@ -139,7 +139,6 @@
       "//ui/base/x",
       "//ui/events/platform/x11",
       "//ui/gfx/x",
-      "//ui/platform_window/x11",
     ]
   }
 
diff --git a/ui/gtk/x/DEPS b/ui/gtk/x/DEPS
deleted file mode 100644
index 098786a57..0000000
--- a/ui/gtk/x/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+ui/platform_window/x11",
-]
diff --git a/ui/gtk/x/gtk_ui_platform_x11.cc b/ui/gtk/x/gtk_ui_platform_x11.cc
index d02db688..a0b043c 100644
--- a/ui/gtk/x/gtk_ui_platform_x11.cc
+++ b/ui/gtk/x/gtk_ui_platform_x11.cc
@@ -1,3 +1,4 @@
+
 // 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.
@@ -7,6 +8,7 @@
 #include "base/check.h"
 #include "base/environment.h"
 #include "base/strings/stringprintf.h"
+#include "ui/base/linux/linux_ui_delegate.h"
 #include "ui/base/x/x11_util.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/event_utils.h"
@@ -19,8 +21,6 @@
 #include "ui/gtk/gtk_compat.h"
 #include "ui/gtk/gtk_util.h"
 #include "ui/gtk/x/gtk_event_loop_x11.h"
-#include "ui/platform_window/x11/x11_window.h"
-#include "ui/platform_window/x11/x11_window_manager.h"
 
 namespace gtk {
 
@@ -91,19 +91,14 @@
   SetProperty(x11_window, x11::GetAtom("_NET_WM_WINDOW_TYPE"), x11::Atom::ATOM,
               x11::GetAtom("_NET_WM_WINDOW_TYPE_DIALOG"));
 
-  ui::X11Window* parent_window =
-      ui::X11WindowManager::GetInstance()->GetWindow(parent);
-  parent_window->SetTransientWindow(x11_window);
-
+  ui::LinuxUiDelegate::GetInstance()->SetTransientWindowForParent(
+      parent, static_cast<gfx::AcceleratedWidget>(x11_window));
   return true;
 }
 
 void GtkUiPlatformX11::ClearTransientFor(gfx::AcceleratedWidget parent) {
-  ui::X11Window* parent_window =
-      ui::X11WindowManager::GetInstance()->GetWindow(parent);
-  // parent_window might be dead if there was a top-down window close
-  if (parent_window)
-    parent_window->SetTransientWindow(x11::Window::None);
+  ui::LinuxUiDelegate::GetInstance()->SetTransientWindowForParent(
+      parent, static_cast<gfx::AcceleratedWidget>(x11::Window::None));
 }
 
 GdkDisplay* GtkUiPlatformX11::GetGdkDisplay() {
diff --git a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
index 93909d0..093cc91 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
@@ -18,7 +18,7 @@
 #include "ui/ozone/public/overlay_plane.h"
 
 #if defined(WAYLAND_GBM)
-#include "ui/gfx/linux/gbm_wrapper.h"
+#include "ui/gfx/linux/gbm_wrapper.h"  // nogncheck
 #include "ui/ozone/platform/wayland/gpu/drm_render_node_handle.h"
 #include "ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.h"
 #endif
diff --git a/ui/ozone/platform/wayland/host/wayland_menu_utils.cc b/ui/ozone/platform/wayland/host/wayland_menu_utils.cc
index 8eed6ce..5f7d76a 100644
--- a/ui/ozone/platform/wayland/host/wayland_menu_utils.cc
+++ b/ui/ozone/platform/wayland/host/wayland_menu_utils.cc
@@ -4,6 +4,12 @@
 
 #include "ui/ozone/platform/wayland/host/wayland_menu_utils.h"
 
+#include "base/strings/utf_string_conversion_utils.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/dom/dom_key.h"
+#include "ui/events/keycodes/keyboard_code_conversion.h"
+#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
+#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_event_source.h"
 
@@ -20,4 +26,32 @@
   return connection_->event_source()->keyboard_modifiers();
 }
 
+std::string WaylandMenuUtils::ToDBusKeySym(KeyboardCode code) const {
+  // KeyboardCode is VKEY_***, and here we convert it into the string
+  // representation.
+  DomCode dom_code = UsLayoutKeyboardCodeToDomCode(code);
+
+  KeyboardLayoutEngine* keyboard_layout_engine =
+      KeyboardLayoutEngineManager::GetKeyboardLayoutEngine();
+  std::unique_ptr<StubKeyboardLayoutEngine> stub_layout_engine;
+  if (!keyboard_layout_engine) {
+    stub_layout_engine = std::make_unique<StubKeyboardLayoutEngine>();
+    keyboard_layout_engine = stub_layout_engine.get();
+  }
+
+  DomKey dom_key;
+  KeyboardCode key_code_ignored;
+  if (!keyboard_layout_engine->Lookup(dom_code, EF_NONE, &dom_key,
+                                      &key_code_ignored) ||
+      !dom_key.IsCharacter()) {
+    // The keycode lookup failed, or mapped to a key that isn't a unicode
+    // character.  Return an empty string.
+    return {};
+  }
+
+  std::string result;
+  base::WriteUnicodeCharacter(dom_key.ToCharacter(), &result);
+  return result;
+}
+
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_menu_utils.h b/ui/ozone/platform/wayland/host/wayland_menu_utils.h
index c9a0bbaa..43d1e85 100644
--- a/ui/ozone/platform/wayland/host/wayland_menu_utils.h
+++ b/ui/ozone/platform/wayland/host/wayland_menu_utils.h
@@ -19,6 +19,7 @@
   ~WaylandMenuUtils() override;
 
   int GetCurrentKeyModifiers() const override;
+  std::string ToDBusKeySym(KeyboardCode code) const override;
 
  private:
   WaylandConnection* const connection_;
diff --git a/ui/ozone/platform/x11/BUILD.gn b/ui/ozone/platform/x11/BUILD.gn
index bc3e13a..9fe6fd74 100644
--- a/ui/ozone/platform/x11/BUILD.gn
+++ b/ui/ozone/platform/x11/BUILD.gn
@@ -20,6 +20,8 @@
     "gl_ozone_glx.h",
     "gl_surface_egl_readback_x11.cc",
     "gl_surface_egl_readback_x11.h",
+    "linux_ui_delegate_x11.cc",
+    "linux_ui_delegate_x11.h",
     "ozone_platform_x11.cc",
     "ozone_platform_x11.h",
     "x11_canvas_surface.cc",
diff --git a/ui/ozone/platform/x11/linux_ui_delegate_x11.cc b/ui/ozone/platform/x11/linux_ui_delegate_x11.cc
new file mode 100644
index 0000000..71ceb74b
--- /dev/null
+++ b/ui/ozone/platform/x11/linux_ui_delegate_x11.cc
@@ -0,0 +1,30 @@
+// 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 "ui/ozone/platform/x11/linux_ui_delegate_x11.h"
+
+#include "ui/gfx/x/xproto.h"
+#include "ui/platform_window/x11/x11_window.h"
+#include "ui/platform_window/x11/x11_window_manager.h"
+
+namespace ui {
+
+LinuxUiDelegateX11::LinuxUiDelegateX11() = default;
+
+LinuxUiDelegateX11::~LinuxUiDelegateX11() = default;
+
+LinuxUiBackend LinuxUiDelegateX11::GetBackend() const {
+  return LinuxUiBackend::kX11;
+}
+
+void LinuxUiDelegateX11::SetTransientWindowForParent(
+    gfx::AcceleratedWidget parent,
+    gfx::AcceleratedWidget transient) {
+  X11Window* parent_window = X11WindowManager::GetInstance()->GetWindow(parent);
+  // parent_window might be dead if there was a top-down window close
+  if (parent_window)
+    parent_window->SetTransientWindow(static_cast<x11::Window>(transient));
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/x11/linux_ui_delegate_x11.h b/ui/ozone/platform/x11/linux_ui_delegate_x11.h
new file mode 100644
index 0000000..25b5885
--- /dev/null
+++ b/ui/ozone/platform/x11/linux_ui_delegate_x11.h
@@ -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.
+
+#ifndef UI_OZONE_PLATFORM_X11_LINUX_UI_DELEGATE_X11_H_
+#define UI_OZONE_PLATFORM_X11_LINUX_UI_DELEGATE_X11_H_
+
+#include "ui/base/linux/linux_ui_delegate.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace ui {
+
+class LinuxUiDelegateX11 : public LinuxUiDelegate {
+ public:
+  LinuxUiDelegateX11();
+  ~LinuxUiDelegateX11() override;
+
+  // LinuxUiDelegate:
+  LinuxUiBackend GetBackend() const override;
+  void SetTransientWindowForParent(gfx::AcceleratedWidget parent,
+                                   gfx::AcceleratedWidget transient) override;
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_X11_LINUX_UI_DELEGATE_X11_H_
diff --git a/ui/ozone/platform/x11/ozone_platform_x11.cc b/ui/ozone/platform/x11/ozone_platform_x11.cc
index b14344aec..013abeee 100644
--- a/ui/ozone/platform/x11/ozone_platform_x11.cc
+++ b/ui/ozone/platform/x11/ozone_platform_x11.cc
@@ -34,6 +34,7 @@
 #include "ui/gfx/switches.h"
 #include "ui/ozone/common/stub_overlay_manager.h"
 #include "ui/ozone/platform/x11/gl_egl_utility_x11.h"
+#include "ui/ozone/platform/x11/linux_ui_delegate_x11.h"
 #include "ui/ozone/platform/x11/x11_clipboard_ozone.h"
 #include "ui/ozone/platform/x11/x11_global_shortcut_listener_ozone.h"
 #include "ui/ozone/platform/x11/x11_keyboard_hook_ozone.h"
@@ -62,14 +63,6 @@
 
 namespace {
 
-class LinuxUiDelegateX11 : public LinuxUiDelegate {
- public:
-  ~LinuxUiDelegateX11() override = default;
-
-  // LinuxUiDelegate:
-  LinuxUiBackend GetBackend() const override { return LinuxUiBackend::kX11; }
-};
-
 // Singleton OzonePlatform implementation for X11 platform.
 class OzonePlatformX11 : public OzonePlatform,
                          public OSExchangeDataProviderFactoryOzone {
diff --git a/weblayer/browser/navigation_controller_impl.cc b/weblayer/browser/navigation_controller_impl.cc
index 7dd686cb..2d083a9 100644
--- a/weblayer/browser/navigation_controller_impl.cc
+++ b/weblayer/browser/navigation_controller_impl.cc
@@ -362,24 +362,54 @@
 }
 
 int NavigationControllerImpl::GetNavigationListSize() {
+  if (web_contents()
+          ->GetController()
+          .GetLastCommittedEntry()
+          ->IsInitialEntry()) {
+    // If we're currently on the initial NavigationEntry, no navigation has
+    // committed, so the initial NavigationEntry should not be part of the
+    // "Navigation List", and we should return 0 as the navigation list size.
+    // This also preserves the old behavior where we used to not have the
+    // initial NavigationEntry.
+    return 0;
+  }
+
   return web_contents()->GetController().GetEntryCount();
 }
 
 int NavigationControllerImpl::GetNavigationListCurrentIndex() {
+  if (web_contents()
+          ->GetController()
+          .GetLastCommittedEntry()
+          ->IsInitialEntry()) {
+    // If we're currently on the initial NavigationEntry, no navigation has
+    // committed, so the initial NavigationEntry should not be part of the
+    // "Navigation List", and we should return -1 as the current index. This
+    // also preserves the old behavior where we used to not have the initial
+    // NavigationEntry.
+    return -1;
+  }
+
   return web_contents()->GetController().GetCurrentEntryIndex();
 }
 
 GURL NavigationControllerImpl::GetNavigationEntryDisplayURL(int index) {
   auto* entry = web_contents()->GetController().GetEntryAtIndex(index);
-  if (!entry)
-    return GURL();
+  // This function should never be called when GetNavigationListSize() is 0
+  // because `index` should be between 0 and GetNavigationListSize() - 1, which
+  // also means `entry` must not be the initial NavigationEntry.
+  DCHECK_NE(0, GetNavigationListSize());
+  DCHECK(!entry->IsInitialEntry());
   return entry->GetVirtualURL();
 }
 
 std::string NavigationControllerImpl::GetNavigationEntryTitle(int index) {
   auto* entry = web_contents()->GetController().GetEntryAtIndex(index);
-  if (!entry)
-    return std::string();
+  // This function should never be called when GetNavigationListSize() is 0
+  // because `index` should be between 0 and GetNavigationListSize() - 1, which
+  // also means `entry` must not be the initial NavigationEntry.
+  DCHECK_NE(0, GetNavigationListSize());
+  DCHECK(!entry->IsInitialEntry());
   return base::UTF16ToUTF8(entry->GetTitle());
 }
 
diff --git a/weblayer/browser/persistence/minimal_browser_persister_browsertest.cc b/weblayer/browser/persistence/minimal_browser_persister_browsertest.cc
index ebc1f1c..19161328 100644
--- a/weblayer/browser/persistence/minimal_browser_persister_browsertest.cc
+++ b/weblayer/browser/persistence/minimal_browser_persister_browsertest.cc
@@ -161,7 +161,7 @@
 
   TabImpl* restored_tab = tab_;
   EXPECT_EQ(restored_tab, browser_->GetActiveTab());
-  EXPECT_EQ(0, restored_tab->web_contents()->GetController().GetEntryCount());
+  EXPECT_EQ(1, restored_tab->web_contents()->GetController().GetEntryCount());
   EXPECT_TRUE(restored_tab->web_contents()->GetController().GetPendingEntry() ==
               nullptr);
 }